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);
}
});
}
}
Ответы
Ответ 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)
}