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

感情迁移 提交于 2019-12-02 18:53:34
hygorxaraujo

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.

Network will switch back to mobile after setProcessDefaultNetwork to wifi, you can't send large data by this way, because all sockets created in this way will cease to work. I don't find a perfect way now, here is for reference only.

1.If you can get root access, do this before connect to wifi:

Process process = runtime.exec("su");
DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream());
dataOutputStream.writeBytes("settings put global captive_portal_server 127.0.0.1\n");
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
int status = process.waitFor();

And delete it after you send data:

dataOutputStream.writeBytes("settings delete global captive_portal_server\n");

2.If you can get WRITE_SECURE_SETTINGS permission:

Settings.Global.putString(getContentResolver(),"captive_portal_server","127.0.0.1");

Or:

Settings.Global.putInt(getContentResolver(),"captive_portal_detection_enabled",0);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!