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);
}
});
}
}
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.
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
}
}
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 .
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.
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)
}