Using a WiFi without Internet Connection
Asked Answered
T

3

6

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

Toxicant answered 19/2, 2017 at 16:29 Comment(2)
Hi @YYjo have you got an answer for this question?Sisto
@KenRatanachaiS. Unfortunately not. As far as I can tell it just doesn't work well on android.Toxicant
T
3

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;
   }
});
Tenishatenn answered 11/9, 2017 at 22:9 Comment(3)
Where are you getting that socket variable from?Broaden
it is throwing java.net.SocketException: Socket is connected while we trying to bindSocketSpoliation
Did anyone ever figure out where he got that socket variable from? Or is it just an arbitrary variable?Pelite
F
3

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.

Fuddyduddy answered 30/12, 2019 at 21:11 Comment(0)
D
1

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.

Dunham answered 22/7, 2018 at 23:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.