web-dev-qa-db-fra.com

Forcer Android à utiliser le réseau Wifi sans Internet

Je construis une application Android qui doit communiquer sur un réseau WiFi sans accès Internet. Le problème est que même lorsque le WiFi est connecté, Android choisit d'utiliser des données cellulaires/mobiles lorsqu'aucune connexion Internet n'est présente sur le réseau wifi.

J'ai lu de nombreux articles sur le sujet, dont beaucoup impliquent l'enracinement de l'appareil, mais ce n'est pas possible avec une application de production (l'enracinement de périphériques est pas une option). Une autre solution (comme mon code ci-dessous) suggère d’utiliser bindProcessToNetwork() qui fonctionne parfaitement sur mon Sony Z2 mais pas sur les autres appareils sur lesquels j’ai testé (tous fonctionnant sous la version 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);
            }
        });
    }
}
25
Lonergan6275

Pourriez-vous essayer de définir le paramètre global captive_portal_detection_enabled sur 0 (false).

Ce qui se passe réellement, c'est que par défaut, chaque fois que vous vous connectez à un réseau wifi, le FW effectuera un test sur un serveur (généralement Google) pour voir s'il s'agit d'un réseau wifi captif (nécessite une connexion). Donc, si votre wifi n'est pas connecté à google, cette vérification échouera. Après cela, l'appareil sait que le wifi ne dispose pas d'une connexion Internet et ne pourra tout simplement pas s'y connecter automatiquement.

Régler ce paramètre sur 0 évitera cette vérification.

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

Édition: vous devrez peut-être utiliser la chaîne "captive_portal_detection_enabled" directement, au lieu de la constante non visible selon la version d'Android.

2
lax1089

Vous pouvez vérifier si le wifi est connecté puis continuer sinon afficher une boîte de dialogue à l'utilisateur lui demandant de se connecter à un réseau wifi

Puisque la méthode NetworkInfo.isConnected () est maintenant obsolète dans API-23, voici une méthode qui détecte si l'adaptateur Wi-Fi est activé et également connecté à un point d'accès à l'aide de 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
    }
}
1
Akshay Sood

vous devez désactiver les données mobiles dans les paramètres (pas certain, si cela peut être fait par programme, ce qui pourrait être une option possible) - ou supprimer l'USIM;

sinon, le comportement habituel est qu’elle aura toujours recours à la meilleure connexion disponible (alors qu’une connexion avec une passerelle Internet peut être préférable, car elle est utilisée par la plupart des applications).

voir aussi cette réponse .

1
Martin Zeitler

Vous êtes sur le bon chemin, la solution est bien avec ConnectivityManager.bindProcessToNetwork (network) . Cette information a été publiée sur le blog des développeurs Android dans cet article: Connexion de votre application à un périphérique Wi-Fi .

En examinant votre code, barCodeData.getSsid() n'a pas l'air d'obtenir le SSID du réseau wifi actuellement connecté. Si tel est le cas, votre code ne pourra jamais être lié au réseau.

Essayez de remplacer votre si déclaration

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

Avec

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

Méthode d'assistance dans kotlin pour récupérer le SSID du réseau wifi connecté

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 ""
}

Si cela ne fonctionne toujours pas, veuillez suivre ma solution complète où j'ai utilisé la même méthode, mais avec quelques vérifications supplémentaires. Je l'ai testé dans les versions Android 5.1.1, 6.0, 6.0.1, 7.1.1 et 8.1.0.

0
Ryan Amaral

Solution sur Kotlin

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)
}
0
Vados