flutternetwork / WiFiFlutter

Flutter plugin suite for various WiFi services.
https://wifi.flutternetwork.dev
290 stars 183 forks source link

Mobile Internet doesn't work, after closing the IOT device wifi connection. #385

Open karthiksensesemi opened 7 months ago

karthiksensesemi commented 7 months ago

I'm using this package for auto-connecting to wifi. Then using the tcp sockets i receive the data. Later, the IOT device gets disconnected and mobile gets switched to either mobile data or another wifi.

The internet gets blocked, unless i restart the app. The internet doesn't work after the communication.

GivDavidL commented 3 months ago

I too have this issue, any fix?

E2-Veera commented 3 months ago

I'm also having this issue any help on this? In my case after IOT device stops the WiFi connection my device should automatically switch to previously configured home wifi.

karthikmohan4 commented 3 months ago

You need to set forceWifiUsage(false) after communicating with IOT device.

E2-Veera commented 3 months ago

I have handled this feature Natively Please find the source code below with this you can achieve the following (Use method channel to call this native code in flutter)

  1. Connect to WiFi IOT device using ssid and password
  2. Able to communicate to the IOT device using localhost connection
  3. Once the IOT device stops WiFi connection your android mobile will automatically switch to previously configured WiFi connections and also you are able to use the Internet as well within the app

Connection method For Android 10+ devices

public static CompletableFuture<String> connectWifi(MainActivity context, String ssid, String password,boolean useTimeout) {
        CompletableFuture<String> future = new CompletableFuture<>();
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                Log.d(TAG, "Device is above Android 10....");
                WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
                        .setSsid(ssid)
                        .setWpa2Passphrase(password)
                        .build();

                NetworkRequest networkRequest = new NetworkRequest.Builder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .setNetworkSpecifier(wifiNetworkSpecifier)
                        .build();

                ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                ConnectivityManager.NetworkCallback callback =  new ConnectivityManager.NetworkCallback() {

                    // When the IOT device connection is established, the below callback is triggered. And the Mobile Device will be connected to the IOT device.
                    @Override
                    public void onAvailable(Network network) {
                        Log.d(TAG, "Network is available: " + network);
                        //This callback will automatically trigger the WiFi connection Popup
                        // bindProcessToNetwork is used to perform API operations with IOT devices.
                        connectivityManager.bindProcessToNetwork(network);
                        future.complete("connected");
                    }

                    @Override
                    public void onUnavailable() {
                        Log.d(TAG, "Network is unavailable");
                        future.complete("networkUnavailable");
                    }

                    @Override
                    public void onLosing(Network network, int maxMsToLive) {
                        Log.d(TAG, "Network is losing with maxMsToLive: " + maxMsToLive);
                        future.complete("networkLoosing");
                    }

                    // When the IOT device connection is lost, the below callback is triggered. Then the Connectivity Manager is set to null.
                    // So that the WiFi connection can be re-switched to the previously connected WiFi network.
                    @Override
                    public void onLost(Network network) {
                        Log.d(TAG, "Network is lost: " + network);
                        // Setting bindProcessToNetwork null to use the Internet connection After IOT is diconnected.
                        connectivityManager.bindProcessToNetwork(null);
                        // Unregister the callback to enable Network Switching after IOT is diconnected
                        connectivityManager.unregisterNetworkCallback(this);
                        future.complete("networkLost");
                    }
                };

                if (connectivityManager != null) {
                    if(useTimeout) {
                        connectivityManager.requestNetwork(networkRequest,callback,60000);
                    }else{
                        connectivityManager.requestNetwork(networkRequest,callback);
                    }

                } else {
                    Log.d(TAG, "Connectivity Manager is null....");
                    future.complete("notConnected");
                }
            } else {
                Log.d(TAG, "Android level is low so Executing legacy method");
                future.complete(connectToWifiLegacy(context, ssid, password));
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "Exception occurred: " + e.getMessage());
            future.completeExceptionally(e);
        }
        return future;
    }

Connection method for Android 10 below devices

 private static String connectToWifiLegacy(MainActivity context, String ssid, String password) {
        try {
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (wifiManager == null) {
                return "notConnected";
            }
            WifiConfiguration wifiConfig = new WifiConfiguration();
            wifiConfig.SSID = String.format("\"%s\"", ssid);
            wifiConfig.preSharedKey = String.format("\"%s\"", password);

            // Add the network and connect to it
            int netId = wifiManager.addNetwork(wifiConfig);
            if (netId == -1) {
                return "Failed to add network configuration";
            }
            wifiManager.disconnect();
            wifiManager.enableNetwork(netId, true);
            boolean flag = wifiManager.reconnect();
            Log.d(TAG, "Reconnect result: " + flag);
            return "connected";
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "Exception occurred: " + e.getMessage());
            return "exception";
        }
    }
Bojan227 commented 1 month ago

I have handled this feature Natively Please find the source code below with this you can achieve the following (Use method channel to call this native code in flutter)

@E2-Veera I'm connected to WiFi IOT using ssid and when i switch the mode from AP to AP + STA, then Android and iOS will auto-connect back to my home network. Will this code help me resolve this issue for Andorid? Do you know any solution for an iOS app?

E2-Veera commented 1 month ago

I have handled this feature Natively Please find the source code below with this you can achieve the following (Use method channel to call this native code in flutter)

@E2-Veera I'm connected to WiFi IOT using ssid and when i switch the mode from AP to AP + STA, then Android and iOS will auto-connect back to my home network. Will this code help me resolve this issue for Andorid? Do you know any solution for an iOS app?

Above android solution perfectly working for me dor iOS I've used the following swift code for WiFi Connection, By using this when your IoT device stops the wifi connection then iPhone will automatically switch to Home WiFi


import Foundation
import NetworkExtension
import SystemConfiguration.CaptiveNetwork

enum WifiStatus: String {
    case connected = "connected"
    case alreadyConnected = "alreadyConnected"
    case notConnected = "notConnected"
    case platformNotSupported = "platformNotSupported"
    case profileAlreadyInstalled = "profileAlreadyInstalled"

    func stringValue() -> String {
        return self.rawValue
    }
}

class WifiHelper {
    func connectToWifi(ssid: String, password: String, result: @escaping (String) -> Void) {
        if #available(iOS 11.0, *) {
            let configuration = NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: false)
            NEHotspotConfigurationManager.shared.removeConfiguration(forSSID: ssid)

            NEHotspotConfigurationManager.shared.apply(configuration) { (error) in
                if let error = error {
                    if error.localizedDescription == "already associated." {
                        result(WifiStatus.alreadyConnected.stringValue())
                    } else {
                        if (error as NSError).code == 10 {
                            result(WifiStatus.profileAlreadyInstalled.stringValue())
                        } else {
                            result(WifiStatus.notConnected.stringValue())
                        }
                    }
                } else {
                    if self.isConnectedToCorrectWifi(wifiToCompareWith: ssid) {
                        result(WifiStatus.connected.stringValue())
                    } else {
                        result(WifiStatus.notConnected.stringValue())
                    }
                }
            }
        } else {
            result(WifiStatus.notConnected.stringValue())
        }
    }
    }

Please note that you have to Enable Local Network Permission to communicate with IoT devices for that you need to add the below permission in info.plist NSLocationAlwaysUsageDescription

Bojan227 commented 1 month ago

@E2-Veera Thank you for your answer. Is there a way to prevent connecting to the home wifi and just connect to the IoT device automatically. What I'm doing is the following, I'm connecting to the IoT device, making a request, after the request the IoT device reboots and I want to reconnect again to the same IoT device, but not to the home wifi..

I'm doing the same from my laptop, but the windows laptop won't switch the network which is an optimal solution for me...

E2-Veera commented 1 month ago

@E2-Veera Thank you for your answer. Is there a way to prevent connecting to the home wifi and just connect to the IoT device automatically. What I'm doing is the following, I'm connecting to the IoT device, making a request, after the request the IoT device reboots and I want to reconnect again to the same IoT device, but not to the home wifi..

I'm doing the same from my laptop, but the windows laptop won't switch the network which is an optimal solution for me...

If want to connect to the same IoT after disconnection then you have to request the connection again. Android: In android Once the Iot stops the wifi connection then onLost() callback will trigger and in that we are unregitering the network associated with it. So in the onLost callback change your logic to connect again. In android Q and above version this will work without user consent (for the 1st time only user will prompt with connect or cancel popup),

iOS: but in iOS when you request for WiFi connection user will prompt with a dialog box. Without user consent you can't connect any wifi within the app on iOS environment.

Bojan227 commented 1 month ago

@E2-Veera Thanks a lot, that makes sense.