2

I need help in creating a C# script that set a android WiFi in hotspot mode. Here is the code that I managed to create.

    public bool setAPEnabled(bool enabled)
{
    using (AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity"))
    {
        try
        {
            if(isWifiEnabled()==true){
                setWifiEnabled(false);
            }
            using (var wifiManager = activity.Call<AndroidJavaObject>("getSystemService", "wifi"))
            {
                return wifiManager.Call<bool>("setWifiApEnabled",null, enabled);
            }
        }
        catch (Exception e)
        {
        }
    }
    return false;
}

Everything works well - but I have a problem with setting the SSID and password. After reviewing the documentation I know that I have to replace my null value with the settings object, but I completely don't know how to do it in Unity.

Bart
  • 19,692
  • 7
  • 68
  • 77
BackLogers
  • 23
  • 1
  • 3

1 Answers1

2

Theses methods works only for android 5.0 and less !

The EASY way :

Try instantiating the WifiConfiguration first :

AndroidJavaObject wifiConfiguration = new AndroidJavaClass("android.net.wifi.WifiConfiguration");

Now you can call methods and set/get fields within this object :

// to set SSID
wifiConfiguration.Set("SSID", meSSID); // string
wifiConfiguration.Set("preSharedKey", mePassword); // string

After settings all of the required fields just call your setWifiApEnabled method :

wifiManager.Call<bool>("setWifiApEnabled", wifiConfiguration, enabled);

Maybe you will have to set more fields than these two but to confirm that you should check the source and ensure what setWifiApEnabled method does internaly.


The HARD way :
( using reflection code )

Step 6 does not work for android 5.0+ !

Using reflection with AndroidJavaObject can be a bit tricky because you have to remember to dispose every object.

So from the beginning :

// android code for that should look like :
// wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);

// but in Unity C# you have to split this into few chunks:
// 1. Get calling class :
using ( AndroidJavaObject classObj = wifiManager.Call<AndroidJavaObject>("getClass") )
{
    // classObj should contains your class object 
    // 2. call get WifiConfiguration class details :
    using ( AndroidJavaObject wifiConfiguration = new AndroidJavaObject("setWifiApEnabled") )
    {
        // 3. Fill that object :
        wifiConfiguration.Set("SSID", meSSID); // string
        wifiConfiguration.Set("preSharedKey", mePassword); // string
        // 4. Get WifiConfiguration class definition
        using (AndroidJavaObject wifiCfgClass = wifiConfiguration.Call<AndroidJavaObject>("getClass") )
        { 
            // 5. Get boolean definition
            using ( AndroidJavaObject booleanObj = new AndroidJavaObject("java.lang.Boolean") )
            {
                using ( AndroidJavaObject booleanClass = booleanObj.Call<AndroidJavaObject>("getClass") )
                // 6. Get method definition
                using ( AndroidJavaObject methodObj = classObj.Call<AndroidJavaObject>("getMethod", "setWifiApEnabled", wifiCfgClass , booleanClass))
                {
                    // 7. Call that method :)
                    methodObj.Call("invoke", wifiManager, wifiConfiguration, enabled);
                }
            }
        }
    }
}

WifiConfiguration :

I was trying to find out why the above code might not work but for me it was working okay ( tested on some virtual machines and Samsung Galaxy S5 Neo ).

What may be the case ( which I found out at almost midnight ) is a passphrase.
According to this wikipedia article in the section about WPA-PSK

Also referred to as WPA-PSK (pre-shared key) mode, this is designed for home and small office networks and doesn't require an authentication server.[9] Each wireless network device encrypts the network traffic using a 256 bit key. This key may be entered either as a string of 64 hexadecimal digits, or as a passphrase of 8 to 63 printable ASCII characters.[10] If ASCII characters are used, the 256 bit key is calculated by applying the PBKDF2 key derivation function to the passphrase, using the SSID as the salt and 4096 iterations of HMAC-SHA1.[11] WPA-Personal mode is available with both WPA and WPA2.)

My suggestion would be to use the same passphrase as in the article linked above to make sure it's valid.

Also another thing to note is the SSID part which has a short but good description here on wikipedia.

A common, albeit incorrect assumption, is that an SSID is a string of human-readable characters (such as ASCII), terminated by a NUL character (as in a C-string). SSIDs must be treated and handled as what they are, a sequence of 0–32 octets, some of which may not be human-readable

From what I've checked you do not need to null-terminate your string within Java or C# because it will be handled by native code but still you should not exceed 31 characters ( 32 will be the null character ).

I checked this with :
SSID:MeHotSpot
WPA-PSK:5260305714217573

Peladao
  • 4,036
  • 1
  • 23
  • 43
mrogal.ski
  • 5,828
  • 1
  • 21
  • 30
  • 1
    It would be worth knowing why someone downvoted this. – mrogal.ski Mar 09 '17 at 14:40
  • I see why you got the downvote. This should not work. `setWifiApEnabled` is a hidden function and not even documented. It needs reflection to work so what you have now will not work. I maybe wrong but there are few more processes to perform to get this work like using the `Method` class... – Programmer Mar 09 '17 at 14:58
  • @Programmer That may be correct but I answered acordingly to [this source](https://android.googlesource.com/platform/frameworks/base.git/+/android-4.2.2_r1/services/java/com/android/server/WifiService.java). But still waiting for some feedback if it really needs reflection or not. I'll edit my answer when it will be needed. – mrogal.ski Mar 09 '17 at 15:01
  • @m.rogalski Thank you so much for help. I modified the code to your instructions - in unity there are no errors, but after installing the application closes after the start hotspot. [link](http://pastebin.com/yFWYJvZp) – BackLogers Mar 09 '17 at 15:25
  • Have you specified permissions to write settings and change connection? ` ` This should be changable in the project settings. – mrogal.ski Mar 09 '17 at 15:30
  • @m.rogalski Yes both permission are added. – BackLogers Mar 09 '17 at 15:49
  • Run the app within Android studio, Eclipse or else. Or use adb. You will be able to see what crashes the application. – Everts Mar 09 '17 at 19:16
  • @m.rogalski `WifiConfigurations` works now. But password still not working - probably because i need to use one of the nested classes of `WifiConfigurations`. But i dont know how to do this in Unity. – BackLogers Mar 09 '17 at 19:26
  • @BackLogers Check edited answer and maybe this will help you. I spend some time trying to figure out what was wrong :D – mrogal.ski Mar 10 '17 at 08:25
  • @m.rogalski [my code](http://pastebin.com/cEw9a8uh) - still nothing, only SSID works (tested on android 4.4.4).I think that we need to use nested classes of `WifiConfigurations` to set a few things [like here](http://stackoverflow.com/questions/17152847/create-wifi-hotspot-configuration-in-android) or [here](http://stackoverflow.com/questions/6394599/android-turn-on-off-wifi-hotspot-programmatically). – BackLogers Mar 10 '17 at 10:12
  • @BackLogers Okay I'll try to figure something out. – mrogal.ski Mar 10 '17 at 10:15
  • the easy way crashes the app and force it to close and the hard way has an error saying setWifiApEnabled cannot be found, what should I do? – Henjin Jun 08 '17 at 06:54