From 2cbf83ffcd12a010409b136519c27f503dd8a864 Mon Sep 17 00:00:00 2001 From: Anthony Sychev Date: Thu, 18 Feb 2021 16:50:32 +0100 Subject: [PATCH 1/3] Api >= 29 Netword specifier new method for Android --- README.md | 485 ++++---- src/android/wifiwizard2/WifiWizard2.java | 118 +- www/WifiWizard2.js | 1360 +++++++++++----------- 3 files changed, 1084 insertions(+), 879 deletions(-) diff --git a/README.md b/README.md index 93ffcd4..ba25c18 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # WiFiWizard2 - 3.2.0 -Table of Contents ---- +## Table of Contents + - [About](#about) - [Basics](#basics) - [Async Handling](#async-handling) @@ -28,15 +28,16 @@ Table of Contents - [Changelog:](#changelog) # About + WifiWizard2 enables Wifi management for both Android and iOS applications within Cordova/Phonegap projects. This project is a fork of the [WifiWizard](https://github.com/hoerresb/WifiWizard) plugin with fixes and updates, as well as patches taken from the [Cordova Network Manager](https://github.com/arsenal942/Cordova-Network-Manager) plugin. -Version 3.0.0+ has undergone a TON of changes from the original fork (version 2.0), and the majority of method/functions have been changed. You can find the latest release of version 2 on the [2.1.x branch](https://github.com/tripflex/WifiWizard2/tree/2.1.x) +Version 3.0.0+ has undergone a TON of changes from the original fork (version 2.0), and the majority of method/functions have been changed. You can find the latest release of version 2 on the [2.1.x branch](https://github.com/tripflex/WifiWizard2/tree/2.1.x) The recommended version to use is the latest 3+ as that is the version that is actively maintained. -*iOS has limited functionality as Apple's WifiManager equivalent is only available as a private API. Any app that used these features would not be allowed on the app store.* +_iOS has limited functionality as Apple's WifiManager equivalent is only available as a private API. Any app that used these features would not be allowed on the app store._ **If you are an iOS developer, please consider helping us to resolve the [open iOS issues](https://github.com/tripflex/WifiWizard2/issues/6)** @@ -49,21 +50,27 @@ The recommended version to use is the latest 3+ as that is the version that is a This plugin creates the object `WifiWizard2` and is accessible after `deviceready` has been fired, see [Cordova deviceready Event Docs](https://cordova.apache.org/docs/en/latest/cordova/events/events.html#deviceready) ```js -document.addEventListener('deviceready', function () { - // Call some WifiWizard2.method after deviceready fired -}, false); +document.addEventListener( + 'deviceready', + function () { + // Call some WifiWizard2.method after deviceready fired + }, + false +); ``` -This is really only necessary if you plan on immediately invoking one of this plugin's methods/functions, as the majority of the time you would probably just call the method/function on say, a button click to scan for networks, etc. Basically if you are going to call something immediately when a webview is shown, make sure to add the event listener for `deviceready` before making that call, otherwise you probably don't need to. +This is really only necessary if you plan on immediately invoking one of this plugin's methods/functions, as the majority of the time you would probably just call the method/function on say, a button click to scan for networks, etc. Basically if you are going to call something immediately when a webview is shown, make sure to add the event listener for `deviceready` before making that call, otherwise you probably don't need to. ## Async Handling -Because Cordova `exec` calls are made asynchronously, all methods/functions return async promises. These functions will return the results, or a JavaScript error. You should use `await` and `try/catch` blocks (or `.then` and `.catch`). See below for more details, and examples. + +Because Cordova `exec` calls are made asynchronously, all methods/functions return async promises. These functions will return the results, or a JavaScript error. You should use `await` and `try/catch` blocks (or `.then` and `.catch`). See below for more details, and examples. **Callbacks are not longer supported in this plugin** -Promises are handled by the [Cordova PromisesPlugin](https://github.com/vstirbu/PromisesPlugin) as an ES6 polyfill if your application does not already define `window.Promise` +Promises are handled by the [Cordova PromisesPlugin](https://github.com/vstirbu/PromisesPlugin) as an ES6 polyfill if your application does not already define `window.Promise` ## Demo Meteor Project + To test this plugin as well as provide some example code for others to work off of, I have created an example Meteor project you can find here: [https://github.com/tripflex/WifiWizard2Demo](https://github.com/tripflex/WifiWizard2Demo) @@ -71,46 +78,57 @@ To test this plugin as well as provide some example code for others to work off This demo has examples of using both async functions (with `async/await` and `try/catch` blocks), as well as non async functions with `.then` and `.catch` ## Android and IOS Permissions and Notes -In order to obtain scan results (to call `scan` or `startScan` then `getScanResults`) your application must have the `ACCESS_FINE_LOCATION` Android Permission. You can do this by calling the `requestPermission` method detailed below, or + +In order to obtain scan results (to call `scan` or `startScan` then `getScanResults`) your application must have the `ACCESS_FINE_LOCATION` Android Permission. You can do this by calling the `requestPermission` method detailed below, or this plugin will automagically do this for you when you call `scan` or `startScan` functions. -Newer versions of Android will **not** allow you to `remove`, update existing configuration, or `disable` networks that were not created by your application. If you are having issues using this features, with your device connected to your computer, run `adb logcat` to view Android Logs for specific error. +Newer versions of Android will **not** allow you to `remove`, update existing configuration, or `disable` networks that were not created by your application. If you are having issues using this features, with your device connected to your computer, run `adb logcat` to view Android Logs for specific error. ## IOS Notes + iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. ## Ionic/Angular Notes + This plugin does not have @ionic/native typings (yet), in order to use it add this to just below your import list on your service: `declare var WifiWizard2: any;` # Global Functions + These are functions that can be used by both Android and iOS applications + ```javascript -WifiWizard2.getConnectedSSID() +WifiWizard2.getConnectedSSID(); ``` - - Returns connected network SSID (only if connected) in success callback, otherwise fail callback will be called (if not connected or unable to retrieve) - - This does **NOT** return the BSSID if unable to obtain SSID (like original WifiWizard did) + +- Returns connected network SSID (only if connected) in success callback, otherwise fail callback will be called (if not connected or unable to retrieve) +- This does **NOT** return the BSSID if unable to obtain SSID (like original WifiWizard did) + ```javascript -WifiWizard2.getConnectedBSSID() +WifiWizard2.getConnectedBSSID(); ``` - - Same as above, except BSSID (mac) is returned + +- Same as above, except BSSID (mac) is returned ```javascript -WifiWizard2.timeout(delay) +WifiWizard2.timeout(delay); ``` - - `delay` should be time in milliseconds to delay - - Helper async timeout delay, `delay` is optional, default is 2000ms = 2 seconds - - This method always returns a resolved promise after the delay, it will never reject or throw an error + +- `delay` should be time in milliseconds to delay +- Helper async timeout delay, `delay` is optional, default is 2000ms = 2 seconds +- This method always returns a resolved promise after the delay, it will never reject or throw an error **Example inside async function** + ```javascript -async function example(){ - await WifiWizard2.timeout(4000); - // do something after 4 seconds +async function example() { + await WifiWizard2.timeout(4000); + // do something after 4 seconds } ``` **Example inside standard non-async function** + ```javascript function example(){ WifiWizard2.timeout(4000).then( function(){ @@ -119,91 +137,122 @@ function example(){ } ``` - **Thrown Errors** +**Thrown Errors** - `TIMEOUT_WAITING_FOR_SCAN` on timeout waiting for scan 10 seconds + - `SCAN_FAILED` if unable to start scan # iOS Functions + For functionality, you need to note the following: - - Connect/Disconnect only works for iOS11+ - - Can't run in the simulator so you need to attach an actual device when building with xCode - - Will ensure 'HotspotConfiguration' and 'NetworkExtensions' capabilities are added to your xCode project - - To connect to open network omit `ssidPassword` or call with `false` + +- Connect/Disconnect only works for iOS11+ +- Can't run in the simulator so you need to attach an actual device when building with xCode +- Will ensure 'HotspotConfiguration' and 'NetworkExtensions' capabilities are added to your xCode project +- To connect to open network omit `ssidPassword` or call with `false` ```javascript -WifiWizard2.iOSConnectNetwork(ssid, ssidPassword) +WifiWizard2.iOSConnectNetwork(ssid, ssidPassword); ``` + ```javascript -WifiWizard2.iOSDisconnectNetwork(ssid) +WifiWizard2.iOSDisconnectNetwork(ssid); ``` # Android Functions - - **WifiWizard2** *will automagically try to enable WiFi if it's disabled when calling any android related methods that require WiFi to be enabled* + +## WiFi connection Specifier + +Android 10 Api >= 29 Specifier connection. Native Ui show modal for connect one device to your Phone. +You can select one network or cancel operation. +Tested success on Samsung SM-N960F and Redmi 7 + +```javascript +WifiWizard2.specifierConnection(sid, password, alhorithm, isHiddenSSID); +``` + +- `ssid` can either be an SSID (string) +- `password` ASCII password (string) +- `alhorithm` by default is (WPA) you can parse (string) "WPA, WPA2, WPA3" +- `isHiddenSSID` boolean determine if is hidden or not +- return boolean, true or false, when is connected or user press cancel on request modal. + +**Thrown Errors** + +- `SPECIFIER_INVALID_DATA` Invalid data format +- `SPECIFIER_NETWORK_UNAVAILABLE` Android returned error when network is not accessible +- `SPECIFIER_INVALID_API_VERSION` Android this function is accesible form Api version 29 + +- **WifiWizard2** _will automagically try to enable WiFi if it's disabled when calling any android related methods that require WiFi to be enabled_ ## Connect vs Enable + When writing Android Java code, there is no `connect` methods, you basically either `enable` or `disable` a network. In the original versions of WifiWizard the `connect` method would basically just call `enable` in Android. I have changed the way this works in WifiWizard2 version 3.0.0+, converting it to a helper method to eliminate having to call `formatWifiConfig` then `add` and then `enable` ... the `connect` method will now automatically call `formatWifiConfig`, then call `add` to either add or update the network configuration, and then call `enable`. If the connect method is unable to update existing network configuration (added by user or other apps), but there is a valid network ID, it will still attempt to enable that network ID. ```javascript -WifiWizard2.connect(ssid, bindAll, password, algorithm, isHiddenSSID) +WifiWizard2.connect(ssid, bindAll, password, algorithm, isHiddenSSID); ``` - - `ssid` should be the SSID to connect to *required* - - `bindAll` should be set to `true` to tell Android to route all connections from your Android app, through the wifi connection (default is `false`) *optional* - - See `WifiWizard2.enable` for more details regarding `bindAll` feature - - `algorithm` and `password` is not required if connecting to an open network - - Currently `WPA` and `WEP` are only supported algorithms - - For `WPA2` just pass `WPA` as the algorithm - - Set `isHiddenSSID` to `true` if the network you're connecting to is hidden - - These arguments are the same as for `formatWifiConfig` - - This method essentially calls `formatWifiConfig` then `add` then `enable` - - If unable to update network configuration (was added by user or other app), but a valid network ID exists, this method will still attempt to enable the network - - Promise will not be returned until method has verified that connection to WiFi was in completed state (waits up to 60 seconds) -**Thrown Errors** - - - - `CONNECT_FAILED_TIMEOUT` unable to verify connection, timed out after 60 seconds - - `INVALID_NETWORK_ID_TO_CONNECT` Unable to connect based on generated wifi config - - `INTERPUT_EXCEPT_WHILE_CONNECTING` Interupt exception while waiting for connection +- `ssid` should be the SSID to connect to _required_ +- `bindAll` should be set to `true` to tell Android to route all connections from your Android app, through the wifi connection (default is `false`) _optional_ + - See `WifiWizard2.enable` for more details regarding `bindAll` feature +- `algorithm` and `password` is not required if connecting to an open network +- Currently `WPA` and `WEP` are only supported algorithms +- For `WPA2` just pass `WPA` as the algorithm +- Set `isHiddenSSID` to `true` if the network you're connecting to is hidden +- These arguments are the same as for `formatWifiConfig` +- This method essentially calls `formatWifiConfig` then `add` then `enable` +- If unable to update network configuration (was added by user or other app), but a valid network ID exists, this method will still attempt to enable the network +- Promise will not be returned until method has verified that connection to WiFi was in completed state (waits up to 60 seconds) +**Thrown Errors** +- `CONNECT_FAILED_TIMEOUT` unable to verify connection, timed out after 60 seconds +- `INVALID_NETWORK_ID_TO_CONNECT` Unable to connect based on generated wifi config +- `INTERPUT_EXCEPT_WHILE_CONNECTING` Interupt exception while waiting for connection ## Disconnect vs Disable + Same as above for Connect vs Enable, except in this situation, `disconnect` will first disable the network, and then attempt to remove it (if SSID is passed) ```javascript -WifiWizard2.disconnect(ssid) +WifiWizard2.disconnect(ssid); ``` - - `ssid` can either be an SSID (string) or a network ID (integer) - - `ssid` is **OPTIONAL** .. if not passed, will disconnect current WiFi (almost all Android versions now will just automatically reconnect to last wifi after disconnecting) - - If `ssid` is provided, this method will first attempt to `disable` and then `remove` the network - - If you do not want to remove network configuration, use `disable` instead + +- `ssid` can either be an SSID (string) or a network ID (integer) +- `ssid` is **OPTIONAL** .. if not passed, will disconnect current WiFi (almost all Android versions now will just automatically reconnect to last wifi after disconnecting) +- If `ssid` is provided, this method will first attempt to `disable` and then `remove` the network +- If you do not want to remove network configuration, use `disable` instead **Thrown Errors** - - `DISCONNECT_NET_REMOVE_ERROR` Android returned error when removing wifi configuration - - `DISCONNECT_NET_DISABLE_ERROR` Unable to connect based on generated wifi config - - `DISCONNECT_NET_ID_NOT_FOUND` Unable to determine network ID to disconnect/remove (from passed SSID) - - `ERROR_DISCONNECT` - Android error disconnecting wifi (only when SSID is not passed) +- `DISCONNECT_NET_REMOVE_ERROR` Android returned error when removing wifi configuration +- `DISCONNECT_NET_DISABLE_ERROR` Unable to connect based on generated wifi config +- `DISCONNECT_NET_ID_NOT_FOUND` Unable to determine network ID to disconnect/remove (from passed SSID) +- `ERROR_DISCONNECT` - Android error disconnecting wifi (only when SSID is not passed) ```javascript -WifiWizard2.formatWifiConfig(ssid, password, algorithm, isHiddenSSID) +WifiWizard2.formatWifiConfig(ssid, password, algorithm, isHiddenSSID); ``` - - `algorithm` and `password` is not required if connecting to an open network - - Currently `WPA` and `WEP` are only supported algorithms - - For `WPA2` just pass `WPA` as the algorithm - - Set `isHiddenSSID` to `true` if the network you're connecting to is hidden + +- `algorithm` and `password` is not required if connecting to an open network +- Currently `WPA` and `WEP` are only supported algorithms +- For `WPA2` just pass `WPA` as the algorithm +- Set `isHiddenSSID` to `true` if the network you're connecting to is hidden + ```javascript -WifiWizard2.formatWPAConfig(ssid, password, isHiddenSSID) +WifiWizard2.formatWPAConfig(ssid, password, isHiddenSSID); ``` - - This is just a helper method that calls `WifiWizard2.formatWifiConfig( ssid, password, 'WPA', isHiddenSSID );` + +- This is just a helper method that calls `WifiWizard2.formatWifiConfig( ssid, password, 'WPA', isHiddenSSID );` ```javascript -WifiWizard2.add(wifi) +WifiWizard2.add(wifi); ``` - - `wifi` must be an object formatted by `formatWifiConfig`, this **must** be done before calling `enable` + +- `wifi` must be an object formatted by `formatWifiConfig`, this **must** be done before calling `enable` **Thrown Errors** @@ -212,42 +261,45 @@ WifiWizard2.add(wifi) - `ERROR_UPDATING_NETWORK` - Same as above, except an existing network ID was found, and unable to update it ```javascript -WifiWizard2.remove(ssid) +WifiWizard2.remove(ssid); ``` - - `ssid` can either be an SSID (string) or a network ID (integer) - - Please note, most newer versions of Android will only allow wifi to be removed if created by your application -**Thrown Errors** +- `ssid` can either be an SSID (string) or a network ID (integer) +- Please note, most newer versions of Android will only allow wifi to be removed if created by your application - - `UNABLE_TO_REMOVE` Android returned failure in removing network - - `REMOVE_NETWORK_NOT_FOUND` Unable to determine network ID from passed SSID +**Thrown Errors** +- `UNABLE_TO_REMOVE` Android returned failure in removing network +- `REMOVE_NETWORK_NOT_FOUND` Unable to determine network ID from passed SSID ```javascript -WifiWizard2.listNetworks() +WifiWizard2.listNetworks(); ``` ```javascript -WifiWizard2.scan([options]) +WifiWizard2.scan([options]); ``` + - Same as calling `startScan` and then `getScanResults`, except this method will only resolve the promise after the scan completes and returns the results. ```javascript -WifiWizard2.startScan() +WifiWizard2.startScan(); ``` - - It is recommended to just use the `scan` method instead of `startScan` -**Thrown Errors** +- It is recommended to just use the `scan` method instead of `startScan` - - `STARTSCAN_FAILED` Android returned failure in starting scan +**Thrown Errors** +- `STARTSCAN_FAILED` Android returned failure in starting scan ```javascript -WifiWizard2.getScanResults([options]) +WifiWizard2.getScanResults([options]); ``` + - `getScanResults` should only be called after calling `startScan` (it is recommended to use `scan` instead as this starts the scan, then returns the results) - `[options]` is optional, if you do not want to specify, just pass `success` callback as first parameter, and `fail` callback as second parameter - Retrieves a list of the available networks as an array of objects and passes them to the function listHandler. The format of the array is: + ```javascript networks = [ { "level": signal_level, // raw RSSI value @@ -262,192 +314,216 @@ networks = [ } ] ``` + - `channelWidth` `centerFreq0` and `centerFreq1` are only supported on API > 23 (Marshmallow), any older API will return null for these values -An options object may be passed. Currently, the only supported option is `numLevels`, and it has the following behavior: +An options object may be passed. Currently, the only supported option is `numLevels`, and it has the following behavior: - if `(n == true || n < 2)`, `*.getScanResults({numLevels: n})` will return data as before, split in 5 levels; - if `(n > 1)`, `*.getScanResults({numLevels: n})` will calculate the signal level, split in n levels; - if `(n == false)`, `*.getScanResults({numLevels: n})` will use the raw signal level; ```javascript -WifiWizard2.isWifiEnabled() +WifiWizard2.isWifiEnabled(); ``` - - Returns boolean value of whether Wifi is enabled or not + +- Returns boolean value of whether Wifi is enabled or not + ```javascript -WifiWizard2.setWifiEnabled(enabled) +WifiWizard2.setWifiEnabled(enabled); ``` - - Pass `true` for `enabled` parameter to set Wifi enabled - - You do not need to call this function to set WiFi enabled to call other methods that require wifi enabled. This plugin will automagically enable WiFi if a method is called that requires WiFi to be enabled. + +- Pass `true` for `enabled` parameter to set Wifi enabled +- You do not need to call this function to set WiFi enabled to call other methods that require wifi enabled. This plugin will automagically enable WiFi if a method is called that requires WiFi to be enabled. **Thrown Errors** - - `ERROR_SETWIFIENABLED` wifi state does not match call (enable or disable) +- `ERROR_SETWIFIENABLED` wifi state does not match call (enable or disable) ```javascript -WifiWizard2.getConnectedNetworkID() +WifiWizard2.getConnectedNetworkID(); ``` - - Returns currently connected network ID in success callback (only if connected), otherwise fail callback will be called + +- Returns currently connected network ID in success callback (only if connected), otherwise fail callback will be called **Thrown Errors** - - `GET_CONNECTED_NET_ID_ERROR` Unable to determine currently connected network ID (may not be connected) +- `GET_CONNECTED_NET_ID_ERROR` Unable to determine currently connected network ID (may not be connected) ## New to 3.2.0+ + ```javascript -WifiWizard2.isLocationEnabled() +WifiWizard2.specifierConnection(sid, password, alhorithm, isHiddenSSID); ``` - - Check if Location (globally) is enabled or not + +- Android 10 Api >= 29 Specifier connection. ```javascript -WifiWizard2.switchToLocationSettings() +WifiWizard2.isLocationEnabled(); ``` - - Switch to Location settings screen in Android -## New to 3.1.1+ +- Check if Location (globally) is enabled or not + ```javascript -WifiWizard2.resetBindAll() +WifiWizard2.switchToLocationSettings(); ``` - - Disable bindAll to WiFi network without disconnecting from WiFi + +- Switch to Location settings screen in Android + +## New to 3.1.1+ ```javascript -WifiWizard2.setBindAll() +WifiWizard2.resetBindAll(); ``` - - Enable bindAll to WiFi network without disconnecting from WiFi + +- Disable bindAll to WiFi network without disconnecting from WiFi ```javascript -WifiWizard2.canConnectToInternet() +WifiWizard2.setBindAll(); ``` - - Returns boolean, true or false, if device is able to connect to https://www.google.com via HTTP connection (since ping is unreliable) - - Unknown errors will still be thrown like all other async functions - - If you called `connect` or `enable` and passed `true` for `bindAll`, your application will force the ping through wifi connection. - - If you did not pass `true` (or passed `false`) for `bindAll`, and the wifi does not have internet connection, Android Lollipop+ (API 21+) will use cell connection to ping (due to Android using cell connection when wifi does not have internet) [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) +- Enable bindAll to WiFi network without disconnecting from WiFi +```javascript +WifiWizard2.canConnectToInternet(); +``` + +- Returns boolean, true or false, if device is able to connect to https://www.google.com via HTTP connection (since ping is unreliable) +- Unknown errors will still be thrown like all other async functions +- If you called `connect` or `enable` and passed `true` for `bindAll`, your application will force the ping through wifi connection. +- If you did not pass `true` (or passed `false`) for `bindAll`, and the wifi does not have internet connection, Android Lollipop+ (API 21+) will use cell connection to ping (due to Android using cell connection when wifi does not have internet) [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) ```javascript -WifiWizard2.canConnectToRouter() +WifiWizard2.canConnectToRouter(); ``` - - As `canPingWifiRouter` is notoriously unreliable, this method uses HTTP connection to test if able to connect to router (as most routers should have web server running on port 80) - - Unknown errors will still be thrown like all other async functions - - This is useful for testing to make sure that your Android app is able to connect to the private network after connecting to WiFi - - This was added for testing the `bindAll` feature to support issues with Android Lollipop+ (API 21+) not routing calls through WiFi if WiFi does not have internet connection [See Android Blog](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) - - Attempts to connect router IP HTTP server on port 80 (example: `http://192.168.0.1/` where `192.168.0.1` is the automatically detected IP address) + +- As `canPingWifiRouter` is notoriously unreliable, this method uses HTTP connection to test if able to connect to router (as most routers should have web server running on port 80) +- Unknown errors will still be thrown like all other async functions +- This is useful for testing to make sure that your Android app is able to connect to the private network after connecting to WiFi +- This was added for testing the `bindAll` feature to support issues with Android Lollipop+ (API 21+) not routing calls through WiFi if WiFi does not have internet connection [See Android Blog](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) +- Attempts to connect router IP HTTP server on port 80 (example: `http://192.168.0.1/` where `192.168.0.1` is the automatically detected IP address) ## New to 3.0.0+ + ```javascript -WifiWizard2.isConnectedToInternet() +WifiWizard2.isConnectedToInternet(); ``` - - Returns boolean, true or false, if device is able to ping 8.8.8.8 - - Unknown errors will still be thrown like all other async functions - - If you called `connect` or `enable` and passed `true` for `bindAll`, your application will force the ping through wifi connection. - - If you did not pass `true` (or passed `false`) for `bindAll`, and the wifi does not have internet connection, Android Lollipop+ (API 21+) will use cell connection to ping (due to Android using cell connection when wifi does not have internet) [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) +- Returns boolean, true or false, if device is able to ping 8.8.8.8 +- Unknown errors will still be thrown like all other async functions +- If you called `connect` or `enable` and passed `true` for `bindAll`, your application will force the ping through wifi connection. +- If you did not pass `true` (or passed `false`) for `bindAll`, and the wifi does not have internet connection, Android Lollipop+ (API 21+) will use cell connection to ping (due to Android using cell connection when wifi does not have internet) [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) ```javascript -WifiWizard2.canPingWifiRouter() +WifiWizard2.canPingWifiRouter(); ``` - - Returns boolean, true or false, if device is able to ping the connected WiFi router IP (obtained from DHCP info) - - Version 3.1.1+ uses HTTP connection to test if able to connect to router (as ping previous did not work) - - Unknown errors will still be thrown like all other async functions - - This is useful for testing to make sure that your Android app is able to connect to the private network after connecting to WiFi - - This was added for testing the `bindAll` feature to support issues with Android Lollipop+ (API 21+) not routing calls through WiFi if WiFi does not have internet connection [See Android Blog](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) +- Returns boolean, true or false, if device is able to ping the connected WiFi router IP (obtained from DHCP info) +- Version 3.1.1+ uses HTTP connection to test if able to connect to router (as ping previous did not work) +- Unknown errors will still be thrown like all other async functions +- This is useful for testing to make sure that your Android app is able to connect to the private network after connecting to WiFi +- This was added for testing the `bindAll` feature to support issues with Android Lollipop+ (API 21+) not routing calls through WiFi if WiFi does not have internet connection [See Android Blog](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) ```javascript -WifiWizard2.enableWifi() +WifiWizard2.enableWifi(); ``` ```javascript -WifiWizard2.disableWifi() +WifiWizard2.disableWifi(); ``` ```javascript -WifiWizard2.getWifiIP() +WifiWizard2.getWifiIP(); ``` - - Returns IPv4 address of currently connected WiFi, or rejects promise if IP not found or wifi not connected + +- Returns IPv4 address of currently connected WiFi, or rejects promise if IP not found or wifi not connected ```javascript -WifiWizard2.getWifiRouterIP() +WifiWizard2.getWifiRouterIP(); ``` - - Returns IPv4 WiFi router IP from currently connected WiFi, or rejects promise if unable to determine, or wifi not connected + +- Returns IPv4 WiFi router IP from currently connected WiFi, or rejects promise if unable to determine, or wifi not connected **Thrown Errors** - - `NO_VALID_IP_IDENTIFIED` if unable to determine a valid IP (ip returned from device is `0.0.0.0`) +- `NO_VALID_IP_IDENTIFIED` if unable to determine a valid IP (ip returned from device is `0.0.0.0`) ```javascript -WifiWizard2.getWifiIPInfo() +WifiWizard2.getWifiIPInfo(); ``` - - Returns a JSON object with IPv4 address and subnet `{"ip": "192.168.1.2", "subnet": "255.255.255.0" }` or rejected promise if not found or not connected -**Thrown Errors** - - `NO_VALID_IP_IDENTIFIED` if unable to determine a valid IP (ip returned from device is `0.0.0.0`) +- Returns a JSON object with IPv4 address and subnet `{"ip": "192.168.1.2", "subnet": "255.255.255.0" }` or rejected promise if not found or not connected + **Thrown Errors** + +- `NO_VALID_IP_IDENTIFIED` if unable to determine a valid IP (ip returned from device is `0.0.0.0`) ```javascript -WifiWizard2.reconnect() +WifiWizard2.reconnect(); ``` - - Reconnect to the currently active access point, **if we are currently disconnected.** + +- Reconnect to the currently active access point, **if we are currently disconnected.** **Thrown Errors** - - `ERROR_RECONNECT` Android returned error when reconnecting +- `ERROR_RECONNECT` Android returned error when reconnecting ```javascript -WifiWizard2.reassociate() +WifiWizard2.reassociate(); ``` - - Reconnect to the currently active access point, **even if we are already connected.** -**Thrown Errors** +- Reconnect to the currently active access point, **even if we are already connected.** - - `ERROR_REASSOCIATE` Android returned error when reassociating +**Thrown Errors** +- `ERROR_REASSOCIATE` Android returned error when reassociating ```javascript -WifiWizard2.getSSIDNetworkID(ssid) +WifiWizard2.getSSIDNetworkID(ssid); ``` - - Get Android Network ID from passed SSID + +- Get Android Network ID from passed SSID ```javascript -WifiWizard2.disable(ssid) +WifiWizard2.disable(ssid); ``` - - `ssid` can either be an SSID (string) or a network ID (integer) - - Disable the passed SSID network - - Please note that most newer versions of Android will only allow you to disable networks created by your application -**Thrown Errors** +- `ssid` can either be an SSID (string) or a network ID (integer) +- Disable the passed SSID network +- Please note that most newer versions of Android will only allow you to disable networks created by your application - - `UNABLE_TO_DISABLE` Android returned failure in disabling network - - `DISABLE_NETWORK_NOT_FOUND` Unable to determine network ID from passed SSID to disable +**Thrown Errors** +- `UNABLE_TO_DISABLE` Android returned failure in disabling network +- `DISABLE_NETWORK_NOT_FOUND` Unable to determine network ID from passed SSID to disable ```javascript -WifiWizard2.requestPermission() +WifiWizard2.requestPermission(); ``` - - Request `ACCESS_FINE_LOCATION` permssion - - This Android permission is required to run `scan`, `startStart` and `getScanResults` - - You can request permission by running this function manually, or WifiWizard2 will automagically request permission when one of the functions above is called -**Thrown Errors** +- Request `ACCESS_FINE_LOCATION` permssion +- This Android permission is required to run `scan`, `startStart` and `getScanResults` +- You can request permission by running this function manually, or WifiWizard2 will automagically request permission when one of the functions above is called - - `PERMISSION_DENIED` user denied permission on device +**Thrown Errors** +- `PERMISSION_DENIED` user denied permission on device ```javascript -WifiWizard2.enable(ssid, bindAll, waitForConnection) +WifiWizard2.enable(ssid, bindAll, waitForConnection); ``` - - `ssid` can either be an SSID (string) or a network ID (integer) - - `bindAll` should be set to `true` to tell Android to route all connections from your Android app, through the wifi connection - - Android Lollipop+ (API 21+) will not route connections to the WiFi device if it does not have internet connection. Passing `true` to `bindAll` will force Android to route connections from your Android app through Wifi, regardless of internet connection. - - If you are having problems connecting to a local IP through WiFi because it does not have internet, try enabling `bindAll` and this should fix the problem. - - During my testing, some versions of Android (5.0 - 7.1.2) would still route connections through WiFi without internet, but it was random that some versions would and would not work. - - Testing Android Oreo+ (8.0.0+) if wifi does not have internet, 100% of the time it would NOT route connections through WiFi, so you *must* enable this for Oreo or newer to route connections from your application through wifi without internet. - - When `bindAll` is enabled, *ALL* connections from your app will be routed through WiFi, until you call `disconnect` or `disable` - - See the Google Android Blog for [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) - - This feature *ONLY* works for Android Lollipop+ (API 21+), if device is running API older than 21, `bindall` will be ignored (as API older than 21 does this by default) - - Enable the passed SSID network - - You **MUST** call `WifiWizard2.add(wifi)` before calling `enable` as the wifi configuration must exist before you can enable it (or previously used `connect` without calling `disconnect`) - - This method does NOT wait or verify connection to wifi network, pass `true` to `waitForConnection` to only return promise once connection is verified in COMPLETED state to specific `ssid` + +- `ssid` can either be an SSID (string) or a network ID (integer) +- `bindAll` should be set to `true` to tell Android to route all connections from your Android app, through the wifi connection + - Android Lollipop+ (API 21+) will not route connections to the WiFi device if it does not have internet connection. Passing `true` to `bindAll` will force Android to route connections from your Android app through Wifi, regardless of internet connection. + - If you are having problems connecting to a local IP through WiFi because it does not have internet, try enabling `bindAll` and this should fix the problem. + - During my testing, some versions of Android (5.0 - 7.1.2) would still route connections through WiFi without internet, but it was random that some versions would and would not work. + - Testing Android Oreo+ (8.0.0+) if wifi does not have internet, 100% of the time it would NOT route connections through WiFi, so you _must_ enable this for Oreo or newer to route connections from your application through wifi without internet. + - When `bindAll` is enabled, _ALL_ connections from your app will be routed through WiFi, until you call `disconnect` or `disable` + - See the Google Android Blog for [More Details](https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html) + - This feature _ONLY_ works for Android Lollipop+ (API 21+), if device is running API older than 21, `bindall` will be ignored (as API older than 21 does this by default) +- Enable the passed SSID network +- You **MUST** call `WifiWizard2.add(wifi)` before calling `enable` as the wifi configuration must exist before you can enable it (or previously used `connect` without calling `disconnect`) +- This method does NOT wait or verify connection to wifi network, pass `true` to `waitForConnection` to only return promise once connection is verified in COMPLETED state to specific `ssid` **Thrown Errors** @@ -457,35 +533,41 @@ WifiWizard2.enable(ssid, bindAll, waitForConnection) ## Master -Run ```cordova plugin add https://github.com/tripflex/WiFiWizard2``` +Run `cordova plugin add https://github.com/tripflex/WiFiWizard2` To install from the master branch (latest on GitHub) To install a specific branch (add `#tag` replacing `tag` with tag from this repo, example: -```cordova plugin add https://github.com/tripflex/wifiwizard2#v3.2.0``` +`cordova plugin add https://github.com/tripflex/wifiwizard2#v3.2.0` + +To install Beta use this branch: +`cordova plugin add https://github.com/tripflex/wifiwizard2#dev` Find available tags here: https://github.com/tripflex/WifiWizard2/tags - If you are wanting to have the latest and greatest stable version, then run the 'Releases' command below. ## Releases -Run ```cordova plugin add cordova-plugin-wifiwizard2``` + +Run `cordova plugin add cordova-plugin-wifiwizard2` ## Meteor + To install and use this plugin in a Meteor project, you have to specify the exact version from NPM repository: [https://www.npmjs.com/package/cordova-plugin-wifiwizard2](https://www.npmjs.com/package/cordova-plugin-wifiwizard2) As of XXX, the latest version is 3.2.0: -```meteor add cordova:cordova-plugin-wifiwizard2@3.2.0``` +`meteor add cordova:cordova-plugin-wifiwizard2@3.2.0` # Errors/Rejections -Methods now return formatted string errors as detailed below, instead of returning generic error messages. This allows you to check yourself what specific error was returned, and customize the error message. + +Methods now return formatted string errors as detailed below, instead of returning generic error messages. This allows you to check yourself what specific error was returned, and customize the error message. In an upcoming release I may add easy ways to override generic messages, or set your own, but for now, errors returned can be found below each method/function. ## Generic **Thrown Errors** + `WIFI_NOT_ENABLED` # Examples @@ -494,19 +576,20 @@ Please see demo Meteor project for code examples: [https://github.com/tripflex/WifiWizard2Demo](https://github.com/tripflex/WifiWizard2Demo) ## Ionic/Angular Example (User Provided) + Props @13546777510 (Angelo Fan) has provided a basic Ionic/Angluar demo app: [https://github.com/13546777510/WifiWizard2-Demo](https://github.com/13546777510/WifiWizard2-Demo) See issue [#69](https://github.com/tripflex/WifiWizard2/issues/69) regarding this -I recommend using [ES6 arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to maintain `this` reference. This is especially useful if you're using Blaze and Meteor. +I recommend using [ES6 arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to maintain `this` reference. This is especially useful if you're using Blaze and Meteor. ```javascript this.FirstName = 'John'; -wifiConnection.then( result => { - // Do something after connecting! - // Using arrow functions, you still have access to `this` - console.log( this.FirstName + ' connected to wifi!' ); +wifiConnection.then((result) => { + // Do something after connecting! + // Using arrow functions, you still have access to `this` + console.log(this.FirstName + ' connected to wifi!'); }); ``` @@ -514,12 +597,16 @@ wifiConnection.then( result => { Apache 2.0 # Changelog: + **3.2.0** - TBD + +- Added specifier connection method `specifierConnection()` - Added check before calling `scan()`, `startScan()`, `getScanResults()`, `getConnectedSSID()`, `getConnectedBSSID()` if Location is globally enabled, ottherwise reject promise due to location being disabled - Added `isLocationEnabled()` method port from [Cordova Diagnostic Plugin](https://github.com/dpa99c/cordova-diagnostic-plugin) Issue #44 - Added `switchToLocationSettings()` method to switch to Location Settings in Android - + **3.1.1** - April 4, 2019 + - Fixed/Added location services check for Android 9+ for any method that utilises the getConnectionInfo method. Issue #71 (@arsenal942) - Move verifyWifiEnabled() to after methods that do not require wifi to be enabled. Issue #54 (@props seanyang1984) - Added `canConnectToRouter()` and `canConnectToInternet()` to use HTTP to test connection (since ping is notoriously unreliable) @@ -529,6 +616,7 @@ Apache 2.0 - Added `isLocationEnabled()` method port from [Cordova Diagnostic Plugin](https://github.com/dpa99c/cordova-diagnostic-plugin) Issue #44 **3.1.0** - August 28, 2018 + - Fixed/Added compatibility with iOS to connect to open network - Fixed Uncaught SyntaxError in JavaScript from using let (changed to var) - Fixed main thread blocked while connecting to a network by connecting asynchronously (props @jack828) @@ -542,6 +630,7 @@ Apache 2.0 - Props to @arsenal942 @jack828 @xLarry @saoron for contributions **3.0.0** - April 12, 2018 + - Completely refactored JS methods, all now return Promises - Added `getWifiIP` and `getWifiIPInfo` functions - Added `getWifiRouterIP` function @@ -558,23 +647,26 @@ Apache 2.0 - Updated all error callbacks to use detectable strings (for custom error messages, instead of generic ones) - DO NOT upgrade from version 2.x.x without reading ENTIRE README! Method/Function names have all been changed! -**2.1.1** - *1/9/2018* +**2.1.1** - _1/9/2018_ + - **Added Async Promise based methods** - Fix issue with thread running before wifi is fully enabled - Added thread sleep for up to 10 seconds waiting for wifi to enable -**2.1.0** - *1/8/2018* +**2.1.0** - _1/8/2018_ + - **Added Async Promise based methods** - Fixed incorrect Android Cordova exec methods incorrectly being called and returned (fixes INVALID ACTION errors/warnings) - Updated javascript code to call `fail` callback when error detected in JS (before calling Cordova) - Moved automagically enabling WiFi to `exec` actions (before actions called that require wifi enabled) - Added `es6-promise-plugin` cordova dependency to plugin.xml - Only return `false` in [Cordova Android](https://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html) `execute` when invalid action is called - [Issue #1](https://github.com/tripflex/WifiWizard2/issues/1) + [Issue #1](https://github.com/tripflex/WifiWizard2/issues/1) - Added JS doc blocks to JS methods - Added Async example code -**2.0.0** - *1/5/2018* +**2.0.0** - _1/5/2018_ + - Added automatic disable of currently connected network on connect call (to prevent reconnect to previous wifi ssid) - Added initial `disconnect()` before and `reconnect()` after disable/enable network on connect call - Added `getConnectedNetworkID` to return currently connected network ID @@ -593,7 +685,6 @@ Apache 2.0 **Changelog below this line, is from original WifiWizard** - **v0.2.9** `isWifiEnabled` bug fixed. `level` in `getScanResults` object now refers to raw RSSI value. The function now accepts an options object, and by specifiying `{ numLevels: value }` you can get the old behavior. @@ -606,50 +697,50 @@ Apache 2.0 - Clobber WifiWizard.js automatically via Cordova plugin architecture -**v0.2.6** +**v0.2.6** - Added `isWifiEnabled`, `setWifiEnabled` -**v0.2.5** +**v0.2.5** - Fixes `getConnectedSSID` error handlers -**v0.2.4** +**v0.2.4** - Added `getConnectedSSID` method -**v0.2.3** +**v0.2.3** - Added `disconnect` that does disconnection on current WiFi -**v0.2.2** +**v0.2.2** - Added `startScan` and `getScanResults` -**v0.2.1** +**v0.2.1** - Fixed reference problem in `formatWPAConfig` -**v0.2.0** +**v0.2.0** - Changed format of wifiConfiguration object to allow more extensibility. -**v0.1.1** +**v0.1.1** - `addNetwork` will now update the network if the SSID already exists. -**v0.1.0** +**v0.1.0** - All functions now work! -**v0.0.3** +**v0.0.3** - Fixed errors in native implementation. Currently, Add and Remove networks aren't working, but others are working as expected. -**v0.0.2** +**v0.0.2** - Changed plugin.xml and WifiWizard.js to attach WifiWizard directly to the HTML. -**v0.0.1** +**v0.0.1** - Initial commit diff --git a/src/android/wifiwizard2/WifiWizard2.java b/src/android/wifiwizard2/WifiWizard2.java index b7a8aea..9aaaa86 100644 --- a/src/android/wifiwizard2/WifiWizard2.java +++ b/src/android/wifiwizard2/WifiWizard2.java @@ -49,7 +49,7 @@ import android.content.Context; import android.os.AsyncTask; import android.util.Log; -import android.os.Build.VERSION; +import android.os.Build; import java.net.URL; import java.net.InetAddress; @@ -60,11 +60,16 @@ import java.net.UnknownHostException; +import java.util.ArrayList; +import android.net.wifi.WifiNetworkSpecifier; + public class WifiWizard2 extends CordovaPlugin { private static final String TAG = "WifiWizard2"; - private static final int API_VERSION = VERSION.SDK_INT; + private static final int API_VERSION = Build.VERSION.SDK_INT; + private static final String SPECIFIER_NETWORK = "specifierConnection"; //>=29 + private static final String ADD_NETWORK = "add"; private static final String REMOVE_NETWORK = "remove"; private static final String CONNECT_NETWORK = "connect"; @@ -109,7 +114,7 @@ public class WifiWizard2 extends CordovaPlugin { private WifiManager wifiManager; private CallbackContext callbackContext; private JSONArray passedData; - + public static LocationManager locationManager; private ConnectivityManager connectivityManager; @@ -163,7 +168,14 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo this.callbackContext = callbackContext; this.passedData = data; - + + //>= 29 + if(action.equals(SPECIFIER_NETWORK)) + { + this.specifierConnection(callbackContext, data); + return true; + } + // Actions that do not require WiFi to be enabled if (action.equals(IS_LOCATION_ENABLED)) { this.isLocationEnabled(callbackContext); @@ -223,7 +235,7 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo callbackContext.error("WIFI_NOT_ENABLED"); return true; // Even though enable wifi failed, we still return true and handle error in callback } - + // Actions that DO require WiFi to be enabled if (action.equals(ADD_NETWORK)) { this.add(callbackContext, data); @@ -696,7 +708,7 @@ private boolean remove(CallbackContext callbackContext, JSONArray data) { * @param data JSON Array, with [0] being SSID to connect */ private void connect(CallbackContext callbackContext, JSONArray data) { - Log.d(TAG, "WifiWizard2: connect entered."); + Log.v(TAG, "WifiWizard2: connect entered."); if (!validateData(data)) { callbackContext.error("CONNECT_INVALID_DATA"); @@ -1954,4 +1966,98 @@ private static class AP { } } + + /* + * Specifier one network to connect wifi providing ssid and password + * Author: Anthony Sychev (hello at dm211 dot com) + * + * DOC: https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder + */ + private void specifierConnection(CallbackContext callbackContext, JSONArray data) { + Log.d(TAG, "WifiWizard2: 211 - Api >= 29 WiFi connection specifier your api version: "+API_VERSION); + + if (API_VERSION >= 29) { + if (!validateData(data)) { + callbackContext.error("SPECIFIER_INVALID_DATA"); + Log.d(TAG, "WifiWizard2: 211 - specifierConnection invalid data."); + return; + } + + try { + String SSID = data.getString(0); + String PASS = data.getString(1); + String Algorithm = data.getString(2); + Boolean isHidden = data.getBoolean(3); + + Log.d(TAG, "WifiWizard2: 211 - data: "+ data); + Log.d(TAG, "WifiWizard2: 211 - ssid: "+ SSID); + Log.d(TAG, "WifiWizard2: 211 - pass: "+ PASS); + Log.d(TAG, "WifiWizard2: 211 - Algorithm: "+ Algorithm); + Log.d(TAG, "WifiWizard2: 211 - ishidden: "+ isHidden); + + WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder(); + builder.setSsid(SSID); + + if(Algorithm.matches("/WEP|WPA|WPA2/gim")) + { + builder.setWpa2Passphrase(PASS); + } + + if(Algorithm.matches("/WPA3/gim")) + { + builder.setWpa3Passphrase(PASS); + } + + if(isHidden) + { + builder.setIsHiddenSsid(true); + } + + WifiNetworkSpecifier wifiNetworkSpecifier = builder.build(); + + //-- + + NetworkRequest.Builder networkRequestBuilder1 = new NetworkRequest.Builder(); + + networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier); + } + + NetworkRequest networkRequest = networkRequestBuilder1.build(); + ConnectivityManager cm = (ConnectivityManager) + cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + ConnectivityManager.NetworkCallback networkCallback = new + ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + super.onAvailable(network); + Log.d(TAG, "WifiWizard2: 211 onAvailable:" + network); + callbackContext.success(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + cm.bindProcessToNetwork(network); + } + } + + @Override + public void onUnavailable() { + super.onUnavailable(); + Log.d(TAG, "WifiWizard2: 211 onUnavailable"); + callbackContext.error("SPECIFIER_NETWORK_UNAVAILABLE"); + } + }; + cm.requestNetwork(networkRequest, networkCallback); + + } catch (Exception e) { + callbackContext.error(e.getMessage()); + Log.d(TAG, e.getMessage()); + } + }else{ + callbackContext.error("SPECIFIER_INVALID_API_VERSION"); + Log.d(TAG, "WifiWizard2: 211 - specifierConnection invalid Android API Version is below as needed."); + } + } } diff --git a/www/WifiWizard2.js b/www/WifiWizard2.js index fc1b431..023324b 100644 --- a/www/WifiWizard2.js +++ b/www/WifiWizard2.js @@ -1,677 +1,685 @@ -/* - * Copyright 2018 Myles McNamara - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var WifiWizard2 = { - - /** - * Connect to network on iOS device - * @param ssid - * @param ssidPassword Password if connecting to WPA/WPA2 network (omit or use false to connect to open network) - * @returns {Promise} +cordova.define('wifiwizard2.WifiWizard2', function (require, exports, module) { + /* + * Copyright 2018 Myles McNamara + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - iOSConnectNetwork: function (ssid, ssidPassword) { - - return new Promise(function (resolve, reject) { - if( ssidPassword === undefined || ! ssidPassword || ssidPassword.length < 1 ){ - // iOS connect open network - cordova.exec(resolve, reject, "WifiWizard2", "iOSConnectOpenNetwork", [{ "Ssid": ssid }]); - - } else if( ssidPassword !== undefined && ssidPassword.length > 0 && ssidPassword.length < 8 ){ - // iOS pass length does not meet requirements (min 8 chars for WPA/WPA2) - reject("WPA/WPA2 password length must be at least 8 characters in length!"); - - } else { - // iOS connect to WPA/WPA2 network - cordova.exec(resolve, reject, "WifiWizard2", "iOSConnectNetwork", [ - { - "Ssid": ssid, - "Password": ssidPassword - }] - ); - } - - }); - - }, - - /** - * Disconnect from SSID on iOS device - * @param ssid - * @returns {Promise} - */ - iOSDisconnectNetwork: function (ssid) { - return new Promise(function (resolve, reject) { - - cordova.exec(resolve, reject, "WifiWizard2", "iOSDisconnectNetwork", [ - { - "Ssid": ssid - }]); - - }); - }, - - /** - * Add wifi network configuration - * @param wifi Must be object created by formatWifiConfig() - * @returns {Promise} - */ - add: function (wifi) { - - return new Promise(function (resolve, reject) { - - if (wifi !== null && typeof wifi === "object") { - // Ok to proceed! - - var networkInformation = []; - - if (wifi.SSID !== undefined && wifi.SSID !== "") { - networkInformation.push(wifi.SSID); - } else { - reject("No SSID given."); - return false; - } - - if (typeof wifi.auth == "object") { - - switch (wifi.auth.algorithm) { - case "WPA": - networkInformation.push("WPA"); - networkInformation.push(wifi.auth.password); - break; - case 'WEP': - networkInformation.push('WEP'); - networkInformation.push(wifi.auth.password); - break; - case "NONE": - networkInformation.push("NONE"); - // Adding twice for data structure consistency - networkInformation.push("NONE"); - break; - case "Newly supported type": - break; - default: - console.log("WifiWizard2: authentication invalid."); - } - - } else { - reject("WifiWizard2: No authentication algorithm given."); - return false; - } - - networkInformation.push(!!wifi.isHiddenSSID) - cordova.exec(resolve, reject, "WifiWizard2", "add", networkInformation); - - } else { - reject("Invalid parameter. Wifi not an object."); - return false; - } - }); - }, - - /** - * Remove wifi network configuration - * @param {string|int} [SSID] - * @returns {Promise} - */ - remove: function (SSID) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "remove", [WifiWizard2.formatWifiString(SSID)]); - }); - }, - - /** - * Connect network with specified SSID - * - * This method will first add the wifi configuration, then enable the network, returning promise when connection is verified. - * - * @param {string|int} [SSID] - * @param {boolean} [bindAll=false] Whether or not to bind all connections from app, through WiFi connection - * @param {string} [password=] - * @param {string} [algorithm=NONE] WPA, WPA (for WPA2), WEP or NONE (NONE by default) - * @returns {Promise} - */ - connect: function (SSID, bindAll, password, algorithm, isHiddenSSID) { - return new Promise(function (resolve, reject) { - - if (!SSID) { - reject('SSID is missing!'); - return; - } - - var wifiConfig = WifiWizard2.formatWifiConfig(SSID, password, algorithm, isHiddenSSID); - bindAll = bindAll ? true : false; - - if (!wifiConfig) { - reject('Algorithm incorrect'); - return; - } - - WifiWizard2.add(wifiConfig).then(function (newNetID) { - - // Successfully updated or added wifiConfig - cordova.exec(resolve, reject, "WifiWizard2", "connect", [WifiWizard2.formatWifiString(SSID), bindAll]); - - // Catch error adding/updating network - }).catch(function (error) { - - // This means the connection could have been setup by mobile phone user, or another app (separate from ours) - // Newer version of Android will NOT allow you to update, remove, any wifi networks setup by user or other apps (regardless of perms set) - if (error === "ERROR_UPDATING_NETWORK") { - - // This error above should only be returned when the add method was able to pull a network ID (as it tries to update instead of adding) - // Lets go ahead and attempt to connect to that SSID (using the existing wifi configuration) - cordova.exec(resolve, reject, "WifiWizard2", "connect", [WifiWizard2.formatWifiString(SSID), bindAll]); - - } else { - - reject(error); - - } - - }); // Close ADD - - }); - }, - - /** - * Disconnect (current if SSID not supplied) - * - * This method, if passed an SSID, will first disable the network, and then remove it from the device. To only "disconnect" (ie disable in android), - * call WifiWizard2.disable() instead of disconnect. - * - * @param {string|int} [SSID=all] - * @returns {Promise} - */ - disconnect: function (SSID) { - return new Promise(function (resolve, reject) { - - if (SSID) { - cordova.exec(resolve, reject, "WifiWizard2", "disconnectNetwork", [WifiWizard2.formatWifiString(SSID)]); - } else { - cordova.exec(resolve, reject, "WifiWizard2", "disconnect", []); - } - - }); - }, - - /** - * Enable Network - * @param {string|int} [SSID] - * @param {boolean} [bindAll=false] Whether or not to bind all network requests to this wifi network - * @param {boolean} [waitForConnection=false] Whether or not to wait before resolving promise until connection to wifi is verified - * @returns {Promise} - */ - enable: function (SSID, bindAll, waitForConnection) { - return new Promise(function (resolve, reject) { - bindAll = bindAll ? true : false; - waitForConnection = waitForConnection ? true : false; - cordova.exec(resolve, reject, "WifiWizard2", "enable", [WifiWizard2.formatWifiString(SSID), bindAll, waitForConnection]); - }); - }, - - /** - * Disable Network - * @param {string|int} [SSID] - * @returns {Promise} - */ - disable: function (SSID) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "disable", [WifiWizard2.formatWifiString(SSID)]); - }); - }, - - /** - * Reconnect to the currently active access point, even if we are already connected. - * @returns {Promise} - */ - reassociate: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "reassociate", []); - }); - }, - - /** - * Reconnect to the currently active access point, if we are currently disconnected. - * @returns {Promise} - */ - reconnect: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "reconnect", []); - }); - }, - - /** - * Returns currently configured networks - * @returns {Promise} - */ - listNetworks: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "listNetworks", []); - }); - }, - - /** - * Start network scan and return results - * @param options - * @returns {Promise} - */ - scan: function (options) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, 'WifiWizard2', 'scan', [options]); - }); - }, - - /** - * Start wifi network scan (results can be retrieved with getScanResults) - * @returns {Promise} - */ - startScan: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "startScan", []); - }); - }, - - /** - * Get wifi scan results (must call startScan first, or just use scan()) - * @param options - * @returns {Promise} - */ - getScanResults: function (options) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getScanResults", [options]); - }); - }, - - /** - * Check if WiFi is enabled - * @returns {Promise} - */ - isWifiEnabled: function () { - return new Promise(function (resolve, reject) { - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - resolve(result == "1"); - }, - reject, "WifiWizard2", "isWifiEnabled", [] - ); - }); - }, - - /** - * Enable or Disable WiFi - * @param enabled - * @returns {Promise} - */ - setWifiEnabled: function (enabled) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "setWifiEnabled", [enabled]); - }); - }, - - /** - * Enable WiFi - * @returns {Promise} - */ - enableWifi: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "setWifiEnabled", [true]); - }); - }, - - /** - * Enable WiFi - * @returns {Promise} - */ - disableWifi: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "setWifiEnabled", [false]); - }); - }, - - /** - * Unbind Network - * @returns {Promise} - */ - resetBindAll: function () { - return new Promise( function( resolve, reject ){ - cordova.exec(resolve, reject, "WifiWizard2", "resetBindAll", []); - }); - }, - - /** - * Bind Network - * @returns {Promise} - */ - setBindAll: function () { - return new Promise( function( resolve, reject ){ - cordova.exec(resolve, reject, "WifiWizard2", "setBindAll", []); - }); - }, - - /** - * Get Wifi Router IP from DHCP - * @returns {Promise} - */ - getWifiRouterIP: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getWifiRouterIP", []); - }); - }, - /** - * Get Wifi IP - * @returns {Promise} - */ - getWifiIP: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getWifiIP", []); - }); - }, - /** - * Get Wifi IP and Subnet Address - * - * This method returns a JSON object similar to: { "ip": "0.0.0.0", "subnet": "0.0.0.0" } - * @returns {Promise} - */ - getWifiIPInfo: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getWifiIPInfo", []); - }); - }, - - /** - * Get Network ID from SSID - * @param {string|int} [SSID] - * @returns {Promise} - */ - getSSIDNetworkID: function (SSID) { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getSSIDNetworkID", [WifiWizard2.formatWifiString(SSID)]); - }); - }, - - /** - * Get currently connected network ID - * @returns {Promise} - */ - getConnectedNetworkID: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getConnectedNetworkID", []); - }); - }, - - /** - * Get currently connected network SSID - * @returns {Promise} - */ - getConnectedSSID: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getConnectedSSID", []); - }); - - }, - - /** - * Get currently connected network BSSID/MAC - * @returns {Promise} - */ - getConnectedBSSID: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "getConnectedBSSID", []); - }); - }, - /** - * Check if current WiFi connection has connection to the internet - * @returns {Promise} - */ - isConnectedToInternet: function () { - return new Promise(function (resolve, reject) { - - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - - if (result == "1") { - resolve("IS_CONNECTED_TO_INTERNET"); - } else { - reject("NOT_CONNECTED_TO_INTERNET"); - } - - }, - reject, "WifiWizard2", "isConnectedToInternet", [] - ); - - }); - }, - /** - * Check if we can ping current WiFi router IP address - * @returns {Promise} - */ - canPingWifiRouter: function () { - return new Promise(function (resolve, reject) { - - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - - if (result == "1") { - resolve("CAN_PING_ROUTER"); - } else { - reject("UNABLE_TO_PING_ROUTER"); - } - - }, - reject, "WifiWizard2", "canPingWifiRouter", [] - ); - - }); - }, - - /** - * Check if we can connect via HTTP current WiFi router IP address - * @returns {Promise} - */ - canConnectToRouter: function () { - return new Promise(function (resolve, reject) { - - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - - if (result == "1") { - resolve("CAN_CONNECT_TO_ROUTER"); - } else { - reject("UNABLE_TO_CONNECT_TO_ROUTER"); - } - - }, - reject, "WifiWizard2", "canConnectToRouter", [] - ); - - }); - }, - /** - * Check if current WiFi connection can connect to internet (checks connection to google.com) - * @returns {Promise} - */ - canConnectToInternet: function () { - return new Promise(function (resolve, reject) { - - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - - if (result == "1") { - resolve("IS_CONNECTED_TO_INTERNET"); - } else { - reject("NOT_CONNECTED_TO_INTERNET"); - } - - }, - reject, "WifiWizard2", "canConnectToInternet", [] - ); - - }); - }, - /** - * Check if Location is enabled on device - * @returns {Promise} - */ - isLocationEnabled: function () { - return new Promise(function (resolve, reject) { - - cordova.exec( - // Cordova can only return strings to JS, and the underlying plugin - // sends a "1" for true and "0" for false. - function (result) { - if (result == "1") { - resolve("LOCATION_IS_ENABLED"); - } else { - reject("LOCATION_NOT_ENABLED"); - } - - }, - reject, "WifiWizard2", "isLocationEnabled", [] - ); - - }); - }, - /** - * Switch to location settings - * @returns {Promise} - */ - switchToLocationSettings: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "switchToLocationSettings", []); - }); - }, - /** - * Request ACCESS_FINE_LOCATION permission - * - * This permission is required by Android to return scan results, you can manually request it prior to running `scan` - * or this plugin will automatically do it when the scan is ran. - * - * @returns {Promise} - */ - requestPermission: function () { - return new Promise(function (resolve, reject) { - cordova.exec(resolve, reject, "WifiWizard2", "requestFineLocation", []); - }); - }, - - /** - * Format WiFi configuration for Android Devices - * @param {string|int} [SSID] - * @param {string} [password] - * @param {string} [algorithm] - * @param {boolean} [isHiddenSSID] - * @returns {*} - */ - formatWifiConfig: function (SSID, password, algorithm, isHiddenSSID) { - var wifiConfig = { - SSID: WifiWizard2.formatWifiString(SSID), - isHiddenSSID: !!isHiddenSSID - }; - if (!algorithm && !password) { - // open network - wifiConfig.auth = { - algorithm: "NONE" - }; - } else if (algorithm === "WPA") { - wifiConfig.auth = { - algorithm: algorithm, - password: WifiWizard2.formatWifiString(password) - // Other parameters can be added depending on algorithm. - }; - } - else if (algorithm === 'WEP') { - wifiConfig.auth = { - algorithm: algorithm, - password: password - // Other parameters can be added depending on algorithm. - }; - } - else if (algorithm === "New network type") { - wifiConfig.auth = { - algorithm: algorithm - // Etc... - }; - } - else { - console.log("Algorithm incorrect"); - return false; - } - return wifiConfig; - }, - - /** - * Format WPA WiFi configuration for Android Devices - * @param {string|int} [SSID] - * @param {string} password - * @param {boolean} isHiddenSSID - * @returns {*} - */ - formatWPAConfig: function (SSID, password, isHiddenSSID) { - return WifiWizard2.formatWifiConfig(SSID, password, "WPA", isHiddenSSID); - }, - - /** - * Format WiFi SSID String - * @param ssid - * @returns {*} - */ - formatWifiString: function (ssid) { - - if (ssid === parseInt(ssid, 10)) { - return ssid; - } - - if (ssid === undefined || ssid === null || ssid === false) { - ssid = ""; - } - ssid = ssid.trim(); - - if (ssid.charAt(0) != '"') { - ssid = '"' + ssid; - } - - if (ssid.charAt(ssid.length - 1) != '"') { - ssid = ssid + '"'; - } - - return ssid; - }, - - /** - * Synchronous Sleep/Timeout `await this.timeout()` - */ - timeout: function (delay) { - - if (!delay) { - delay = 2000; // 2s timeout by default - } - - return new Promise(function (resolve, reject) { - setTimeout(resolve, delay); - }); - } -}; - -module.exports = WifiWizard2; + + var WifiWizard2 = { + /** + * Connect to network on iOS device + * @param ssid + * @param ssidPassword Password if connecting to WPA/WPA2 network (omit or use false to connect to open network) + * @returns {Promise} + */ + iOSConnectNetwork: function (ssid, ssidPassword) { + return new Promise(function (resolve, reject) { + if (ssidPassword === undefined || !ssidPassword || ssidPassword.length < 1) { + // iOS connect open network + cordova.exec(resolve, reject, 'WifiWizard2', 'iOSConnectOpenNetwork', [{ Ssid: ssid }]); + } else if (ssidPassword !== undefined && ssidPassword.length > 0 && ssidPassword.length < 8) { + // iOS pass length does not meet requirements (min 8 chars for WPA/WPA2) + reject('WPA/WPA2 password length must be at least 8 characters in length!'); + } else { + // iOS connect to WPA/WPA2 network + cordova.exec(resolve, reject, 'WifiWizard2', 'iOSConnectNetwork', [ + { + Ssid: ssid, + Password: ssidPassword, + }, + ]); + } + }); + }, + + /** + * Disconnect from SSID on iOS device + * @param ssid + * @returns {Promise} + */ + iOSDisconnectNetwork: function (ssid) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'iOSDisconnectNetwork', [ + { + Ssid: ssid, + }, + ]); + }); + }, + + /** + * Add wifi network configuration + * @param wifi Must be object created by formatWifiConfig() + * @returns {Promise} + */ + add: function (wifi) { + return new Promise(function (resolve, reject) { + if (wifi !== null && typeof wifi === 'object') { + // Ok to proceed! + + var networkInformation = []; + + if (wifi.SSID !== undefined && wifi.SSID !== '') { + networkInformation.push(wifi.SSID); + } else { + reject('No SSID given.'); + return false; + } + + if (typeof wifi.auth == 'object') { + switch (wifi.auth.algorithm) { + case 'WPA': + networkInformation.push('WPA'); + networkInformation.push(wifi.auth.password); + break; + case 'WEP': + networkInformation.push('WEP'); + networkInformation.push(wifi.auth.password); + break; + case 'NONE': + networkInformation.push('NONE'); + // Adding twice for data structure consistency + networkInformation.push('NONE'); + break; + case 'Newly supported type': + break; + default: + console.log('WifiWizard2: authentication invalid.'); + } + } else { + reject('WifiWizard2: No authentication algorithm given.'); + return false; + } + + networkInformation.push(!!wifi.isHiddenSSID); + cordova.exec(resolve, reject, 'WifiWizard2', 'add', networkInformation); + } else { + reject('Invalid parameter. Wifi not an object.'); + return false; + } + }); + }, + + /** + * Remove wifi network configuration + * @param {string|int} [SSID] + * @returns {Promise} + */ + remove: function (SSID) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'remove', [WifiWizard2.formatWifiString(SSID)]); + }); + }, + + /** + * Connect network with specified SSID + * + * This method will first add the wifi configuration, then enable the network, returning promise when connection is verified. + * + * @param {string|int} [SSID] + * @param {boolean} [bindAll=false] Whether or not to bind all connections from app, through WiFi connection + * @param {string} [password=] + * @param {string} [algorithm=NONE] WPA, WPA (for WPA2), WEP or NONE (NONE by default) + * @returns {Promise} + */ + connect: function (SSID, bindAll, password, algorithm, isHiddenSSID) { + return new Promise(function (resolve, reject) { + if (!SSID) { + reject('SSID is missing!'); + return; + } + + var wifiConfig = WifiWizard2.formatWifiConfig(SSID, password, algorithm, isHiddenSSID); + bindAll = bindAll ? true : false; + + if (!wifiConfig) { + reject('Algorithm incorrect'); + return; + } + + WifiWizard2.add(wifiConfig) + .then(function (newNetID) { + // Successfully updated or added wifiConfig + cordova.exec(resolve, reject, 'WifiWizard2', 'connect', [WifiWizard2.formatWifiString(SSID), bindAll]); + + // Catch error adding/updating network + }) + .catch(function (error) { + // This means the connection could have been setup by mobile phone user, or another app (separate from ours) + // Newer version of Android will NOT allow you to update, remove, any wifi networks setup by user or other apps (regardless of perms set) + if (error === 'ERROR_UPDATING_NETWORK') { + // This error above should only be returned when the add method was able to pull a network ID (as it tries to update instead of adding) + // Lets go ahead and attempt to connect to that SSID (using the existing wifi configuration) + cordova.exec(resolve, reject, 'WifiWizard2', 'connect', [WifiWizard2.formatWifiString(SSID), bindAll]); + } else { + reject(error); + } + }); // Close ADD + }); + }, + + /** + * Disconnect (current if SSID not supplied) + * + * This method, if passed an SSID, will first disable the network, and then remove it from the device. To only "disconnect" (ie disable in android), + * call WifiWizard2.disable() instead of disconnect. + * + * @param {string|int} [SSID=all] + * @returns {Promise} + */ + disconnect: function (SSID) { + return new Promise(function (resolve, reject) { + if (SSID) { + cordova.exec(resolve, reject, 'WifiWizard2', 'disconnectNetwork', [WifiWizard2.formatWifiString(SSID)]); + } else { + cordova.exec(resolve, reject, 'WifiWizard2', 'disconnect', []); + } + }); + }, + + /** + * Enable Network + * @param {string|int} [SSID] + * @param {boolean} [bindAll=false] Whether or not to bind all network requests to this wifi network + * @param {boolean} [waitForConnection=false] Whether or not to wait before resolving promise until connection to wifi is verified + * @returns {Promise} + */ + enable: function (SSID, bindAll, waitForConnection) { + return new Promise(function (resolve, reject) { + bindAll = bindAll ? true : false; + waitForConnection = waitForConnection ? true : false; + cordova.exec(resolve, reject, 'WifiWizard2', 'enable', [WifiWizard2.formatWifiString(SSID), bindAll, waitForConnection]); + }); + }, + + /** + * Disable Network + * @param {string|int} [SSID] + * @returns {Promise} + */ + disable: function (SSID) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'disable', [WifiWizard2.formatWifiString(SSID)]); + }); + }, + + /** + * Reconnect to the currently active access point, even if we are already connected. + * @returns {Promise} + */ + reassociate: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'reassociate', []); + }); + }, + + /** + * Reconnect to the currently active access point, if we are currently disconnected. + * @returns {Promise} + */ + reconnect: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'reconnect', []); + }); + }, + + /** + * Returns currently configured networks + * @returns {Promise} + */ + listNetworks: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'listNetworks', []); + }); + }, + + /** + * Start network scan and return results + * @param options + * @returns {Promise} + */ + scan: function (options) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'scan', [options]); + }); + }, + + /** + * Start wifi network scan (results can be retrieved with getScanResults) + * @returns {Promise} + */ + startScan: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'startScan', []); + }); + }, + + /** + * Get wifi scan results (must call startScan first, or just use scan()) + * @param options + * @returns {Promise} + */ + getScanResults: function (options) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getScanResults', [options]); + }); + }, + + /** + * Check if WiFi is enabled + * @returns {Promise} + */ + isWifiEnabled: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + resolve(result == '1'); + }, + reject, + 'WifiWizard2', + 'isWifiEnabled', + [] + ); + }); + }, + + /** + * Enable or Disable WiFi + * @param enabled + * @returns {Promise} + */ + setWifiEnabled: function (enabled) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'setWifiEnabled', [enabled]); + }); + }, + + /** + * Enable WiFi + * @returns {Promise} + */ + enableWifi: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'setWifiEnabled', [true]); + }); + }, + + /** + * Enable WiFi + * @returns {Promise} + */ + disableWifi: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'setWifiEnabled', [false]); + }); + }, + + /** + * Unbind Network + * @returns {Promise} + */ + resetBindAll: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'resetBindAll', []); + }); + }, + + /** + * Bind Network + * @returns {Promise} + */ + setBindAll: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'setBindAll', []); + }); + }, + + /** + * Get Wifi Router IP from DHCP + * @returns {Promise} + */ + getWifiRouterIP: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getWifiRouterIP', []); + }); + }, + /** + * Get Wifi IP + * @returns {Promise} + */ + getWifiIP: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getWifiIP', []); + }); + }, + /** + * Get Wifi IP and Subnet Address + * + * This method returns a JSON object similar to: { "ip": "0.0.0.0", "subnet": "0.0.0.0" } + * @returns {Promise} + */ + getWifiIPInfo: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getWifiIPInfo', []); + }); + }, + + /** + * Get Network ID from SSID + * @param {string|int} [SSID] + * @returns {Promise} + */ + getSSIDNetworkID: function (SSID) { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getSSIDNetworkID', [WifiWizard2.formatWifiString(SSID)]); + }); + }, + + /** + * Get currently connected network ID + * @returns {Promise} + */ + getConnectedNetworkID: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getConnectedNetworkID', []); + }); + }, + + /** + * Get currently connected network SSID + * @returns {Promise} + */ + getConnectedSSID: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getConnectedSSID', []); + }); + }, + + /** + * Get currently connected network BSSID/MAC + * @returns {Promise} + */ + getConnectedBSSID: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'getConnectedBSSID', []); + }); + }, + /** + * Check if current WiFi connection has connection to the internet + * @returns {Promise} + */ + isConnectedToInternet: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + if (result == '1') { + resolve('IS_CONNECTED_TO_INTERNET'); + } else { + reject('NOT_CONNECTED_TO_INTERNET'); + } + }, + reject, + 'WifiWizard2', + 'isConnectedToInternet', + [] + ); + }); + }, + /** + * Check if we can ping current WiFi router IP address + * @returns {Promise} + */ + canPingWifiRouter: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + if (result == '1') { + resolve('CAN_PING_ROUTER'); + } else { + reject('UNABLE_TO_PING_ROUTER'); + } + }, + reject, + 'WifiWizard2', + 'canPingWifiRouter', + [] + ); + }); + }, + + /** + * Check if we can connect via HTTP current WiFi router IP address + * @returns {Promise} + */ + canConnectToRouter: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + if (result == '1') { + resolve('CAN_CONNECT_TO_ROUTER'); + } else { + reject('UNABLE_TO_CONNECT_TO_ROUTER'); + } + }, + reject, + 'WifiWizard2', + 'canConnectToRouter', + [] + ); + }); + }, + /** + * Check if current WiFi connection can connect to internet (checks connection to google.com) + * @returns {Promise} + */ + canConnectToInternet: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + if (result == '1') { + resolve('IS_CONNECTED_TO_INTERNET'); + } else { + reject('NOT_CONNECTED_TO_INTERNET'); + } + }, + reject, + 'WifiWizard2', + 'canConnectToInternet', + [] + ); + }); + }, + /** + * Check if Location is enabled on device + * @returns {Promise} + */ + isLocationEnabled: function () { + return new Promise(function (resolve, reject) { + cordova.exec( + // Cordova can only return strings to JS, and the underlying plugin + // sends a "1" for true and "0" for false. + function (result) { + if (result == '1') { + resolve('LOCATION_IS_ENABLED'); + } else { + reject('LOCATION_NOT_ENABLED'); + } + }, + reject, + 'WifiWizard2', + 'isLocationEnabled', + [] + ); + }); + }, + /** + * Switch to location settings + * @returns {Promise} + */ + switchToLocationSettings: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'switchToLocationSettings', []); + }); + }, + /** + * Request ACCESS_FINE_LOCATION permission + * + * This permission is required by Android to return scan results, you can manually request it prior to running `scan` + * or this plugin will automatically do it when the scan is ran. + * + * @returns {Promise} + */ + requestPermission: function () { + return new Promise(function (resolve, reject) { + cordova.exec(resolve, reject, 'WifiWizard2', 'requestFineLocation', []); + }); + }, + + /** + * Format WiFi configuration for Android Devices + * @param {string|int} [SSID] + * @param {string} [password] + * @param {string} [algorithm] + * @param {boolean} [isHiddenSSID] + * @returns {*} + */ + formatWifiConfig: function (SSID, password, algorithm, isHiddenSSID) { + let wifiConfig = { + SSID: WifiWizard2.formatWifiString(SSID), + isHiddenSSID: !!isHiddenSSID, + }; + + if (!SSID) return false; + + switch (algorithm) { + case 'WEP': + wifiConfig.auth = { + algorithm: algorithm, + password: password, + // Other parameters can be added depending on algorithm. + }; + break; + + case 'WPA': + case 'WPA2': + case 'WPA3': + wifiConfig.auth = { + algorithm: algorithm, + password: WifiWizard2.formatWifiString(password), + }; + break; + + break; + default: + wifiConfig.auth = { + algorithm: 'NONE', + }; + break; + } + + return wifiConfig; + }, + + /** + * Format WPA WiFi configuration for Android Devices + * @param {string|int} [SSID] + * @param {string} password + * @param {boolean} isHiddenSSID + * @returns {*} + */ + formatWPAConfig: function (SSID, password, isHiddenSSID) { + return WifiWizard2.formatWifiConfig(SSID, password, 'WPA', isHiddenSSID); + }, + + /** + * Format WiFi SSID String + * @param ssid + * @returns {*} + */ + formatWifiString: function (ssid) { + if (ssid === parseInt(ssid, 10)) { + return ssid; + } + + if (ssid === undefined || ssid === null || ssid === false) { + ssid = ''; + } + ssid = ssid.trim(); + + if (ssid.charAt(0) != '"') { + ssid = '"' + ssid; + } + + if (ssid.charAt(ssid.length - 1) != '"') { + ssid = ssid + '"'; + } + + return ssid; + }, + + /** + * Synchronous Sleep/Timeout `await this.timeout()` + */ + timeout: function (delay) { + if (!delay) { + delay = 2000; // 2s timeout by default + } + + return new Promise(function (resolve, reject) { + setTimeout(resolve, delay); + }); + }, + + /** + * Specifier for connect to network with specified SSID and Password + * Author: Anthony Sychev (hello at dm211 dot com) + * + * @param {string|int} [SSID] + * @param {string} [password=] + * @param {string} [alhorithm=WPA] + * @param {booleab} [isHiddenSSID] + * @returns {Promise} + */ + specifierConnection: function (SSID, password, alhorithm, isHiddenSSID) { + isHiddenSSID = isHiddenSSID ? true : false; + alhorithm = alhorithm ? alhorithm : 'WPA'; + + return new Promise(function (resolve, reject) { + if (!SSID) { + reject('SSID is missing!'); + return; + } + + var wifiConfig = WifiWizard2.formatWifiConfig(SSID, password, alhorithm, isHiddenSSID); + + if (!wifiConfig) { + reject('Algorithm incorrect'); + return; + } + + cordova.exec(resolve, reject, 'WifiWizard2', 'specifierConnection', [SSID, password, wifiConfig.auth.algorithm, wifiConfig.isHiddenSSID]); + }); + }, + }; + + module.exports = WifiWizard2; +}); From a40b429b014bbdda4fd42907dd0a3508342f62e6 Mon Sep 17 00:00:00 2001 From: Anthony Sychev Date: Tue, 2 Mar 2021 09:49:54 +0100 Subject: [PATCH 2/3] bugfix: as default network is set as NONE for OPEN WiFi Connection --- src/android/wifiwizard2/WifiWizard2.java | 8 +++++--- www/WifiWizard2.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/android/wifiwizard2/WifiWizard2.java b/src/android/wifiwizard2/WifiWizard2.java index 9aaaa86..2e7c330 100644 --- a/src/android/wifiwizard2/WifiWizard2.java +++ b/src/android/wifiwizard2/WifiWizard2.java @@ -1971,6 +1971,8 @@ private static class AP { * Specifier one network to connect wifi providing ssid and password * Author: Anthony Sychev (hello at dm211 dot com) * + * If you not provide pass or algorithm is not set as WPE|WPA|WPA2|WPA3 is represent as default Open network + * * DOC: https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder */ private void specifierConnection(CallbackContext callbackContext, JSONArray data) { @@ -1997,13 +1999,13 @@ private void specifierConnection(CallbackContext callbackContext, JSONArray data WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder(); builder.setSsid(SSID); - - if(Algorithm.matches("/WEP|WPA|WPA2/gim")) + + if(Algorithm.matches("/WEP|WPA|WPA2/gim") && PASS != '') { builder.setWpa2Passphrase(PASS); } - if(Algorithm.matches("/WPA3/gim")) + if(Algorithm.matches("/WPA3/gim") && PASS != '') { builder.setWpa3Passphrase(PASS); } diff --git a/www/WifiWizard2.js b/www/WifiWizard2.js index 023324b..18e1e90 100644 --- a/www/WifiWizard2.js +++ b/www/WifiWizard2.js @@ -655,13 +655,13 @@ cordova.define('wifiwizard2.WifiWizard2', function (require, exports, module) { * * @param {string|int} [SSID] * @param {string} [password=] - * @param {string} [alhorithm=WPA] + * @param {string} [alhorithm=OPEN] OPEN|WEP|WPA|WPA2|WPA3 * @param {booleab} [isHiddenSSID] * @returns {Promise} */ specifierConnection: function (SSID, password, alhorithm, isHiddenSSID) { isHiddenSSID = isHiddenSSID ? true : false; - alhorithm = alhorithm ? alhorithm : 'WPA'; + alhorithm = alhorithm ? alhorithm : 'NONE'; return new Promise(function (resolve, reject) { if (!SSID) { From fbd164175ef810f2893fb243329264e91ac54236 Mon Sep 17 00:00:00 2001 From: Anthony <2700881+klich3@users.noreply.github.com> Date: Wed, 24 Mar 2021 13:40:23 +0100 Subject: [PATCH 3/3] Update src/android/wifiwizard2/WifiWizard2.java Correction aported by DarAng3L Co-authored-by: Mihai --- src/android/wifiwizard2/WifiWizard2.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/wifiwizard2/WifiWizard2.java b/src/android/wifiwizard2/WifiWizard2.java index 2e7c330..21f507d 100644 --- a/src/android/wifiwizard2/WifiWizard2.java +++ b/src/android/wifiwizard2/WifiWizard2.java @@ -2000,7 +2000,7 @@ private void specifierConnection(CallbackContext callbackContext, JSONArray data WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder(); builder.setSsid(SSID); - if(Algorithm.matches("/WEP|WPA|WPA2/gim") && PASS != '') + if(Algorithm.matches("/WEP|WPA|WPA2/gim") && PASS.length() > 0) { builder.setWpa2Passphrase(PASS); }