I'm working on a project which need to connect to a Wi-Fi in a background service, the service running when the device is screen off.
The connecting code is like below:
public boolean connect_android(String ssid) {
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
boolean find = false;
for( WifiConfiguration i : list ) {
if(i.SSID != null && i.SSID.equals("\"" + ssid + "\"")) {
wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
find = true;
break;
}
}
while after the connecting code is executed in the background running service, the device never connect to the Wi-Fi successfully until the screen is turned on. I logged the supplicant state, it is in complete state. As the google docs says:
This state indicates that the supplicant has completed its processing for the association phase and that data connection is fully configured. Note, however, that there may not be any IP address associated with the connection yet. Typically, a DHCP request needs to be sent at this point to obtain an address.
So can i come to the conclusion that, when the screen is turned on, a DHCP request is send the device receives an IP and the connection is complete successfully. But who is in charge of sending the DHCP, the wpa_supplicant or Android framework, is there any docs about this? How can i connect to a Wi-Fi AP without turn on the screen? Thanks in advance!
Maybe because your device use feature turn of wifi when screen of (Settings -> Wireless and network -> WiFi settings -> (menu button) Advanced -> Wifi sleep policy)
Your app will cannot connect to network
Related
My app needs to use a wifi network (without internet, thus android avoids it by default). And I want it to be simple to use (like Grandma doesn't have to be manually changing settings). This is just an personal IoT device so I want to use ConnectivityManager.BindProcessToNetwork(Android.Net.Network network). How do I get the Android.Net.Network associated with the currently connected wifi network so I can use BindProcessToNetwork?
//c#(Xamarin)
//my rudimentary attempt to get the connected wifi network:
var networks = ConnectivityManager.GetAllNetworks();
foreach (Network network in networks) {
NetworkCapabilities networkCability =ConnectivityManager.GetNetworkCapabilities(network);
if (networkCability.HasTransport(TransportType.Wifi))
{
currentWifiNetwork = network; // this is never reached
}
}
ConnectivityManager.BindProcessToNetwork( currentWifiNetwork );
Is there not a distinct Network object for all the phones currently in use WiFi, cellular, etc... networks?
This blog got me close: https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html.
A binding socket method would work too (except the wifi network isn't an available network until the use network without internet box is checked). I just need to the App to use urls that are on port 8080 via the wifi.
I want to avoid having to manually telling Android to "use the network with no internet".
Cheers
Update
When I run this, there are only two Networks returned by ConnectivityManager.GetAllNetworks(), and looking at them in the debugger, one is the Cellular network with internet and mms, and the other is another Cellular network without internet and mms. So no ConnectivityManager.GetAllNetworks() doesn't get the wifi network as it appears android won't even add the wifi network unless it has internet! If the phones data is disabled Android will switch and use the internet-less wifi for all traffic (without having to check use the network anyways box).So their must be a way to get the WiFi network bound to the app! or...
How does one programmatically check the use network anyways box!?
I have not seen a solution to this. Just a bunch of open questions all over the web. At this rate I might just use dnsmasq on the iot device and a spoofing web server to make android think it has internet.
I also see that API 29 has NetworkBuilder and that you can specify a request for a WiFi network without internet capabilities...but I need lower API support.
Update:
Android now supports requesting local only wifi networks (networks without the NetworkCapabilities#NET_CAPABILITY_INTERNET capability) check out :
https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder
Original Answer:
This is the solution that I came up with (for Api 28 ). It prioritizes WiFi over 4G/5G (Data) regardless of internet capability via a NetworkRequest, and then allows for both internet over 4G/5G (Data) and the app to use its local WiFi services:
public static WifiManager WifiManager { get; } = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
public static ConnectivityManager ConnectivityManager { get; set; } = (ConnectivityManager)Android.App.Application.Context.GetSystemService(Context.ConnectivityService);
public bool ConnectToWifi(string ssid, string password, bool previouslyConnected = true)
{
if (!WifiManager.IsWifiEnabled)
WifiManager.SetWifiEnabled(true); //turn on wifi if not on
var formattedSsid = $"\"{ssid}\"";
var formattedPassword = $"\"{password}\"";
var wifiConfig = new WifiConfiguration
{
Ssid = formattedSsid,
PreSharedKey = formattedPassword,
Priority = 0
};
_NetworkId = WifiManager.AddNetwork(wifiConfig);
WifiManager.Disconnect();
bool enableNetwork = WifiManager.EnableNetwork(_NetworkId, true);
NetworkRequest.Builder builder = new NetworkRequest.Builder(); //request that WiFi be prioritized over the 4G internet capable network.
builder.AddTransportType(TransportType.Wifi);
ConnectivityManager.RequestNetwork(builder.Build(), new BindNetworkCallBack ());
return enableNetwork;
}
This call back then binds the appropriate WIFI network to the app(process)! Allowing for the user to both simultaneously use the app with the local server over WIFI, and other apps that still require internet, as Android OS can allow other processes to access the internet via the 4G/5G data connection!
public class BindNetworkCallBack : ConnectivityManager.NetworkCallback
{
public override void OnAvailable(Network network)
{
if (WifiManager.ConnectionInfo.BSSID == NetworkBSSID) /*
The only way on Android (API 28+) to check if the acquired network is
the one you want is to use the BSSID (MAC address) of the network.
You can omit the if statement if you want to presume the acquired network is correct/
cannot know the MAC address...
*/
{
try
{
ConnectivityManager.BindProcessToNetwork(network);
}
catch (Exception ex)
{
Debug.WriteLine(#"\tERROR Unable to Bind process to network {0}", ex.Message);
}
}
}
}
"bindProcessToNetwork Binds the current process to network. All Sockets created in the future (and not explicitly bound via a bound SocketFactory from Network.getSocketFactory()) will be bound to network. All host name resolutions will be limited to network as well." - Android Docs
I am experiencing a strange behavior in my Android app: Every time I connect programmatically to a WiFi network (source see below), first it works as intended, but after a couple of seconds (between 5 and around a minute) the connection is dropped and the device tries to connect to another network.
If I, however, connect to the same network manually (i.e. through Android's Settings App), everything works as intended and the device stays connected to the AP (I have cleared the WifiConfiguration-list, so there is only occurrence of the desired SSID).
Here is the relevant part of the code I use to connect to the network:
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
String ssid = "NameOfAP";
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for (WifiConfiguration i : list) {
if (i.SSID != null && i.SSID.equals("\"" + ssid + "\"")) {
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
break;
}
}
Some additional info:
Lenovo Yoga Tablet 2 with Android 5.0.1 (since it is an in-house app which only runs on this device)
The network is not connected to the internet (though the captive portal detection flag is set to disabled/0)
I have tried to look at Android's code in Lollipop, but they are using wifiManager.connect(), which I somehow cannot access.
Any help appreciated!
I am creating an app, which can list out all the available wifi's in a ListView. If I select one of the wifi's in the list, which was cached before in List<WifiConfiguration> list = wifiManager.getConfiguredNetworks(); then it should connect to it. If the WifiConfiguration list doesn't contain the selected wifi, then nothing happens. My problem is, that sometimes I select a wifi from the list (which I know for sure is in the WifiConfiguration list), but it doesn't connects to it. Instead it connects back to the previously connected wifi. After some attempts (selecting again and again the same wifi) it connects to it finally. This doesn't happen always, just sometimes. What can be the problem? Here is my code snippet:
// Go through all the cached wifis and check if the selected GoPro was cached before
for (WifiConfiguration config : configurations) {
// If it was cached connect to it and that's all
if (config.SSID != null && config.SSID.equals("\"" + mDrawerListView.getAdapter().getItem(position) + "\"")) {
// Log
Log.i("onReceive", "Connecting to: " + config.SSID);
mWifiManager.disconnect();
mWifiManager.enableNetwork(config.networkId, true);
mWifiManager.reconnect();
break;
}
}
This is what's going on. Basically, you can tell the OS to disable a network, and you can tell the OS to enable a network, but it's not possible to tell the OS what network to connect to.
If there are multiple WiFi access points in range that are both configured on the device (and both are in the enabled state), the OS will decide which one to connect to.
The only way to force the OS to connect to one of the networks in range instead of the other one is to call disableNetwork() on the network that is in range that you don't want to connect to.
Let's go through your code line by line:
mWifiManager.disconnect();
The line above tells the OS to disconnect from the currently connected WiFi access point.
mWifiManager.enableNetwork(config.networkId, true);
The line above tells the device to set the network to the enabled state if it was previously in the disabled state.
mWifiManager.reconnect();
From the documentation:
Reconnect to the currently active access point, if we are currently
disconnected. This may result in the asynchronous delivery of state
change events.
So, when you say Instead it connects back to the previously connected wifi., it's working exactly as expected, as the OS is re-connecting to what it considers the currently active access point.
If you really want to disable the other network so that the OS will connect to the one you just clicked on, you could do something like this:
// Go through all the cached wifis and check if the selected GoPro was cached before
WifiInfo info = mWifiManager.getConnectionInfo(); //get WifiInfo
int id = info.getNetworkId(); //get id of currently connected network
for (WifiConfiguration config : configurations) {
// If it was cached connect to it and that's all
if (config.SSID != null && config.SSID.equals("\"" + mDrawerListView.getAdapter().getItem(position) + "\"")) {
// Log
Log.i("onReceive", "Connecting to: " + config.SSID);
mWifiManager.disconnect();
mWifiManager.disableNetwork(id); //disable current network
mWifiManager.enableNetwork(config.networkId, true);
mWifiManager.reconnect();
break;
}
}
Hi instead of disabling the previous network , you can change the priority of the network you to connect to greater than all other configured networks and then when you reconnect() . it will connect to the highest priority network in range.
wificonfig.priority = 10000;
wifiManager.updateNetwork(wificonfig);
wifiManager.saveConfiguration();
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, false);
wifiManager.reconnect();
I am working on an android application which involves connecting to a specific wifi when in range. Once I am done doing some stuff, I am trying to connect back to my original wifi. For some strange reason, it connects to my original wifi as I want it to, but after about 30 seconds or so, it drops the connection. When I check my wifi settings on the device it shows that wifi as disabled.
To sum up:
1. Connect to Wifi W1.
2. When Wifi W2 is in range, connect to that (using the SSID) but, remember the SSID of W1 for later.
3. Disconnect from W2 and look for W1 in wificonfiguration list (using SSID). When found, connect to that.
All three steps are working, but for some reason, a short while after step 3 succeeds (< 1 minute)the connection to W1 is dropped and disabled by the device. This only happens when I change wifi connections through code. Here's what my code looks like:
the 'net' variable contains the SSID value of the original wifi connection's SSID (W1). Does anyone have any idea why I would be dropping connection shortly after reconnecting to the original Wifi?
if(net!=""){
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for( WifiConfiguration i : list ) {
if(i.SSID != null && i.SSID.contains(net)) {
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, true);
wifiManager.setWifiEnabled(true);
break;
}
}
}
I have a suggestion which I am not sure if this is going to solve the problem or not but it would be worth trying
in the below code if you place
if(net!=""){
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for( WifiConfiguration i : list ) {
if(i.SSID != null && i.SSID.contains(net)) {
wifiManager.disconnect();
//place a sleep on thread so that the underlying hardware gets some time to disconnect
Thread.sleep(10000);
//Now trying connecting to the previous network. Also try increasing the time to wait if 5 seconds is not working.
wifiManager.enableNetwork(i.networkId, true);
wifiManager.setWifiEnabled(true);
break;
}
}
}
EDIT:
It seems to work with the interval more than 10seconds. This time interval is i think dependent on the WiFi Chipset of the device, it needs some time to disconnect from the current network and to be connected to other. Also If the device has a low quality chipset then it might take longer Also I reckon if the device has a high quality chipset then it will be much quicker..
I have an android app that tried to connect to a website in an AsyncTask and perform some tasks. My application always seems to crash when there is a change in the network connection i.e The app is connected to a wifi network initially, but loses connection and switches to mobile network. When this happens my Android Application crashes. My code is surrounded within a try catch block, so I'm not sure why the application would crash ? How do I fix my problem ?
Thanks!
WifiInfo info = WifiManager.getConnectionInfo();
if (info.getSSID() != null) {
String ssid = info.getSSID();
...
}
I don't know if it would be overkill to write:
if (info != null && info.getSSID() != null)
Also, the BroadcastReceiver that I need to monitor when a connection is made is WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION. It turns out that I had a copy and paste error in my onResume(), and I wasn't really registering WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.
or u can use following link
Android: How to Enable/Disable Wifi or Internet Connection Programmatically
You have to make sure you wait for a network connectivity to be available before continuing your websites connections.
Plus, be aware that if you try to enable a mobile connection without disabling WiFi beforehand, the Android system will automatically shutdown the newly enabled mobile connection (it gives priority to WiFi to sum up). So you need to make sure you do it in the right order :
(WiFi enabled)
(WiFi ready)
Websites connections STARTED
Websites connections STOPPPED
(WiFi disabled)
(WiFi unavailable)
(Mobile enabled)
(Mobile ready)
Websites connections RESUMED