Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Android Wifi Manager

Discussion in 'Android' started by Piflik, Apr 17, 2023.

  1. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    289
    I posted this a couple of days ago on stackoverflow, without any results, so I though I'd try here as well.

    I am currently trying to list all available Wifi networks with their signal strength and then select one to connect to, all from within an application built with Unity (the usecase is changing the network while the device is in kiosk mode). The first part (listing networks) I got working, but I am struggling with the second half. This is the code I wrote by referencing the documentation (sadly Unity can interact with Android classes only via reflection, so the types are all AndroidJavaObject. Also, this is also the first time I try to interface with native Android code from Unity, so I might do something fundamentally wrong):

    Code (CSharp):
    1. private const int TRANSPORT_TYPE_WIFI = 1;
    2. private const int NET_CAPABILITY_INTERNET = 12;
    3. private const string JAVA_CLASS_IDENTIFIER = "com.unity3d.player.UnityPlayer";
    4.  
    5. private static AndroidJavaObject _wifiManager;
    6. private static AndroidJavaObject _connectivityManager;
    7. private static AndroidJavaObject _networkSpecifierBuilder;
    8. private static AndroidJavaObject _networkRequestBuilder;
    9.  
    10. //this is done once at initialization
    11. Input.location.Start(); //this is used to start the location service from Unity to enable wifi detection
    12. AndroidJavaObject activity = new AndroidJavaClass(JAVA_CLASS_IDENTIFIER).GetStatic<AndroidJavaObject>("currentActivity");
    13. _wifiManager = activity.Call<AndroidJavaObject>("getSystemService", "wifi");
    14. _connectivityManager = activity.Call<AndroidJavaObject>("getSystemService", "connectivity");
    15. _networkSpecifierBuilder = new AndroidJavaObject("android.net.wifi.WifiNetworkSpecifier$Builder");
    16. _networkRequestBuilder = new AndroidJavaObject("android.net.NetworkRequest$Builder");
    17.  
    18. //this is done each time I connect to a network
    19. AndroidJavaObject specifierBuilder = _networkSpecifierBuilder.Call<AndroidJavaObject>("setSsid", network.ssid);
    20. if (network.encryption == Encryption.WPA2) {
    21.     specifierBuilder = specifierBuilder.Call<AndroidJavaObject>("setWpa2Passphrase", network.password);
    22. } else if (network.encryption == Encryption.WPA3) {
    23.     specifierBuilder = specifierBuilder.Call<AndroidJavaObject>("setWpa3Passphrase", network.password);
    24. }
    25.  
    26. AndroidJavaObject networkSpecifier = specifierBuilder.Call<AndroidJavaObject>("build");
    27. AndroidJavaObject networkRequest = _networkRequestBuilder
    28.     .Call<AndroidJavaObject>("addTransportType", TRANSPORT_TYPE_WIFI)
    29.     //.Call<AndroidJavaObject>("addCapability", NET_CAPABILITY_INTERNET)
    30.     .Call<AndroidJavaObject>("setNetworkSpecifier", networkSpecifier)
    31.     .Call<AndroidJavaObject>("build");
    32.  
    33. _connectivityManager.Call("requestNetwork", networkRequest, new AndroidJavaObject("android.net.ConnectivityManager$NetworkCallback"));
    34. //I need a callback object for the function to work, but I can't override its functions from Unity.
    35. //This is where things might go wrong, but I also didn't find anything in the documentation stating that any of the callback's functions need to be implemented in a certain way to get a working connection.
    The
    Network
    class is just a data-object holding ssid, signal strength, encryption type and passphrase. When I run the code, I get a little popup asking me if I really want to connect, but when I click "connect" the connection is not working right. Different code relying on an active internet connection does not work correctly (it does if I connect to the same network manually, even while the app is running, so it is unlikely that the other part of the code runs into some fail-state) and the code I use to detect an active wifi connection also doesn't report a connection. The most peculiar part is that I can still reach the device over wifi using adb logcat (I need to restart logcat, but I get a realtime log in my console). Also, if I require the "INTERNET" capabilitiy, I don't even get the popup to connect to the wifi network. This behaviour is identical if the app is started while the device is not connected to any wifi network or to the exact same network I try to connect to from within the application. Permissions are all set in the manifest file and I also don't get any (visible) exceptions, but also no working connection.

    Target API level is 29 (Android 10), currently, so the simpler connection API in the WifiManager doesn't work anymore.
     
  2. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    289
    For completion's sake, this is the code I use for testing an active connection (it works if I have connected manually):

    Code (CSharp):
    1. using AndroidJavaObject wifiInfo = _wifiManager.Call<AndroidJavaObject>("getConnectionInfo");
    2. using AndroidJavaObject currentSsid = wifiInfo.Call<AndroidJavaObject>("getSSID");
    3. return currentSsid.Call<string>("toString");
    And for finding all visible networks:

    Code (CSharp):
    1. Dictionary<string, Network> visibleNetworks = new Dictionary<string, Network>();
    2.  
    3. using AndroidJavaObject scanResults = _wifiManager.Call<AndroidJavaObject>("getScanResults");
    4.  
    5. int count = scanResults.Call<int>("size");
    6.  
    7. for (int i = 0; i < count; ++i) {
    8.     using AndroidJavaObject scanResult = scanResults.Call<AndroidJavaObject>("get", i);
    9.  
    10.     string ssid = scanResult.Get<string>("SSID");
    11.     int signalStrength = _wifiManager.CallStatic<int>("calculateSignalLevel", scanResult.Get<int>("level"), 5);
    12.  
    13.     if (string.IsNullOrWhiteSpace(ssid)) continue;
    14.  
    15.     if (visibleNetworks.TryGetValue(ssid, out Network network)) {
    16.         if (network.signalStrength >= signalStrength) continue;
    17.         network.signalStrength = signalStrength;
    18.     } else {
    19.         string capabilities = scanResult.Get<string>("capabilities").ToLowerInvariant();
    20.         Encryption encryption = GetEncryption(capabilities); //currently just a helper function to test if the capabilities string contains wpa2 or wpa3
    21.  
    22.         visibleNetworks[ssid] = new Network(ssid, encryption) {
    23.             signalStrength = signalStrength,
    24.         };
    25.     }
    26. }
     
    Kareem_Hesham and MD_Reptile like this.
  3. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    I can't help you figure out the connection stuff, but I was tinkering with this sort of thing too and discovered that in unity 2022.3.4f1 I don't see a network name of the wifi network I am connected to and only see <unknown ssid> instead - but I did see the name in unity version 2021.3.19f1 which seemed strange. I dunno if this helps anybody who runs into that but yeah...

    EDIT: Doh - needed location permission, forgot I had changed up the manifest! Works to show the SSID again.
     
    Last edited: Jul 2, 2023