Reputation: 1724
In my app I am connecting to a device that has it's own WiFi network. In android 6 and above the system asks me after a few seconds if I want to connect to this network even though there is no internet connection. Only after approving that message I can connect to my device. I tried connecting to the network programmatically and not force the user to go to his settings and connect manually every time. I used the following code to connect to the devices network:
private void connectToWiFi(WifiManager wifiManager, String wifiName) {
WifiConfiguration configuration = new WifiConfiguration();
configuration.SSID = "\"" + wifiName + "\"";
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wifiManager.addNetwork(configuration);
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for (WifiConfiguration i : list) {
if (i.SSID != null && i.SSID.equals("\"" + wifiName + "\"")) {
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
break;
}
}
}
and also trying to force the app to use the WiFi connection and not the cellular data I am using :
NetworkRequest.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
String ssid = wifiManager.getConnectionInfo().getSSID();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(null);
if (ssid.equals("\"" + Prefs.getWifiName(PUFMainActivity.this) + "\"")) {
connectivityManager.bindProcessToNetwork(network);
connectivityManager.unregisterNetworkCallback(this);
}
}
}
});
}
Although as long as the Cellular data is active the device doesn't apear to be connected. If I disable the Cellular data then it works fine. I need to know if there is a way to do what I want programmatically without telling the user to disable his Cellular data.
Thanks
Upvotes: 6
Views: 10086
Reputation: 31
For those still attempting to figure this out, based on the
wifiNetwork.bindSocket(socket)
provided by @MayconPrado
Yes, that socket variable was declared ahead of time. That answer assumes you are sending UDP or TCP packets over the network.
The partial but more complete code would look something along the lines of
val socket = DatagramSocket(somePortNumber)
wifiNetwork.bindSocket(socket)
val udpPacket = DatagramPacket(/** args specific to use case **/)
socket.send(udpPacket)
Would have commented this, but I have never posted to SO, so I have 1 rep ATM.
Upvotes: 3
Reputation: 4279
Your code looks correct from Marshmallow onwards but be aware that your solution doesn't work in Lollipop (API levels 21 and 22).
The problem can be because you may being trying to force the app to use the WiFi connection AFTER connecting the WiFi network.
You need to set the NetworkCallback BEFORE changing to the WiFi network you want to have the communications over WiFi only. This is because once you connected to the desired network onAvailable() will be invoked and the bindProcessToNetwork() will be executed.
Consider look into my complete solution where I used the same method but also supports Lollipop. I tested it in the Android versions 5.1.1, 6.0, 6.0.1, 7.1.1 and 8.1.0.
Upvotes: 1
Reputation: 62
Although as long as the Cellular data is active the device doesn't apear to be connected. If I disable the Cellular data then it works fine.
I was facing a similar problem. The default solution didn't work for me so I used the bindSocket
method from Network
class, and apparently it is working just fine. I don't know if this solution applies to your problem, but here's some code:
ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] networks = connectivityManager.getAllNetworks();
for(Network network : networks){
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI){
wifiNetwork = network; // Grabbing the Network object for later usage
}
}
and after the socket:
if(android.os.Build.VERSION.SDK_INT >= 22) {
wifiNetwork.bindSocket(socket);
}
UPDATE:
You can use a NetworkCallback
to grab the Network
object as well.
NetworkRequest.Builder builder;
builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
wifiNetwork = network;
}
});
Upvotes: 3