Comment détecter lorsque la connexion WIFI a été établie sous Android?


140

J'ai besoin de détecter quand j'ai une connectivité réseau via WIFI. Quelle diffusion est envoyée pour établir qu'une connexion réseau valide a été établie. Je dois valider qu'une connexion réseau valide pour HTTP existe. Que dois-je écouter et quels tests supplémentaires dois-je faire pour savoir qu'une connexion valide existe.


Certaines parties de cette question ont été répondues ici, j'ai trouvé: stackoverflow.com/questions/4238921/…
Androider

1
Mais il reste la question de savoir QUAND vérifier ces conditions?
Androider

1
Je voudrais savoir si des diffusions se produiront et pourraient être captées par un récepteur de diffusion?
Androider

1
Comment puis-je faire cela sur Android O car les récepteurs de diffusion implicites tels que android.net.wifi.STATE_CHANGE ne seront plus autorisés à être enregistrés dans le manifeste (voir developer.android.com/guide/components/… ). Si nous l'enregistrons dans l'activité de l'application (disons onCreate), alors il devra être désenregistré dans onStop (), et nous ne recevrons plus d'événements liés au wifi
zafar142003

Réponses:


126

Vous pouvez enregistrer un BroadcastReceiverpour être averti lorsqu'une connexion WiFi est établie (ou si la connexion a changé).

Enregistrez le BroadcastReceiver:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);

Et puis dans votre BroadcastReceiverfaire quelque chose comme ceci:

@Override
public void onReceive(Context context, Intent intent) {
    final String action = intent.getAction();
    if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
        if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
            //do stuff
        } else {
            // wifi connection was lost
        }
    }
}

Pour plus d'informations, consultez la documentation sur BroadcastReceiveretWifiManager

Bien sûr, vous devez vérifier si l'appareil est déjà connecté au WiFi avant cela.

EDIT: Grâce à ban-geoengineering, voici une méthode pour vérifier si l'appareil est déjà connecté:

private boolean isConnectedViaWifi() {
     ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
     NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
     return mWifi.isConnected();
}

1
Pourquoi SUPPLICANT_CONECTION_CHANGE_ACTION? Je pensais que c'était JUST CONNECTION_CHANGE diffusion de changement. Pourquoi SUPPLCANT ??? merci
Androider

2
hein? Je ne vois pas une action appelée connection_change ...? Je ne vois que l'état du wifi changé mais cette action indique seulement si le wifi est activé ou non (ou activé / désactivé) pas s'il est connecté ... est-ce que supplicant_connection_change_action ne fait pas ce dont vous avez besoin?
jpm

9
Pour moi, WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION ne fonctionne pas dans le cas où la connexion à une station wifi connue a été établie / perdue. Mais WifiManager.NETWORK_STATE_CHANGED_ACTION fonctionne.
Yar

1
"android.net.wifi.STATE_CHANGE" a fonctionné pour moi. vérifier ma réponse ci
M. Usman Khan

1
"Bien sûr, vous devriez vérifier si l'appareil est déjà connecté au WiFi avant cela." - donc, pour obtenir l'état initial du Wi-Fi, vous pouvez utiliser cette méthode ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
ban-geoengineering

106

Le meilleur qui a fonctionné pour moi:

AndroidManifest

<receiver android:name="com.AEDesign.communication.WifiReceiver" >
   <intent-filter android:priority="100">
      <action android:name="android.net.wifi.STATE_CHANGE" />
   </intent-filter>
</receiver>

Classe BroadcastReceiver

public class WifiReceiver extends BroadcastReceiver {

   @Override
   public void onReceive(Context context, Intent intent) {

      NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
      if(info != null && info.isConnected()) {
        // Do your work. 

        // e.g. To check the Network Name or other info:
        WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        String ssid = wifiInfo.getSSID();
      }
   }
}

Autorisations

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

1
Je pense que c'est la meilleure réponse pour le chage spécifiquement de l'état du wifi. Merci
Mikel

4
Pour une référence future, cette action codée en dur est WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage

3
if (info! = null && info.isConnected ()) = pas de spaghetti.
gswierczynski

1
devons-nous écrire un code pour envoyer la diffusion dans l'activité principale?
Nisari Balakrishnan

1
Comment puis-je faire cela sur Android O car les récepteurs de diffusion implicites tels que android.net.wifi.STATE_CHANGE ne seront plus autorisés à être enregistrés dans le manifeste (voir developer.android.com/guide/components/… ). Si nous l'enregistrons dans l'activité de l'application (disons onCreate), alors il devra être désenregistré dans onStop (), et nous ne recevrons plus d'événements liés au wifi.
zafar142003

18

Pour moi ne WifiManager.NETWORK_STATE_CHANGED_ACTIONfonctionne que.

Enregistrer un récepteur de diffusion:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(broadcastReceiver, intentFilter);

et recevez:

@Override
public void onReceive(Context context, Intent intent) {

    final String action = intent.getAction();

    if(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
        NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
        boolean connected = info.isConnected();

        //call your method
    }      
}

1
Pour moi aussi, seul WifiManager.NETWORK_STATE_CHANGED_ACTION a fonctionné, des explications sur la raison pour laquelle seul cela fonctionnera?
benchuk

11

Les réponses données par l'utilisateur @JPM et @usman sont vraiment très utiles. Cela fonctionne bien mais dans mon cas, cela arrive onReceiveplusieurs fois dans mon cas 4 fois, donc mon code s'exécute plusieurs fois.

Je fais quelques modifications et fais selon mes besoins et maintenant cela ne vient qu'une fois

Voici la classe java pour Broadcast.

public class WifiReceiver extends BroadcastReceiver {

String TAG = getClass().getSimpleName();
private Context mContext;

@Override
public void onReceive(Context context, Intent intent) {

    mContext = context;


    if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {

        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();

        if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
                networkInfo.isConnected()) {
            // Wifi is connected
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            String ssid = wifiInfo.getSSID();

            Log.e(TAG, " -- Wifi connected --- " + " SSID " + ssid );

        }
    }
    else if (intent.getAction().equalsIgnoreCase(WifiManager.WIFI_STATE_CHANGED_ACTION))
    {
        int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
        if (wifiState == WifiManager.WIFI_STATE_DISABLED)
        {
            Log.e(TAG, " ----- Wifi  Disconnected ----- ");
        }

    }
}
}

Dans AndroidManifest

<receiver android:name=".util.WifiReceiver" android:enabled="true">
        <intent-filter>
            <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
        </intent-filter>
    </receiver>


<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

1
qu'est-ce que wifiState?
behelit

1
Voudrait également savoir ce qu'est wifiState, comment il a été généré
Evan Parsons

1
@behelit maintenant "wifiState" est là dans la réponse éditée.
Yog Guru

8

Vous pouvez démarrer une connexion wifi si vous donnez à l'utilisateur le choix de remplacer le comportement normal consistant à demander à chaque fois.

J'ai choisi d'utiliser trois méthodes ...

public boolean isOnline() 
{
 ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
 NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
 return (networkInfo != null && networkInfo.isConnected());
}  

Il s'agit de vérifier rapidement s'il existe une connexion Internet Wifi ou CellData. De là, vous pouvez choisir l'action que vous souhaitez entreprendre. Est-il en mode avion doit également être vérifié.

Sur un fil séparé. J'ai mis une variable IpAddress à = "" Et interroger jusqu'à ce que j'aie une adresse IP valide.

  WifiManager wifi;
  wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
  WifiInfo wifiInfo = wifi.getConnectionInfo();
  int ipAddress = wifiInfo.getIpAddress();
  String ip = null;
  ip = String.format("%d.%d.%d.%d",
  (ipAddress & 0xff),
  (ipAddress >> 8 & 0xff),
  (ipAddress >> 16 & 0xff),
  (ipAddress >> 24 & 0xff));
  Log.e(" >>IP number Begin ",ip);

Un autre extrait de code ... S'il n'est pas activé, activez-le (avec l'autorisation préalable des utilisateurs)

   if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);  

7

Pour détecter l'état de la connexion WIFI, j'ai utilisé CONNECTIVITY_ACTION de la classe ConnectivityManager afin:

    IntentFilter filter=new IntentFilter();
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    registerReceiver(receiver, filter);

et depuis votre BroadCastReceiver:

    if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
        int networkType = intent.getIntExtra(
                android.net.ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
        if (ConnectivityManager.TYPE_WIFI == networkType) {
            NetworkInfo networkInfo = (NetworkInfo) intent
                    .getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            if (networkInfo != null) {
                if (networkInfo.isConnected()) {

                    // TODO: wifi is connected
                } else {
                    // TODO: wifi is not connected
                }
            }
        }

    }

ps: fonctionne bien pour moi :)


1
Pour info, avec Android 6, lorsque vous disposez d'une connexion de données cellulaire valide, les changements d'état du wifi ne déclenchent pas CONNECTIVITY_ACTION. La seule raison pour laquelle ils l'ont fait est que l'état de la connectivité a été affecté, maintenant ce n'est pas le cas.
Bruce

5

Ce code ne nécessite aucune autorisation. Il est limité uniquement aux changements d'état de la connectivité du réseau Wi-Fi (aucun autre réseau n'est pris en compte). Le récepteur est statiquement publié dans le fichier AndroidManifest.xml et n'a pas besoin d'être exporté comme il sera invoqué par le système protected broadcast, NETWORK_STATE_CHANGED_ACTIONà chaque connectivité réseau changement d'état.

AndroidManifest:

<receiver
    android:name=".WifiReceiver"
    android:enabled="true"
    android:exported="false">

    <intent-filter>
        <!--protected-broadcast: Special broadcast that only the system can send-->
        <!--Corresponds to: android.net.wifi.WifiManager.NETWORK_STATE_CHANGED_ACTION-->
        <action android:name="android.net.wifi.STATE_CHANGE" />
    </intent-filter>

</receiver>

Classe BroadcastReceiver:

public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/*
 Tested (I didn't test with the WPS "Wi-Fi Protected Setup" standard):
 In API15 (ICE_CREAM_SANDWICH) this method is called when the new Wi-Fi network state is:
 DISCONNECTED, OBTAINING_IPADDR, CONNECTED or SCANNING

 In API19 (KITKAT) this method is called when the new Wi-Fi network state is:
 DISCONNECTED (twice), OBTAINING_IPADDR, VERIFYING_POOR_LINK, CAPTIVE_PORTAL_CHECK
 or CONNECTED

 (Those states can be obtained as NetworkInfo.DetailedState objects by calling
 the NetworkInfo object method: "networkInfo.getDetailedState()")
*/
    /*
     * NetworkInfo object associated with the Wi-Fi network.
     * It won't be null when "android.net.wifi.STATE_CHANGE" action intent arrives.
     */
    NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);

    if (networkInfo != null && networkInfo.isConnected()) {
        // TODO: Place the work here, like retrieving the access point's SSID

        /*
         * WifiInfo object giving information about the access point we are connected to.
         * It shouldn't be null when the new Wi-Fi network state is CONNECTED, but it got
         * null sometimes when connecting to a "virtualized Wi-Fi router" in API15.
         */
        WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
        String ssid = wifiInfo.getSSID();
    }
}
}

Autorisations:

None

1
Le fonctionne dans les appareils exécutant <API 26. Comme @Isham l'a suggéré, l'action n'est plus prise en charge dans Android O
tiagocarvalho92

3

Voici un exemple de mon code, qui prend en compte la préférence des utilisateurs de n'autoriser les communications que lorsqu'ils sont connectés au Wifi.

J'appelle ce code de l'intérieur IntentServiceavant d'essayer de télécharger des trucs.

Notez que ce NetworkInfosera le nullcas s'il n'y a pas de connexion réseau d'aucune sorte.

private boolean canConnect()
{
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

    boolean canConnect = false;
    boolean wifiOnly = SharedPreferencesUtils.wifiOnly();

    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    if(networkInfo != null)
    {
        if(networkInfo.isConnected())
        {
            if((networkInfo.getType() == ConnectivityManager.TYPE_WIFI) ||
               (networkInfo.getType() != ConnectivityManager.TYPE_WIFI && !wifiOnly))
            {
                canConnect = true;
            }
        }
    }

    return canConnect;
}

3

Android O a supprimé la possibilité de recevoir les diffusions implicites pour un changement d'état du wifi. Donc, si votre application est fermée, vous ne pourrez pas les recevoir. Le nouveauWorkManager a la capacité de s'exécuter lorsque votre application est fermée, j'ai donc expérimenté un peu avec elle et cela semble fonctionner assez bien:

Ajoutez ceci à vos dépendances:

implementation "android.arch.work:work-runtime:1.0.0-alpha08"

WifiConnectWorker.kt

class WifiConnectWorker : Worker() {

    override fun doWork(): Result {
        Log.i(TAG, "I think we connected to a wifi")
        return Result.SUCCESS
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)

        val workManager = WorkManager.getInstance()

        // Add constraint to start the worker when connecting to WiFi
        val request = OneTimeWorkRequest.Builder(WifiConnectWorker::class.java)
            .setConstraints(Constraints.Builder()
                .setRequiredNetworkType(UNMETERED)
                .build())
            .build()

        // The worker should be started, even if your app is closed
        workManager.beginUniqueWork("watch_wifi", REPLACE, request).enqueue()
    }
}

Gardez à l'esprit qu'il ne s'agissait que d'un test rapide pour une notification unique. Il y a plus de travail à faire pour toujours être averti lorsque le WiFi est activé et désactivé.

PS: Lorsque l'application est forcée à quitter , le worker n'est pas démarré, il semble alors WorkManagerannuler les demandes.


Existe-t-il un moyen de démarrer Worker même si mon application est à l'état de sortie forcée. Le gestionnaire de travail utilise .setRequiredNetworkType (UNMETERED) uniquement si l'application est ouverte. Existe-t-il un moyen de déclencher un ouvrier même si l'application est tuée (forcer l'état de fermeture). Parce que le récepteur de diffusion implicite a également quelque peu restreint. Quelle sera la meilleure alternative?
Suresh le

2

J'ai utilisé ce code:

public class MainActivity extends Activity
    {
    .
    .
    .
    @Override
    protected void onCreate(Bundle savedInstanceState)
        {
        super.onCreate(savedInstanceState);
        .
        .
        .
        }

    @Override
    protected void onResume()
        {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
        registerReceiver(broadcastReceiver, intentFilter);  
        }

    @Override
    protected void onPause()
        {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
        }

    private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
        {
        @Override
        public void onReceive(Context context, Intent intent)
            {
            final String action = intent.getAction();
            if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION))
                {
                if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false))
                    {
                    // wifi is enabled
                    }
                else
                    {
                    // wifi is disabled
                    }
                }
            }
        };
    }

2

J'ai deux méthodes pour détecter la connexion WIFI recevant le contexte de l'application:

1) mon ancienne méthode

public boolean isConnectedWifi1(Context context) {
    try {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();           
        if (networkInfo != null) {
            NetworkInfo[] netInfo = connectivityManager.getAllNetworkInfo();
            for (NetworkInfo ni : netInfo) {
                if ((ni.getTypeName().equalsIgnoreCase("WIFI"))
                        && ni.isConnected()) {
                    return true;
                }                   
            }
        }
        return false;
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }
    return false;
}

2) ma nouvelle méthode (j'utilise actuellement cette méthode):

public boolean isConnectedWifi(Context context) {
         ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
         return networkInfo.isConnected();
}

Comment puis-je faire cela sur Android O car les récepteurs de diffusion implicites tels que android.net.wifi.STATE_CHANGE ne seront plus autorisés à être enregistrés dans le manifeste (voir developer.android.com/guide/components/… ). Si nous l'enregistrons dans l'activité de l'application (disons onCreate), alors il devra être désenregistré dans onStop (), et nous ne recevrons plus d'événements liés au wifi
zafar142003


2

1) J'ai également essayé l'approche Broadcast Receiver même si je sais que CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE est obsolète dans l'API 28 et n'est pas recommandé. Également lié à l'utilisation d'un registre explicite, il écoute tant que l'application est en cours d'exécution.

2) J'ai également essayé Firebase Dispatcher qui fonctionne mais pas au-delà de l'application tuée.

3) La méthode recommandée est WorkManager pour garantir l'exécution au-delà du processus tué et en interne en utilisant registerNetworkRequest ()

La plus grande preuve en faveur de l'approche n ° 3 est référencée par Android doc lui-même. Surtout pour les applications en arrière-plan.

Ici aussi

Dans Android 7.0, nous supprimons trois diffusions implicites couramment utilisées - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE et ACTION_NEW_VIDEO - car elles peuvent réveiller les processus d'arrière-plan de plusieurs applications à la fois et épuiser la mémoire et la batterie. Si votre application les reçoit, profitez plutôt d'Android 7.0 pour migrer vers JobScheduler et les API associées.

Jusqu'à présent, cela fonctionne bien pour nous en utilisant la requête Periodic WorkManager.

Mise à jour: J'ai fini par écrire 2 articles médiatiques à ce sujet.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.