Подтвердить что ты не робот

Force Android использует Wi-Fi сеть без Интернета

Я создаю приложение для Android, которое должно связываться через сеть WiFi, у которой не будет доступа к Интернету. Проблема в том, что даже когда Wi-Fi подключен, android решает использовать сотовые/мобильные данные, если в сети Wi-Fi нет интернет-соединения.

Я прочитал много сообщений по проблеме, многие из которых связаны с укоренением устройства, но это невозможно с производственным приложением (укореняющие устройства не). другое решение (например, мой код ниже) предлагает использовать bindProcessToNetwork(), который отлично работает на моем Sony Z2, но не на других устройствах, на которых я тестировал (все работает 6.0.1)

private void bindToNetwork() {
    final ConnectivityManager connectivityManager = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkRequest.Builder builder;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder = new NetworkRequest.Builder();
        //set the transport type do WIFI
        builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
        connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


                    connectivityManager.bindProcessToNetwork(null);
                    if (barCodeData.getSsid().contains("screenspace")) {
                        connectivityManager.bindProcessToNetwork(network);
                    }

                } else {
                    //This method was deprecated in API level 23
                    ConnectivityManager.setProcessDefaultNetwork(null);
                    if (barCodeData.getSsid().contains("screenspace")) {

                        ConnectivityManager.setProcessDefaultNetwork(network);
                    }
                }

                connectivityManager.unregisterNetworkCallback(this);
            }
        });
    }
}
4b9b3361

Ответ 1

Не удалось установить глобальный параметр captive_portal_detection_enabled в значение 0 (false).

Что на самом деле происходит, так это то, что по умолчанию каждый раз, когда вы подключаетесь к Wi-Fi, FW будет протестировать сервер (как правило, google), чтобы увидеть, является ли он доступным wifi (требуется логин). Поэтому, если ваш Wi-Fi не подключен к Google, эта проверка завершится с ошибкой. После этого устройство знает, что Wi-Fi не имеет подключения к интернету и просто не будет автоподключиться к нему.

Установка этого параметра в 0, позволит избежать этой проверки.

Programatically: Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);

Изменить: вам может потребоваться использовать строку "captive_portal_detection_enabled" напрямую, а не константу, которая не отображается в зависимости от версии Android.

Ответ 2

вам нужно отключить мобильные данные в настройках (не обязательно, если это можно сделать программно, что может быть возможным) - или вывести USIM;

иначе обычное поведение заключается в том, что он всегда будет возвращаться к наилучшему доступному соединению (в то время как соединение с интернет-шлюзом может быть предпочтительным, поскольку оно используется большинством приложений).

также см. ответ .

Ответ 3

Вы можете проверить, подключено ли Wi-Fi, а затем еще раз показать диалоговое окно, в котором пользователь просит его подключиться к сети Wi-Fi.

Так как метод NetworkInfo.isConnected() теперь устарел в API-23, вот метод, который определяет, включен ли адаптер Wi-Fi, а также подключен к точке доступа с помощью WifiManager:

private boolean checkWifiOnAndConnected() {
    WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);

    if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON

        WifiInfo wifiInfo = wifiMgr.getConnectionInfo();

        if( wifiInfo.getNetworkId() == -1 ){
            return false; // Not connected to an access point
        }
        return true; // Connected to an access point
    }
    else {
        return false; // Wi-Fi adapter is OFF
    }
}

Ответ 4

Вы на правильном пути, решение действительно с ConnectivityManager.bindProcessToNetwork (сеть). Эта информация была опубликована в блоге разработчиков Android в этой статье: Подключение вашего приложения к устройству Wi-Fi.

В вашем коде этот barCodeData.getSsid() не смотрит, что он получает SSID текущей подключенной сети Wi-Fi. В этом случае ваш код никогда не будет успешно привязан к сети.

Попробуйте заменить ваше выражение if

if (barCodeData.getSsid().contains("screenspace"))

С

if (getNetworkSsid(context).equals("screenspace"))

Вспомогательный метод в kotlin для получения SSID подключенной сети Wi-Fi

private fun getNetworkSsid(context: Context?): String {
    // WiFiManager must use application context (not activity context) otherwise a memory leak can occur
    val mWifiManager = context?.applicationContext?.getSystemService(Context.WIFI_SERVICE) as WifiManager
    val wifiInfo: WifiInfo? = mWifiManager.connectionInfo
    if (wifiInfo?.supplicantState == SupplicantState.COMPLETED) {
        return wifiInfo.ssid.removeSurrounding("\"")
    }
    return ""
}

Если все еще не работает, пожалуйста, следуйте моему полному решению, где я использовал тот же метод, но с некоторыми дополнительными проверками. Я тестировал его в версиях Android 5.1.1, 6.0, 6.0.1, 7.1.1 и 8.1.0.

Ответ 5

Решение по Котлину

class ConnectWithoutInternetTest constructor(
private val mContext: Context,
private val connectivityManager: ConnectivityManager,
private val wifiManager: WifiManager
) {

private val mWifiBroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
                val info = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO)
                val isConnected = info.isConnected

                val ssid: String? = normalizeAndroidWifiSsid(wifiManager.connectionInfo?.ssid)

                if (isConnected) {
                    val builder = NetworkRequest.Builder()
                    builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    connectivityManager.registerNetworkCallback(
                        builder.build(),
                        object : ConnectivityManager.NetworkCallback() {
                            override fun onAvailable(network: Network) {
                                super.onAvailable(network)
                                val networkInfo = connectivityManager.getNetworkInfo(network)
                                val networkSsid = networkInfo.extraInfo
                                if (networkSsid == ssid) {
                                    connectivityManager.unregisterNetworkCallback(this)
                                }
                            }
                        })
                }
            }
        }
    }
}

private fun init() {
    val intentFilter = IntentFilter()
    intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
    mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter)
}

private fun destroy() {
    mContext.unregisterReceiver(mWifiBroadcastReceiver)
}

private fun normalizeAndroidWifiSsid(ssid: String?): String? {
    return ssid?.replace("\"", "") ?: ssid
}

fun connectToWifi(ssidParam: String, password: String?) {
    init()
    val ssid = "\"$ssidParam\""
    val config = wifiManager.configuredNetworks.find { it.SSID == ssid }
    val netId = if (config != null) {
        config.networkId
    } else {
        val wifiConfig = WifiConfiguration()
        wifiConfig.SSID = ssid
        password?.let { wifiConfig.preSharedKey = "\"$password\"" }
        wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
        wifiManager.addNetwork(wifiConfig)
    }

    wifiManager.disconnect()
    val successful = wifiManager.enableNetwork(netId, true)
}