B4A Library MLwifi Library Updated to v4.00

Attached Java Source Code

MLWifi.zip - couldn't attach the entire Android Studio project as even zipped it was too big (900 KB) for the forum limits. If you want the entire project, private message me with your email address & I'll send it to you.

Library updated to v4.40

Added @Events so the callbacks can be auto-generated by the B4A IDE.

Library updated to v4.40

Added WifiBSSID function. Returns a string with the currently connected AP BSSID. Note that Wifi_ConnectionResult & isonline_pingdone don't require the EventName prefix.

Library updated to v4.30

Minor code tweaks & tidy up. Tested saveWifiAP, connectWifiAP, reconnectWifiAP & disconnectWifiAP on Android 4.4.2, 9 & 10.

Library updated to v4.20

Bug Fixes / Improvements:
* Added support for Android Pie.
* Improved connectivity when using saveWifiAP with Android Q+.

Library updated to v4.10

Added:

reconnectWifiAP: (reconnects to a saved Wifi network)

Parameters:
ssid - the name of the Wifi Network
timeout - fail if not connected within timeout (Ms)

Raises Wifi_ConnectionResult event on success or failure

NOTE FOR SDK 29+: Will only work if the network being connected to is not secured.
You can connect to the previously connected network by calling disconnectWifiAP
or a specific network by calling connectWifiAP with the correct parameters.

Example:
B4X:
Private Sub connectToWifi
    Private wifi As MLwifi
    'reconnect to a Wifi network saved on this device
    wifi.reconnectWifiAP("wifissid", 30000)
End Sub

Public Sub Wifi_ConnectionResult(success As Boolean)
    If success then
        'Connected - set up sockets, etc...
    Else
        'Couldn't connect...
    End If
End Sub

Bug Fixes:

isWifiConnected now correctly reports the connection state (true or false).

v4.00

connectWifiAP:
(connects to an existing Wifi Network)

Parameters:
ssid - the name of the Wifi Network
security = 0 = Open (SECURITY_OPEN), 1 = WEP (SECURITY_WEP), 2 = WPA-2/PSK (SECURITY_WPA2PSK)
password - the password or "" if the network is open
timeout - fail if not connected within timeout (Ms)

Raises Wifi_ConnectionResult event on success or failure

Example:
B4X:
Private Sub connectToWifi
    Private wifi As MLwifi

    'To connect to an open network
    wifi.connectWifiAP("wifissid", wifi.SECURITY_OPEN, "", 30000)
    'To connect to a WPA-2 secured network
    wifi.connectWifiAP("wifissid", wifi.SECURITY_WPA2PSK, "password", 30000)
End Sub

Public Sub Wifi_ConnectionResult(success As Boolean)
    If success then
        'Connected - set up sockets, etc...
    Else
        'Couldn't connect...
    End If
End Sub

saveWifiAP: (adds a Wifi network, then optionally connects)

Parameters:
ssid - the name of the Wifi Network
security = 0 = Open (SECURITY_OPEN), 1 = WEP (SECURITY_WEP), 2 = WPA-2/PSK (SECURITY_WPA2PSK)
password - the password or "" if the network is open
connect - ignored for Android Q+ (will always connect)
timeout - fail if not connected within timeout (ms)

Raises Wifi_ConnectionResult event on success or failure

Example:
B4X:
Private Sub connectToWifi
    Private wifi As MLwifi

    'To save & connect to an open network
    wifi.saveWifiAP("wifissid", wifi.SECURITY_OPEN, "", True, 30000)
    'To save & connect to a WPA-2 secured network
    wifi.saveWifiAP("wifissid", wifi.SECURITY_WPA2PSK, "password", True, 30000)
End Sub

Public Sub Wifi_ConnectionResult(success As Boolean)
    If success then
        'Connected - set up sockets, etc...
    Else
        'Couldn't connect...
    End If
End Sub

disconnectWifiAP: (disconnects from a Wifi network)

Usage:
B4X:
    Private disconnected As Boolean = MLwifi.disconnectWifiAP

Note that the connectWifiAP & saveWifiAP functions no longer return a Boolean. They now raise the Wifi_ConnectionResult(success As Boolean) callback event.

I haven't made any changes to any other library functions, nor have I tested them - so if there are functions that aren't working correctly, you'll have to let me know & I'll take a look at them. I also haven't tested the functions I did change/add beyond a couple of use cases (connecting to an ESP8266 Access Point & connecting to my home Wifi), so if there are situations that it doesn't work correctly in, you'll have to let me know.

Also note that there are some Android Q+ Wifi behaviors that are quite different to before, so I suggest you take a look at the android.net.wifi reference to give you a better idea of how the deprecated functions have been re-implemented.

- Colin.
 

Attachments

  • MLwifi400-v4.41.zip
    26 KB · Views: 1,349
  • MLwifi.zip
    8.6 KB · Views: 525
Last edited:

Computersmith64

Well-Known Member
Licensed User
Longtime User
I forgot to mention in my OP that I have also included a debug property. It's set to False by default, but if you set it to True you'll get some debug messages from the library in your B4A logs tab. All the library messages are prefixed with [MLwifi].

- Colin.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
How are you compiling this library? It seems to have an odd structure for a B4A library, unlike the original, with what appears to be an empty jar and the code in the aar when I would expect it to all exist in the jar.
I'm compiling it in Android Studio (per this thread) - which produces an .aar file. Apparently B4A needs the empty .jar for it to work properly.

Edit: There apparently is a way to create a traditional .jar from Android Studio, but I haven't tried it as yet. I'll have a look when I have some time - but as it is, the library appears to function correctly as an .aar.

- Colin.
 

agraham

Expert
Licensed User
Longtime User
but as it is, the library appears to function correctly as an .aar.
I'm sure it does, it just has some unnecessary baggage in the aar which offends my tiny little tidy pedantic mind (R.txt and a manifest ). I compile my libraries with with SLC and just get a plain jar.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
I'm sure it does, it just has some unnecessary baggage in the aar which offends my tiny little tidy pedantic mind (R.txt and a manifest ). I compile my libraries with with SLC and just get a plain jar.
That extra baggage only takes up about 2KB of space - but if that's a problem you can just extract the classes.jar, rename it to MLwifi400.jar, edit MLwifi400.xml & remove the @DependsOn (the 2nd last line of the file), delete the .aar & replace the .jar with your renamed classes.jar. Too easy ?.

- Colin.
 

Nitin Joshi

Active Member
Licensed User
I would like to understand how to tackle with .connectWiFiAP property from new library. Let me explain here.

In earlier version of MLWiFi library, input parameter was SSID for .connectiWiFiAP property howevery new library is....wifi.connectWifiAP("wifissid", wifi.SECURITY_WPA2PSK, "password", 30000)

Here with new property, I am facing below problem. Flow of my APP is..
1) Before opening the APP, say mobile is connected to "ABC" SSID. (it can be home broadband SSID of user mobile)
2) When APP is opened, first, I save connected WiFi SSID using string variable mySSID.
3) Later, my APP connects to another SSID, say "XYZ" (Arduino SSID as Arduino is Access Point in my project) by using .connectWiFiAP property - here is know the other credentials like security and password so no issue.
4) But, for some purpose, I need to connect back to SSID "ABC". In earlier version of MLWiFi library, it was easy as i used to execute code wifi.connectWiFiAP(mySSID). Now, new version requires credentials. We can never come to know the credentials of already saved SSID in mobile. This is leading to big problem as without credentials i can not use .connectWiFiAP property.

Please suggest how to tackle this issue.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
I would like to understand how to tackle with .connectWiFiAP property from new library. Let me explain here.

In earlier version of MLWiFi library, input parameter was SSID for .connectiWiFiAP property howevery new library is....wifi.connectWifiAP("wifissid", wifi.SECURITY_WPA2PSK, "password", 30000)

Here with new property, I am facing below problem. Flow of my APP is..
1) Before opening the APP, say mobile is connected to "ABC" SSID. (it can be home broadband SSID of user mobile)
2) When APP is opened, first, I save connected WiFi SSID using string variable mySSID.
3) Later, my APP connects to another SSID, say "XYZ" (Arduino SSID as Arduino is Access Point in my project) by using .connectWiFiAP property - here is know the other credentials like security and password so no issue.
4) But, for some purpose, I need to connect back to SSID "ABC". In earlier version of MLWiFi library, it was easy as i used to execute code wifi.connectWiFiAP(mySSID). Now, new version requires credentials. We can never come to know the credentials of already saved SSID in mobile. This is leading to big problem as without credentials i can not use .connectWiFiAP property.

Please suggest how to tackle this issue.

OK - that's a scenario that I didn't consider, but you can use:
B4X:
connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout)
& on pre-Q devices it will connect if the network is already saved on the device (regardless of the security, etc...). For Q+, it won't connect like that as-is & I'm looking into why that is the case (although it didn't work in the old library either, so you haven't lost any functionality at this point). Problem is, I'm going away tomorrow for a week - so if I don't get it sorted tonight, it'll have to wait until I get back.

Also - using connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout) for a saved network isn't ideal, so I'll rework it to make it more intuitive.

- Colin.
 
Last edited:

Nitin Joshi

Active Member
Licensed User
Thanks Colin, I will wait till you are back. I will hold my development.

Also - using connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout) for a saved network isn't ideal, so I'll rework it to make it more intuitive.

Yes, its not ideal.

I think, .connectiWiFiAP property should be without credentials, only SSID should be ok because .saveWiFiAP property handles the credentials.

Thank You.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Yes, its not ideal.

I think, .connectiWiFiAP property should be without credentials, only SSID should be ok because .saveWiFiAP property handles the credentials.

The reason I made it this way is because I couldn't find (& still can't find) a way to connect to a secure saved network on Q+ devices without providing credentials. The functionality that allows you to do it on pre-Q devices doesn't seem to exist in the new API. I could provide 2 different connectWifiAP functions, but then it would be up to you to determine what android version the device is running so you know which function to call. The way I implemented it, the library takes care of that.

There are a lot of changes for Q+ & many of them seem to be aimed at tightening up security & privacy. Per my OP in this thread, it wouldn't hurt for you to take a look at the android.net.wifi reference to get a better understanding of how it now works - & you might also find something I've missed..?

- Colin.
 

Nitin Joshi

Active Member
Licensed User
Ohh, now I understood, its limitation of Q+ version.

So currently for pre Q version, below command can be used to connect to saved SSID?
ConnectWiFiAP procedure:
connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout)

but for Q+ we do not have solution now, is it? but what will happen if we continue to use above command? device will not able to connect to SSID which is saved? If device can not connect to SSID which is saved then its a big challenge.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Ohh, now I understood, its limitation of Q+ version.

So currently for pre Q version, below command can be used to connect to saved SSID?
ConnectWiFiAP procedure:
connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout)
Correct.

but for Q+ we do not have solution now, is it? but what will happen if we continue to use above command? device will not able to connect to SSID which is saved? If device can not connect to SSID which is saved then its a big challenge.
I'll keep looking into it while I'm away & hopefully find a solution - but if they've decided to remove that functionality from Q+, then I guess we will have to live with it.

- Colin.
 

hatzisn

Expert
Licensed User
Longtime User
I have some problems detecting if WiFi is connected and in fact I cannot do that at all.
Please see this thread:
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Hi Colin, how are you? hope fine and back. Could you get time to check the solution? thank
I just got home this evening, so I will take a look at it either later tonight or tomorrow. Some research I did while I was away suggests that there is no way to connect to a saved ssid without credentials (if it's secure) in Q+. I guess this makes sense from a security standpoint because it prevents malicious apps from connecting to secure WiFi networks without the user providing the password.

There's also another issue I need to look at as reported by @hatzisn in post #13.

- Colin.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Hi Colin, how are you? hope fine and back. Could you get time to check the solution? thank
OK - after some further research, coding & testing, this is what I've concluded:

The function that gets the list of saved networks (WifiManager.getConfiguredNetworks()) is deprecated in API29 - so will always return an empty list. Because of that, you cannot get the networkId for any saved network you want to reconnect to. All you can do (in the library code) is provide the name of the network you want to connect to to the API & if the other details match a previously saved network (ie: SSID & password), it will present the user with a dialog asking them to confirm the connection. I guess the idea is that the app can connect to a network that is relevant to whatever it's doing, but can't arbitrarily just connect to any secure network it wants to.

So that's the bad news. The good news is that on Q+, if the device is already connected to a network, when your app closes (or you call disconnectWifiAP()) the device will disconnect from the network your app connected to & automatically reconnect to the previously connected network. So in the use case you described, you don't have to do anything to reconnect to the previous network. This behavior is different in P- devices where the device will remain connected to the network your app connected it to.

I'm still trying to get my head around how to implement connection to saved networks on P- devices, because they don't require the credentials like Q+ ones do. I'm thinking I might have to implement 2 functions - a reconnectWifiAP(timeout As Int) function for P- & the connectWifiAP(ssid As String, security As Int, password As String, timeout As Int) for Q+. The would leave it up to the B4A code to determine which one to call based on the SDK running on the device. Any better suggestions?

Btw - @hatzisn, I have fixed the isWifiConnected() issue. I'll release an update once I get the connect functions sorted.

- Colin.
 

Nitin Joshi

Active Member
Licensed User
Dear Colin, Thank you for feedback...
I am trying to suggest you the way, please check it is possible for not. Flow chart will be like this...

Function name. .connectWifiAP(ssid as String)
Inside this function....Identify API, if API is >27 then disable wifi -> enable wifi (disabling and enabling back will process as you have mentioned earlier, copied below.
on Q+, if the device is already connected to a network, when your app closes (or you call disconnectWifiAP()) the device will disconnect from the network your app connected to & automatically reconnect to the previously connected network.
else connect the WiFi to SSID which user wants to.....as credentials are not required for version P or API level 27 and before.

What you think? Otherwise, if we have to pass credentials then each APP must have database file to store the credentials which is unnecessary requirement of database file just for storing wifi credentials.

Regards,

Nitin
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Dear Colin, Thank you for feedback...
I am trying to suggest you the way, please check it is possible for not. Flow chart will be like this...

Function name. .connectWifiAP(ssid as String)
Inside this function....Identify API, if API is >27 then disable wifi -> enable wifi (disabling and enabling back will process as you have mentioned earlier, copied below.

else connect the WiFi to SSID which user wants to.....as credentials are not required for version P or API level 27 and before.

What you think? Otherwise, if we have to pass credentials then each APP must have database file to store the credentials which is unnecessary requirement of database file just for storing wifi credentials.

Regards,

Nitin

I don't really understand what you're trying to do here. In your earlier post you said you wanted to connect to an AP, then later connect back to the Wifi that the device was previously connected to. In Q+ (which is 29+ btw, P = 28), the device will automatically reconnect to the previous Wifi if you disconnect from the AP (ie: if you call disconnectWifiAP, or close the app).

- Colin.
 

Nitin Joshi

Active Member
Licensed User
In your earlier post you said you wanted to connect to an AP, then later connect back to the Wifi that the device was previously connected to.
Yes, still my requirement is same.

the device will automatically reconnect to the previous Wifi if you disconnect from the AP (ie: if you call disconnectWifiAP, or close the app).
You have recommended to disconnectWifiAP or close the APP.......I want APP to connect previously connected SSID without closing the APP (i.e. switch back to home/office wifi) so another available option is call disconnectWiFiAP. If i do so then i need to call back connectWifiAP which require credential and that is our problem.

Previously connected WiFi means home or office wifi whose SSID or other credentials are not changed frequently.
Does it mean, I need to add button in my app as "SAVE WIFI" to store credentials in local database? Actually, i need to avoid any database creation just for this purpose.

For P or earlier version, we can call connetWiFi and will pass credentials as you have mentioned earlier.
connectWifiAP("ssid", MLwifi.SECURITY_OPEN, "", timeout)


Looking for a solution for Q+ version.
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Yes, still my requirement is same.
[...]
If i do so then i need to call back connectWifiAP which require credential and that is our problem.

Previously connected WiFi means home or office wifi whose SSID or other credentials are not changed frequently.
Does it mean, I need to add button in my app as "SAVE WIFI" to store credentials in local database? Actually, i need to avoid any database creation just for this purpose.
[...]
No - as I said, Q+ devices will automatically reconnect to whatever network they were connected to before. Eg:

* App disconnects from current Wifi & connects to ESP8266 AP
* App does whatever with AP
* App disconnects from AP by calling disconnectWifiAP
* Device automatically connects to previously connected network (no action required from app)

Think of it like your app is temporarily "borrowing" the Wifi for its own use, then when it's done it hands it back to the device to reset itself to whatever Wifi state it was in beforehand.

- Colin.
 
Top