androidsocketswifinetwork-interface

Send data through wifi (no internet) when mobile data on


I'm developing and application that connects to a hardware device through wifi (generated by the device) and send data to it through a socket connection. The problem is that when mobile data (3G/4G) is activated android tries to send the data through it instead of sending it through the wifi generated by the device, because because the wifi has no internet connection. I was thinking of using ConnectivityManager#setNetworkPreference() but it has been deprecated in api 21.

How can I set it to send data using the wifi generated by the device instead of the mobile data interface?


Solution

  • After a lot of research and time trying to understand it all I found out that this isn't possible in versions previous to Android 5.0 (Lollipop), the OS only keeps one network interface up at a time and the apps don't have control over this.

    So to do this on versions greater or equal to the Lollipop I did the following:

    1. Before doing your socket connection check if android greater or equal to Lollipop, in case it isn't you just do whatever you have to do normally;
    2. In case the version is equal or greater to Lollipop you need to do something like this:

      if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
          final ConnectivityManager manager = (ConnectivityManager) context
                  .getSystemService(Context.CONNECTIVITY_SERVICE);
          NetworkRequest.Builder builder;
          builder = new NetworkRequest.Builder();
          //set the transport type do WIFI
          builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
          manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
              @Override
              public void onAvailable(Network network) {
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                      manager.bindProcessToNetwork(network);
                  } else {
                      //This method was deprecated in API level 23
                      ConnectivityManager.setProcessDefaultNetwork(network);
                  }
                  try {
                      //do a callback or something else to alert your code that it's ok to send the message through socket now
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  manager.unregisterNetworkCallback(this);
              }
          });
      }
      
    3. After you finish you should stop binding the process with this:

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          ConnectivityManager manager = (ConnectivityManager) InovePlugApplication.getContext()
                  .getSystemService(Context.CONNECTIVITY_SERVICE);
          manager.bindProcessToNetwork(null);
      } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          ConnectivityManager.setProcessDefaultNetwork(null);
      }
      

    This answer helped me unsderstand how to do it https://stackoverflow.com/a/29837637/2550932.