Отправить данные через wifi (нет интернета), когда мобильные данные на

Я разрабатываю и приложение, которое подключается к аппаратному устройству через wifi (генерируется устройством) и отправляет на него данные через сокет-соединение. Проблема в том, что при активации мобильных данных (3G/4G) android пытается отправить данные через него, а не отправлять их через wifi, генерируемый устройством, потому что wifi не имеет подключения к интернету. Я думал об использовании ConnectivityManager#setNetworkPreference() но он был устарел в в API 21.

Как я могу установить его для отправки данных с помощью wifi, генерируемого устройством вместо интерфейса мобильных данных?

2 ответов


Итак, чтобы сделать это на версиях, больших или равных леденцу, я сделал следующее:

  1. перед выполнением подключения сокета проверьте, если android больше или равен Lollipop, в случае, если это не вы просто делаете все, что угодно вы должны делать нормально;
  2. если версия равна или больше Lollipop, вам нужно сделать что-то вроде этого:

    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. после того, как вы закончите, вы должны прекратить связывать процесс с этим:

    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);
    }
    

этот ответ помог мне понять, как это сделать https://stackoverflow.com/a/29837637/2550932.


сеть переключится обратно на мобильный после setProcessDefaultNetwork в wifi, вы не можете отправлять большие данные таким образом, потому что все сокеты, созданные таким образом, перестанут работать. Я не нахожу идеальный способ сейчас, вот только для справки.

1.Если вы можете получить доступ root, сделайте это перед подключением к 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();

и удалить его после отправки данных:

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

2.Если вы можете получить WRITE_SECURE_SETTINGS разрешение:

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

или:

Settings.Global.putInt(getContentResolver(),"captive_portal_detection_enabled",0);