Отправка данных через Wi-Fi (без Интернета), когда мобильные данные включены

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

Как я могу настроить отправку данных с использованием Wi-Fi, генерируемого устройством, вместо мобильного интерфейса передачи данных?


person hygorxaraujo    schedule 02.02.2016    source источник


Ответы (2)


После долгих исследований и времени, пытаясь понять все это, я обнаружил, что это невозможно в версиях, предшествующих Android 5.0 (Lollipop), ОС поддерживает только один сетевой интерфейс за раз, и приложения не имеют контроля. через это.

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

  1. Прежде чем выполнять подключение к сокету, проверьте, больше ли андроид или равен 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.

person hygorxaraujo    schedule 12.03.2016
comment
Вам понадобится <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> в вашем манифесте, чтобы это работало. - person AppleGrew; 17.09.2016
comment
@hygorxaraujo Я использую ваш код, но он не работает для Android Nougat. Я делаю manager.bindProcessToNetwork(сеть) для Marshamallow и выше. есть ли обходной путь? - person Satpal Yadav; 23.06.2017
comment
@satpal002 извините, я использовал этот код только до Android Marshmallow (и у меня нет устройства с Nougat, чтобы проверить его). Я не заметил никаких изменений в API, чтобы он перестал работать developer.android .com/reference/android/net/. В предыдущих версиях (выше Lollipop) работает нормально? - person hygorxaraujo; 24.06.2017
comment
да, он отлично работает в marshamallow, но на нуге: я отправляю сообщение сокета на ip, затем выдается исключение, что сеть недоступна (мобильные данные включены, а также устройство подключено к Wi-Fi, и этот ip доступны в той же сети Wi-Fi). - person Satpal Yadav; 26.06.2017

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

1.Если вы можете получить root-доступ, сделайте это перед подключением к Wi-Fi:

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

Or:

Settings.Global.putInt(getContentResolver(),"captive_portal_detection_enabled",0);
person MADAO    schedule 12.03.2016
comment
Привет @MADAO, спасибо за ответ, я думаю, ты тоже прав. Я уже нашел ответ на этот вопрос и забыл обновить вопрос здесь. - person hygorxaraujo; 12.03.2016