From 3b924a6ff6a0aa9e92df8c3fb1a2c4da127c2552 Mon Sep 17 00:00:00 2001 From: "Jianbing (Bruce) Li" Date: Fri, 3 Apr 2020 15:08:34 +1300 Subject: [PATCH 1/2] extend isRemoveWifiNetworkReturnPromiseBoolean --- .../java/com/reactlibrary/rnwifi/RNWifiModule.java | 13 ++++++++----- lib/types/index.d.ts | 9 ++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java b/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java index 274741b..80f1ae4 100644 --- a/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java +++ b/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java @@ -15,6 +15,7 @@ import android.net.wifi.WifiManager; import android.os.Build; + import androidx.annotation.NonNull; import com.facebook.react.bridge.Callback; @@ -288,23 +289,25 @@ public void getIP(final Callback callback) { * This method will remove the wifi network as per the passed SSID from the device list * * @param ssid - * @param callback + * @param promise true means the ssid has been removed or did not existed in configured network list + * false means the ssid removed failed. */ @ReactMethod - public void isRemoveWifiNetwork(String ssid, final Callback callback) { + public void isRemoveWifiNetwork(String ssid, final Promise promise) { List mWifiConfigList = wifi.getConfiguredNetworks(); for (WifiConfiguration wifiConfig : mWifiConfigList) { String comparableSSID = ('"' + ssid + '"'); //Add quotes because wifiConfig.SSID has them if (wifiConfig.SSID.equals(comparableSSID)) { - wifi.removeNetwork(wifiConfig.networkId); + boolean success = wifi.removeNetwork(wifiConfig.networkId); wifi.saveConfiguration(); - callback.invoke(true); + promise.resolve(success); return; } } - callback.invoke(false); + promise.resolve(true); } + /** * This method is similar to `loadWifiList` but it forcefully starts the wifi scanning on android and in the callback fetches the list * diff --git a/lib/types/index.d.ts b/lib/types/index.d.ts index 1a28cef..2dc0df7 100644 --- a/lib/types/index.d.ts +++ b/lib/types/index.d.ts @@ -86,7 +86,14 @@ declare module 'react-native-wifi-reborn' { export function disconnect(): void; - export function isRemoveWifiNetwork(SSID: string): Promise; + /** + * Remove the network with SSID from configirued networks. + * When their is a wrong authed network in configured network, the connectToProtectedSSID will fail. + * So please use this function to delete it first. + * @param SSID + * @returns true: the network has been deleted. false: the network is created by others, you can not delete it. + */ + export function isRemoveWifiNetwork(SSID: string): Promise; export enum FORCE_WIFI_USAGE_ERRORS { couldNotGetConnectivityManager = 'couldNotGetConnectivityManager', From b7bc503af945a5dc35688ef796db1bee664376dd Mon Sep 17 00:00:00 2001 From: "Jianbing (Bruce) Li" Date: Thu, 23 Apr 2020 09:13:05 +1200 Subject: [PATCH 2/2] make connect and disconnet working on android 10 --- .../com/reactlibrary/rnwifi/RNWifiModule.java | 131 +++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java b/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java index 80f1ae4..fc6cd7d 100644 --- a/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java +++ b/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java @@ -5,18 +5,25 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.net.DhcpInfo; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; 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.net.wifi.WifiNetworkSuggestion; +import android.os.PatternMatcher; +import android.text.format.Formatter; +import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; @@ -33,11 +40,16 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class RNWifiModule extends ReactContextBaseJavaModule { private final WifiManager wifi; private final ReactApplicationContext context; + private final String TAG= "RNWifi"; + private ConnectivityManager.NetworkCallback networkCallback = null; RNWifiModule(ReactApplicationContext context) { super(context); @@ -157,6 +169,99 @@ public void setEnabled(Boolean enabled) { wifi.setWifiEnabled(enabled); } + public void verifyNetworkSwitched(final String SSID, final Promise promise){ + Log.d(TAG, "verifyNetworkSwitched"); + + // Timeout if there is no other saved WiFi network reachable + ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1); + + // Verify the connection + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + final BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + if (info != null && info.isConnected()) { + final WifiInfo wifiInfo = wifi.getConnectionInfo(); + String ssid = wifiInfo.getSSID(); + // This value should be wrapped in double quotes, so we need to unwrap it. + if (ssid.startsWith("\"") && ssid.endsWith("\"")) { + ssid = ssid.substring(1, ssid.length() - 1); + } + Log.d(TAG, "connect to "+ssid); + + context.unregisterReceiver(this); + exec.shutdownNow(); + if (ssid.equals(SSID)) { + final String routerIP = Formatter.formatIpAddress(wifi.getDhcpInfo().gateway); + final String localIP = Formatter.formatIpAddress(wifi.getDhcpInfo().ipAddress); + Log.d(TAG, String.format("Network %s ip %s router %s", SSID, localIP,routerIP)); + promise.resolve(null); + } + else { + promise.reject("connectNetworkFailed", String.format("Could not connect to network with SSID: %s", SSID)); + } + } + } + }; + exec.schedule(new Runnable() { + public void run() { + Log.d(TAG, "timeout"); + context.unregisterReceiver(receiver);//make sure promise only resolve once + promise.reject("connectNetworkFailed", String.format("Timeout connecting to network with SSID: %s", SSID)); + } + }, 10, TimeUnit.SECONDS); + context.registerReceiver(receiver, intentFilter); + } + + @RequiresApi(api = Build.VERSION_CODES.Q) + private void androidQConnectToProtectedSSID(@NonNull final String SSID, @NonNull final String password, final boolean isWep, final Promise promise) { + Log.d(TAG, String.format("call androidQConnectToProtectedSSID with %s %s", SSID, password)); + + final NetworkSpecifier specifier = + new WifiNetworkSpecifier.Builder().setSsid(SSID).setWpa2Passphrase(password) + .build(); + + final NetworkRequest request = + new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .setNetworkSpecifier(specifier) + .build(); + + final ConnectivityManager connectivityManager = (ConnectivityManager) + context.getSystemService(Context.CONNECTIVITY_SERVICE); + + if(connectivityManager == null){ + Log.d(TAG, "Can not get ConnectivityManager"); + promise.reject("failed", "Can not get ConnectivityManager"); + return; + } + + networkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(@NonNull Network network) { + super.onAvailable(network); + + Log.d(TAG, String.format("AndroidQ+ request to wifi %s",network.toString())); + boolean binded = connectivityManager.bindProcessToNetwork(network); + Log.d(TAG, String.format("AndroidQ+ bind to wifi %b", binded)); + + verifyNetworkSwitched(SSID, promise); + } + + @Override + public void onUnavailable() { + super.onUnavailable(); + + Log.d(TAG, "AndroidQ+ could not connect to wifi"); + promise.reject("failed", "AndroidQ+ could not connect to wifi"); + + } + }; + connectivityManager.requestNetwork(request, networkCallback); + } + /** * Use this to connect with a wifi network. * Example: wifi.findAndConnect(ssid, password, false); @@ -180,7 +285,12 @@ public void connectToProtectedSSID(@NonNull final String SSID, @NonNull final St promise.reject("location off", "Location service is turned off"); return; } - + if(isAndroid10OrLater()){ + Log.d(TAG,"androidQConnectToProtectedSSID"); + androidQConnectToProtectedSSID(SSID,password,isWep,promise); + return; + } + WifiUtils.enableLog(true); WifiUtils.withContext(context).connectWith(SSID, password).onConnectionResult(new ConnectionSuccessListener() { @Override public void isSuccessful(boolean isSuccess) { @@ -191,6 +301,7 @@ public void isSuccessful(boolean isSuccess) { } } }).start(); + } /** @@ -214,7 +325,20 @@ public void connectionStatus(Callback connectionStatusResult) { */ @ReactMethod public void disconnect() { + if(isAndroid10OrLater()){ + ConnectivityManager connManager = (ConnectivityManager) getReactApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); + if(connManager!=null) { + if(networkCallback!=null) { + Log.d(TAG,"unregisterNetworkCallback"); + connManager.unregisterNetworkCallback(networkCallback); + networkCallback = null; + } + Log.d(TAG,"bindProcessToNetwork to null"); + connManager.bindProcessToNetwork(null); + } + }else{ wifi.disconnect(); + } } /** @@ -397,7 +521,6 @@ private static boolean isAndroidLollipopOrLater() { * @return true if the current sdk is above or equal to Android Q */ private static boolean isAndroid10OrLater() { - return false; // TODO: Compatibility with Android 10 - // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; } }