diff --git a/README.md b/README.md index de269d2e..8f44568a 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ Becareful, some commands as no effect on iOS because Apple don't let us to do wh ## WiFi connections | Description | Android | iOS | | :---------------------------------------------------- | :----------------: | :------------------: | -| Enabling / Disabling WiFi module | :white_check_mark: | :x: | +| Enabling / Disabling WiFi module | :warning:(5) | :x: | | Getting WiFi status | :white_check_mark: | :x: | | Scanning for networks, with "already-associated" flag | :white_check_mark: | :x: | -| Connecting / Disconnecting on a network in WPA / WEP | :white_check_mark: | :white_check_mark:(1) | -| Registering / Unregistering a WiFi network | :white_check_mark: | :warning:(2) | +| Connecting / Disconnecting on a network in WPA / WEP | :white_check_mark:(6) | :white_check_mark:(1) | +| Registering / Unregistering a WiFi network | :warning:(7) | :warning:(2) | | Getting informations like : | :white_check_mark: | :warning:(3) | | - SSID | :white_check_mark: | :white_check_mark: | | - BSSID | :white_check_mark: | :x: | @@ -31,6 +31,12 @@ Becareful, some commands as no effect on iOS because Apple don't let us to do wh :question:(4) : I think there is a way to get the IP address but for now, this is not implemented.. +:warning:(5): On Android SDK >= 29, this is deprecated and will always fail (except DO, PO and system apps). [[docs](https://developer.android.com/reference/android/net/wifi/WifiManager#setWifiEnabled(boolean))] + +:white_check_mark:(6): On Android SDK >= 29, WEP security is deprecated and will always fail, also the network will be disconnected when the app is closed. [[docs](https://developer.android.com/reference/android/net/ConnectivityManager?hl=en#requestNetwork(android.net.NetworkRequest,%20android.net.ConnectivityManager.NetworkCallback))]. If permanent network is required(Check :warning:(7)), there is a way but that network will not be controlled by the app, it will be as if user is adding the network manually, not supported as of now, open issue if you want this feature. + +:warning:(7) On Android SDK >=29, this is deprecated. Although there could be ways for user to be sent to Settings App for registering only(pre-filled) but not supported as of now. + ## Access Point | Description | Android | iOS | | :------------------------------------------------------------------------------------ | :----------------: | :------------------: | diff --git a/android/build.gradle b/android/build.gradle index 37ff19d6..818a711b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:4.1.0' } } @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 28 + compileSdkVersion 30 defaultConfig { minSdkVersion 16 diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index ebcf6f19..03b3fb2a 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -6,5 +6,5 @@ - + diff --git a/android/src/main/java/com/alternadom/wifiiot/WifiIotPlugin.java b/android/src/main/java/com/alternadom/wifiiot/WifiIotPlugin.java index 0ae97014..ffe8adc8 100644 --- a/android/src/main/java/com/alternadom/wifiiot/WifiIotPlugin.java +++ b/android/src/main/java/com/alternadom/wifiiot/WifiIotPlugin.java @@ -7,36 +7,32 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.os.Handler; -import android.os.Looper; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.net.wifi.WifiNetworkSpecifier; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.DatagramSocket; -import java.net.Socket; import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; import info.whitebyte.hotspotmanager.ClientScanResult; import info.whitebyte.hotspotmanager.FinishScanListener; import info.whitebyte.hotspotmanager.WifiApManager; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -49,55 +45,122 @@ /** * WifiIotPlugin */ -public class WifiIotPlugin implements MethodCallHandler, EventChannel.StreamHandler { +public class WifiIotPlugin implements FlutterPlugin, ActivityAware, MethodCallHandler, EventChannel.StreamHandler { + /// This local reference serves to register the plugin with the Flutter Engine and unregister it + /// when the Flutter Engine is detached from the Activity + private MethodChannel channel; + private EventChannel eventChannel; + private WifiManager moWiFi; private Context moContext; private WifiApManager moWiFiAPManager; private Activity moActivity; private BroadcastReceiver receiver; + private ConnectivityManager.NetworkCallback networkCallback; private List ssidsToBeRemovedOnExit = new ArrayList(); - private WifiIotPlugin(Activity poActivity) { - this.moActivity = poActivity; - this.moContext = poActivity.getApplicationContext(); - this.moWiFi = (WifiManager) moContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); - this.moWiFiAPManager = new WifiApManager(moContext.getApplicationContext()); + // initialize members of this class with Context + private void initWithContext(Context context) { + moContext = context; + moWiFi = (WifiManager) moContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + moWiFiAPManager = new WifiApManager(moContext.getApplicationContext()); + } + + // initialize members of this class with Activity + private void initWithActivity(Activity activity) { + moActivity = activity; + } + + // cleanup + private void cleanup() { + if (!ssidsToBeRemovedOnExit.isEmpty()) { + List wifiConfigList = + moWiFi.getConfiguredNetworks(); + for (String ssid : ssidsToBeRemovedOnExit) { + for (android.net.wifi.WifiConfiguration wifiConfig : wifiConfigList) { + if (wifiConfig.SSID.equals(ssid)) { + moWiFi.removeNetwork(wifiConfig.networkId); + } + } + } + } + // setting all members to null to avoid memory leaks + channel = null; + eventChannel = null; + moActivity = null; + moContext = null; + moWiFi = null; + moWiFiAPManager = null; } + /** - * Plugin registration. + * Plugin registration. This is used for registering with v1 Android embedding. */ public static void registerWith(Registrar registrar) { - if (registrar.activity() == null) { - // When a background flutter view tries to register the plugin, the registrar has no activity. - // We stop the registration process as this plugin is foreground only. - return; - } final MethodChannel channel = new MethodChannel(registrar.messenger(), "wifi_iot"); final EventChannel eventChannel = new EventChannel(registrar.messenger(), "plugins.wififlutter.io/wifi_scan"); - final WifiIotPlugin wifiIotPlugin = new WifiIotPlugin(registrar.activity()); + final WifiIotPlugin wifiIotPlugin = new WifiIotPlugin(); + wifiIotPlugin.initWithActivity(registrar.activity()); + wifiIotPlugin.initWithContext(registrar.activeContext()); eventChannel.setStreamHandler(wifiIotPlugin); channel.setMethodCallHandler(wifiIotPlugin); registrar.addViewDestroyListener(new ViewDestroyListener() { @Override public boolean onViewDestroy(FlutterNativeView view) { - if (!wifiIotPlugin.ssidsToBeRemovedOnExit.isEmpty()) { - List wifiConfigList = - wifiIotPlugin.moWiFi.getConfiguredNetworks(); - for (String ssid : wifiIotPlugin.ssidsToBeRemovedOnExit) { - for (WifiConfiguration wifiConfig : wifiConfigList) { - if (wifiConfig.SSID.equals(ssid)) { - wifiIotPlugin.moWiFi.removeNetwork(wifiConfig.networkId); - } - } - } - } + wifiIotPlugin.cleanup(); return false; } }); } + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + // initialize method and event channel and set handlers + channel = new MethodChannel(binding.getBinaryMessenger(), "wifi_iot"); + eventChannel = new EventChannel(binding.getBinaryMessenger(), "plugins.wififlutter.io/wifi_scan"); + channel.setMethodCallHandler(this); + eventChannel.setStreamHandler(this); + + // initializeWithContext + initWithContext(binding.getApplicationContext()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + // set null as channel handlers + channel.setMethodCallHandler(null); + eventChannel.setStreamHandler(null); + + // set member to null + cleanup(); + } + + @Override + public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { + // init with activity + initWithActivity(binding.getActivity()); + } + + @Override + public void onDetachedFromActivityForConfigChanges() { + // set activity to null + moActivity = null; + } + + @Override + public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { + // init with activity + initWithActivity(binding.getActivity()); + } + + @Override + public void onDetachedFromActivity() { + // set activity to null + moActivity = null; + } + @Override public void onMethodCall(MethodCall poCall, Result poResult) { switch (poCall.method) { @@ -141,10 +204,16 @@ public void onMethodCall(MethodCall poCall, Result poResult) { getIP(poResult); break; case "removeWifiNetwork": - removeWifiNetwork(poCall, poResult); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) + removeWifiNetwork(poCall, poResult); + else + poResult.error("Error", "removeWifiNetwork not supported for Android SDK " + Build.VERSION.SDK_INT, null); break; case "isRegisteredWifiNetwork": - isRegisteredWifiNetwork(poCall, poResult); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) + isRegisteredWifiNetwork(poCall, poResult); + else + poResult.error("Error", "isRegisteredWifiNetwork not supported for Android SDK " + Build.VERSION.SDK_INT, null); break; case "isWiFiAPEnabled": isWiFiAPEnabled(poResult); @@ -186,7 +255,6 @@ public void onMethodCall(MethodCall poCall, Result poResult) { } /** - * * @param poCall * @param poResult */ @@ -207,7 +275,7 @@ private void setMACFiltering(MethodCall poCall, Result poResult) { * (e.g., {@code 01a243f405}). */ private void getWiFiAPSSID(Result poResult) { - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); if (oWiFiConfig != null && oWiFiConfig.SSID != null) { poResult.success(oWiFiConfig.SSID); return; @@ -218,7 +286,7 @@ private void getWiFiAPSSID(Result poResult) { private void setWiFiAPSSID(MethodCall poCall, Result poResult) { String sAPSSID = poCall.argument("ssid"); - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); oWiFiConfig.SSID = sAPSSID; @@ -232,7 +300,7 @@ private void setWiFiAPSSID(MethodCall poCall, Result poResult) { * SSID-specific probe request must be used for scans. */ private void isSSIDHidden(Result poResult) { - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); if (oWiFiConfig != null && oWiFiConfig.hiddenSSID) { poResult.success(oWiFiConfig.hiddenSSID); return; @@ -243,7 +311,7 @@ private void isSSIDHidden(Result poResult) { private void setSSIDHidden(MethodCall poCall, Result poResult) { boolean isSSIDHidden = poCall.argument("hidden"); - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); oWiFiConfig.hiddenSSID = isSSIDHidden; @@ -262,7 +330,7 @@ private void setSSIDHidden(MethodCall poCall, Result poResult) { * string otherwise. */ private void getWiFiAPPreSharedKey(Result poResult) { - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); if (oWiFiConfig != null && oWiFiConfig.preSharedKey != null) { poResult.success(oWiFiConfig.preSharedKey); return; @@ -273,7 +341,7 @@ private void getWiFiAPPreSharedKey(Result poResult) { private void setWiFiAPPreSharedKey(MethodCall poCall, Result poResult) { String sPreSharedKey = poCall.argument("preSharedKey"); - WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); + android.net.wifi.WifiConfiguration oWiFiConfig = moWiFiAPManager.getWifiApConfiguration(); oWiFiConfig.preSharedKey = sPreSharedKey; @@ -312,8 +380,8 @@ public void onFinishScan(final ArrayList clients) { Boolean clientIsReachable = client.isReachable(); Boolean shouldReturnCurrentClient = true; - if ( finalOnlyReachables.booleanValue()) { - if (!clientIsReachable.booleanValue()){ + if (finalOnlyReachables.booleanValue()) { + if (!clientIsReachable.booleanValue()) { shouldReturnCurrentClient = Boolean.valueOf(false); } } @@ -379,9 +447,9 @@ private void getWiFiAPState(Result poResult) { @Override public void onListen(Object o, EventChannel.EventSink eventSink) { - int PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION = 65655434; - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ - moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION); + int PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION = 65655434; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION); } receiver = createReceiver(eventSink); @@ -390,14 +458,14 @@ public void onListen(Object o, EventChannel.EventSink eventSink) { @Override public void onCancel(Object o) { - if(receiver != null){ + if (receiver != null) { moContext.unregisterReceiver(receiver); receiver = null; } } - private BroadcastReceiver createReceiver(final EventChannel.EventSink eventSink){ + private BroadcastReceiver createReceiver(final EventChannel.EventSink eventSink) { return new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -405,7 +473,8 @@ public void onReceive(Context context, Intent intent) { } }; } - JSONArray handleNetworkScanResult(){ + + JSONArray handleNetworkScanResult() { List results = moWiFi.getScanResults(); JSONArray wifiArray = new JSONArray(); @@ -445,12 +514,13 @@ JSONArray handleNetworkScanResult(){ private void loadWifiList(final Result poResult) { try { - int PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION = 65655434; - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ - moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION); + int PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION = 65655434; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION); } - moWiFi.startScan(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) + moWiFi.startScan(); poResult.success(handleNetworkScanResult().toString()); @@ -499,7 +569,7 @@ public void onAvailable(Network network) { final Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override - public void run () { + public void run() { poResult.success(result); } }); @@ -540,15 +610,8 @@ public void run() { String security = poCall.argument("security"); Boolean joinOnce = poCall.argument("join_once"); - final boolean connected = connectTo(ssid, password, security, joinOnce); - - final Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run () { - poResult.success(connected); - } - }); + connectTo(poResult, ssid, password, security, joinOnce); + } }.start(); } @@ -558,9 +621,9 @@ public void run () { /// After 10 seconds, a post telling you whether you are connected will pop up. /// Callback returns true if ssid is in the range private void findAndConnect(final MethodCall poCall, final Result poResult) { - int PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION = 65655434; - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ - moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION); + int PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION = 65655434; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && moContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION); } new Thread() { public void run() { @@ -577,15 +640,7 @@ public void run() { } } - final boolean connected = connectTo(ssid, password, security, joinOnce); - - final Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run () { - poResult.success(connected); - } - }); + connectTo(poResult, ssid, password, security, joinOnce); } }.start(); } @@ -606,18 +661,56 @@ private static String getSecurityType(ScanResult scanResult) { /// Use this method to check if the device is currently connected to Wifi. private void isConnected(Result poResult) { - ConnectivityManager connManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo mWifi = connManager != null ? connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) : null; - if (mWifi != null && mWifi.isConnected()) { - poResult.success(true); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + isConnectedDeprecated(poResult); } else { - poResult.success(false); + int PERMISSIONS_REQUEST_CODE_ACCESS_NETWORK_STATE = 656889657; + if (moContext.checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) { + moActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_NETWORK_STATE}, PERMISSIONS_REQUEST_CODE_ACCESS_NETWORK_STATE); + } + + ConnectivityManager connManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE); + boolean result = false; + if (connManager != null) { + // `connManager.getActiveNetwork` only return if the network has internet + // therefore using `connManager.getAllNetworks()` to check all networks + for (final Network network : connManager.getAllNetworks()) { + final NetworkCapabilities capabilities = network != null + ? connManager.getNetworkCapabilities(network) + : null; + final boolean isConnected = capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); + if (isConnected) { + result = true; + break; + } + } + } + + poResult.success(result); } } + @SuppressWarnings("deprecation") + private void isConnectedDeprecated(Result poResult) { + ConnectivityManager connManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE); + android.net.NetworkInfo mWifi = connManager != null + ? connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) + : null; + + poResult.success(mWifi != null && mWifi.isConnected()); + } + /// Disconnect current Wifi. private void disconnect(Result poResult) { - moWiFi.disconnect(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + //noinspection deprecation + moWiFi.disconnect(); + } else { + if (networkCallback != null) { + final ConnectivityManager connectivityManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE); + connectivityManager.unregisterNetworkCallback(networkCallback); + } + } poResult.success(null); } @@ -677,8 +770,8 @@ private void removeWifiNetwork(MethodCall poCall, Result poResult) { poResult.error("Error", "No prefix SSID was given!", null); } - List mWifiConfigList = moWiFi.getConfiguredNetworks(); - for (WifiConfiguration wifiConfig : mWifiConfigList) { + List mWifiConfigList = moWiFi.getConfiguredNetworks(); + for (android.net.wifi.WifiConfiguration wifiConfig : mWifiConfigList) { String comparableSSID = ('"' + prefix_ssid); //Add quotes because wifiConfig.SSID has them if (wifiConfig.SSID.startsWith(comparableSSID)) { moWiFi.removeNetwork(wifiConfig.networkId); @@ -695,10 +788,10 @@ private void isRegisteredWifiNetwork(MethodCall poCall, Result poResult) { String ssid = poCall.argument("ssid"); - List mWifiConfigList = moWiFi.getConfiguredNetworks(); + List mWifiConfigList = moWiFi.getConfiguredNetworks(); String comparableSSID = ('"' + ssid + '"'); //Add quotes because wifiConfig.SSID has them if (mWifiConfigList != null) { - for (WifiConfiguration wifiConfig : mWifiConfigList) { + for (android.net.wifi.WifiConfiguration wifiConfig : mWifiConfigList) { if (wifiConfig.SSID.equals(comparableSSID)) { poResult.success(true); return; @@ -726,9 +819,66 @@ private static String longToIP(int longIp) { } /// Method to connect to WIFI Network - private Boolean connectTo(String ssid, String password, String security, Boolean joinOnce) { + private void connectTo(final Result poResult, final String ssid, final String password, final String security, final Boolean joinOnce) { + final Handler handler = new Handler(Looper.getMainLooper()); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + final boolean connected = connectToDeprecated(ssid, password, security, joinOnce); + handler.post(new Runnable() { + @Override + public void run() { + poResult.success(connected); + } + }); + } else { + // Make new network specifier + final WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder(); + // set ssid + builder.setSsid(ssid); + // set security + if (security != null && security.toUpperCase().equals("WPA")) { + builder.setWpa2Passphrase(password); + } else if (security != null && security.toUpperCase().equals("WEP")) { + // WEP is not supported + poResult.error("Error", "WEP is not supported for Android SDK " + Build.VERSION.SDK_INT, ""); + } + + final NetworkRequest networkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .setNetworkSpecifier(builder.build()) + .build(); + + final ConnectivityManager connectivityManager = (ConnectivityManager) moContext.getSystemService(Context.CONNECTIVITY_SERVICE); + + + if (networkCallback != null) + connectivityManager.unregisterNetworkCallback(networkCallback); + + networkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(@NonNull Network network) { + super.onAvailable(network); + poResult.success(true); + } + + @Override + public void onUnavailable() { + super.onUnavailable(); + poResult.success(false); + } + }; + + + connectivityManager.requestNetwork(networkRequest, networkCallback, handler, 30 * 1000); + + // TODO remove network in cleanup, if joinOnce + } + } + + @SuppressWarnings("deprecation") + private Boolean connectToDeprecated(String ssid, String password, String security, Boolean joinOnce) { /// Make new configuration - WifiConfiguration conf = new WifiConfiguration(); + android.net.wifi.WifiConfiguration conf = new android.net.wifi.WifiConfiguration(); conf.SSID = "\"" + ssid + "\""; if (security != null) security = security.toUpperCase(); @@ -740,38 +890,38 @@ private Boolean connectTo(String ssid, String password, String security, Boolean /// ifcase of not added it will not be able to connect conf.preSharedKey = "\"" + password + "\""; - conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); + conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.RSN); - conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + conf.allowedKeyManagement.set(android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK); - conf.status = WifiConfiguration.Status.ENABLED; + conf.status = android.net.wifi.WifiConfiguration.Status.ENABLED; - conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); - conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); + conf.allowedGroupCiphers.set(android.net.wifi.WifiConfiguration.GroupCipher.TKIP); + conf.allowedGroupCiphers.set(android.net.wifi.WifiConfiguration.GroupCipher.CCMP); - conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + conf.allowedKeyManagement.set(android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK); - conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); - conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); + conf.allowedPairwiseCiphers.set(android.net.wifi.WifiConfiguration.PairwiseCipher.TKIP); + conf.allowedPairwiseCiphers.set(android.net.wifi.WifiConfiguration.PairwiseCipher.CCMP); - conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); - conf.allowedProtocols.set(WifiConfiguration.Protocol.WPA); + conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.RSN); + conf.allowedProtocols.set(android.net.wifi.WifiConfiguration.Protocol.WPA); } else if (security.equals("WEP")) { conf.wepKeys[0] = "\"" + password + "\""; conf.wepTxKeyIndex = 0; - conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); + conf.allowedKeyManagement.set(android.net.wifi.WifiConfiguration.KeyMgmt.NONE); + conf.allowedGroupCiphers.set(android.net.wifi.WifiConfiguration.GroupCipher.WEP40); } else { - conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + conf.allowedKeyManagement.set(android.net.wifi.WifiConfiguration.KeyMgmt.NONE); } /// Remove the existing configuration for this netwrok - List mWifiConfigList = moWiFi.getConfiguredNetworks(); + List mWifiConfigList = moWiFi.getConfiguredNetworks(); int updateNetwork = -1; if (mWifiConfigList != null) { - for (WifiConfiguration wifiConfig : mWifiConfigList) { + for (android.net.wifi.WifiConfiguration wifiConfig : mWifiConfigList) { if (wifiConfig.SSID.equals(conf.SSID)) { conf.networkId = wifiConfig.networkId; updateNetwork = moWiFi.updateNetwork(conf); @@ -817,69 +967,5 @@ private Boolean connectTo(String ssid, String password, String security, Boolean return connected; } - - public static String sudoForResult(String... strings) { - String res = ""; - DataOutputStream outputStream = null; - InputStream response = null; - try { - Process su = Runtime.getRuntime().exec("su"); - outputStream = new DataOutputStream(su.getOutputStream()); - response = su.getInputStream(); - - for (String s : strings) { - outputStream.writeBytes(s + "\n"); - outputStream.flush(); - } - - outputStream.writeBytes("exit\n"); - outputStream.flush(); - try { - su.waitFor(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - res = readFully(response); - } catch (IOException e) { - e.printStackTrace(); - } finally { - Closer.closeSilently(outputStream, response); - } - return res; - } - - private static String readFully(InputStream is) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int length = 0; - while ((length = is.read(buffer)) != -1) { - baos.write(buffer, 0, length); - } - return baos.toString("UTF-8"); - } - - static class Closer { - /// closeAll() - public static void closeSilently(Object... xs) { - /// Note: on Android API levels prior to 19 Socket does not implement Closeable - for (Object x : xs) { - if (x != null) { - try { - if (x instanceof Closeable) { - ((Closeable) x).close(); - } else if (x instanceof Socket) { - ((Socket) x).close(); - } else if (x instanceof DatagramSocket) { - ((DatagramSocket) x).close(); - } else { - throw new RuntimeException("cannot close " + x); - } - } catch (Throwable e) { - // TODO : do something ? - } - } - } - } - } } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d6350163..650cbdc1 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -15,7 +15,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion 30 lintOptions { disable 'InvalidPackage' @@ -25,10 +25,10 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.alternadom.wifiiotexample" minSdkVersion 16 - targetSdkVersion 27 + targetSdkVersion 30 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { @@ -46,6 +46,6 @@ flutter { dependencies { testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index e2dc8b67..541f1e93 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -35,5 +35,8 @@ + diff --git a/example/android/app/src/main/java/com/alternadom/wifiiotexample/MainActivity.java b/example/android/app/src/main/java/com/alternadom/wifiiotexample/MainActivity.java index c1c764de..38596d24 100644 --- a/example/android/app/src/main/java/com/alternadom/wifiiotexample/MainActivity.java +++ b/example/android/app/src/main/java/com/alternadom/wifiiotexample/MainActivity.java @@ -1,14 +1,6 @@ package com.alternadom.wifiiotexample; -import android.os.Bundle; - -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; +import io.flutter.embedding.android.FlutterActivity; public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } } diff --git a/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java index 38a33ea2..7b5c1f91 100644 --- a/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ b/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -1,25 +1,18 @@ package io.flutter.plugins; -import io.flutter.plugin.common.PluginRegistry; -import com.alternadom.wifiiot.WifiIotPlugin; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; + +import io.flutter.embedding.engine.FlutterEngine; /** * Generated file. Do not edit. + * This file is generated by the Flutter tool based on the + * plugins that support the Android platform. */ +@Keep public final class GeneratedPluginRegistrant { - public static void registerWith(PluginRegistry registry) { - if (alreadyRegisteredWith(registry)) { - return; - } - WifiIotPlugin.registerWith(registry.registrarFor("com.alternadom.wifiiot.WifiIotPlugin")); - } - - private static boolean alreadyRegisteredWith(PluginRegistry registry) { - final String key = GeneratedPluginRegistrant.class.getCanonicalName(); - if (registry.hasPlugin(key)) { - return true; - } - registry.registrarFor(key); - return false; + public static void registerWith(@NonNull FlutterEngine flutterEngine) { + flutterEngine.getPlugins().add(new com.alternadom.wifiiot.WifiIotPlugin()); } } diff --git a/example/android/build.gradle b/example/android/build.gradle index 44768875..c9e3db0a 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:4.1.0' } } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index aa901e1e..69e97a3f 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Thu Oct 29 10:36:05 IST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip diff --git a/example/pubspec.lock b/example/pubspec.lock index 71f43872..ee019f92 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,62 +1,48 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.5.0-nullsafety.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" - charcode: + version: "2.1.0-nullsafety.1" + characters: dependency: transitive description: - name: charcode + name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" - collection: + version: "1.1.0-nullsafety.3" + charcode: dependency: transitive description: - name: collection + name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" - convert: + version: "1.2.0-nullsafety.1" + clock: dependency: transitive description: - name: convert + name: clock url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" - crypto: + version: "1.1.0-nullsafety.1" + collection: dependency: transitive description: - name: crypto + name: collection url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "1.15.0-nullsafety.3" cupertino_icons: dependency: "direct main" description: @@ -64,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0-nullsafety.1" flutter: dependency: "direct main" description: flutter @@ -74,55 +67,27 @@ packages: description: flutter source: sdk version: "0.0.0" - image: - dependency: transitive - description: - name: image - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.10-nullsafety.1" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0-nullsafety.3" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0+1" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.0" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" + version: "1.8.0-nullsafety.1" sky_engine: dependency: transitive description: flutter @@ -134,70 +99,63 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.8.0-nullsafety.2" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0-nullsafety.1" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0-nullsafety.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.19-nullsafety.2" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0-nullsafety.3" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0-nullsafety.3" wifi_iot: dependency: "direct dev" description: path: ".." relative: true source: path - version: "0.1.0" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "3.5.0" + version: "0.1.1" sdks: - dart: ">=2.4.0 <3.0.0" + dart: ">=2.10.0-110 <2.11.0" flutter: ">=1.10.0 <2.0.0"