Отправить данные через Wi-Fi (без интернета), когда мобильные данные на
Я разрабатываю и приложение, которое подключается к аппаратному устройству через Wi-Fi (генерируется устройством) и отправляет данные на него через сокет-соединение. Проблема в том, что при активации мобильных данных (3G/4G) Android пытается отправить данные через него, а не через Wi-Fi, сгенерированный устройством, потому что Wi-Fi не имеет подключения к Интернету. Я думал об использовании ConnectivityManager#setNetworkPreference(), но это устарело в API 21.
Как я могу настроить его для отправки данных, используя Wi-Fi, сгенерированный устройством вместо мобильного интерфейса данных?
2 ответа
После долгих исследований и попыток понять все это я обнаружил, что это невозможно в версиях, предшествующих Android 5.0 (Lollipop), ОС поддерживает только один сетевой интерфейс за раз, а приложения не имеют контроля через это.
Таким образом, чтобы сделать это на версиях, больших или равных Lollipop, я сделал следующее:
- Перед выполнением подключения к сокету проверьте, больше ли Android или равен Lollipop, если это не вы просто делаете то, что обычно делаете;
Если версия 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); } }); }
После того, как вы закончите, вы должны прекратить связывать процесс с этим:
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); }
Этот ответ помог мне понять, как это сделать /questions/15331294/kak-ostavatsya-na-svyazi-cherez-mobilnuyu-set-posle-podklyucheniya-wifi-na-android/15331302#15331302.
Сеть переключится обратно на мобильную сеть после того, как setProcessDefaultNetwork перейдет на Wi-Fi. Таким способом невозможно отправить большие данные, поскольку все созданные таким образом сокеты перестанут работать. Я не нахожу идеальный способ сейчас, здесь только для справки.
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);