Come rilevare quando è stata stabilita la connessione WIFI in Android?


140

Devo rilevare quando ho la connettività di rete tramite WIFI. Quale trasmissione viene inviata per stabilire che è stata stabilita una connessione di rete valida. Devo confermare che esiste una connessione di rete valida per HTTP. Cosa devo ascoltare e quali test aggiuntivi devo fare per sapere che esiste una connessione valida.


Alcune parti di questa domanda hanno avuto risposta qui Ho trovato: stackoverflow.com/questions/4238921/…
Androider

1
Ma c'è ancora la domanda su QUANDO controllare queste condizioni?
Androider,

1
Vorrei feedback su se ci saranno trasmissioni che potrebbero essere catturate da un ricevitore broadcast?
Androider

1
Come posso farlo su Android O come ricevitori di trasmissione impliciti come android.net.wifi.STATE_CHANGE non sarà più permesso di essere registrati nel manifest (vedi developer.android.com/guide/components/… ). Se lo registriamo nell'attività dell'applicazione (ad esempio onCreate), dovrà essere cancellato in onStop () e non riceveremo più eventi relativi al wifi
zafar142003

Risposte:


126

È possibile registrare a BroadcastReceiverper ricevere una notifica quando viene stabilita una connessione WiFi (o se la connessione è stata modificata).

Registra il BroadcastReceiver:

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

E poi nel tuo BroadcastReceiverfare qualcosa del genere:

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

Per ulteriori informazioni, consultare la documentazione di BroadcastReceivereWifiManager

Naturalmente prima di questo dovresti verificare se il dispositivo è già connesso al WiFi.

EDIT: grazie al ban-geoengineering, ecco un metodo per verificare se il dispositivo è già collegato:

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

1
Perché SUPPLICANT_CONECTION_CHANGE_ACTION? Ho pensato che fosse solo JUST CONNECTION_CHANGE cambio di trasmissione. Perché SUPPLCANT ??? grazie
Androider,

2
eh? Non vedo un'azione chiamata connection_change ...? Vedo solo lo stato del wifi cambiato, ma quell'azione indica solo se il wifi è abilitato o meno (o abilitato / disabilitato) non se è collegato ... supplicant_connection_change_action non sta facendo ciò di cui hai bisogno?
jpm

9
Per me WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION non funziona nel caso in cui sia stata stabilita / persa la connessione a una stazione wifi nota. Ma WifiManager.NETWORK_STATE_CHANGED_ACTION funziona.
Anno

1
"android.net.wifi.STATE_CHANGE" ha funzionato per me. controlla la mia risposta qui sotto
M. Usman Khan

1
"Naturalmente prima di questo dovresti verificare se il dispositivo è già connesso al WiFi." - quindi, per ottenere lo stato iniziale del Wi-Fi, puoi usare questo metodo ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
ban-geoengineering

106

Il meglio che ha funzionato per me:

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

permessi

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

1
Penso che questa sia la risposta migliore per lo chage di stato specificamente wifi. Grazie
Mikel,

4
Per riferimento futuro, quell'azione codificata è WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage

3
if (info! = null && info.isConnected ()) = no spaghetti.
gswierczynski,

1
dobbiamo scrivere qualche codice per inviare la trasmissione nell'attività principale ??
Nisari Balakrishnan,

1
Come posso farlo su Android O come ricevitori di trasmissione impliciti come android.net.wifi.STATE_CHANGE non sarà più permesso di essere registrati nel manifest (vedi developer.android.com/guide/components/… ). Se lo registriamo nell'attività dell'applicazione (diciamo onCreate), allora dovrà essere cancellato in onStop () e non riceveremo più eventi relativi al wifi.
zafar142003,

18

Per me WifiManager.NETWORK_STATE_CHANGED_ACTIONfunziona solo .

Registrare un ricevitore di trasmissione:

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

e ricevi:

@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
Anche per me ha funzionato solo WifiManager.NETWORK_STATE_CHANGED_ACTION, qualche spiegazione per il motivo per cui solo questo funzionerà?
Benchuk,

11

Le risposte fornite dall'utente @JPM e @usman sono davvero molto utili. Funziona bene, ma nel mio caso arriva onReceivepiù volte nel mio caso 4 volte quindi il mio codice viene eseguito più volte.

Faccio alcune modifiche e applico secondo le mie esigenze e ora arriva solo 1 volta

Ecco la classe Java per 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 ----- ");
        }

    }
}
}

In 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
cos'è wifiState?
Behelit,

1
Vorrei anche sapere cos'è wifiState, come è stato generato
Evan Parsons,

1
@behelit ora "wifiState" è presente nella risposta modificata.
Yog Guru

8

È possibile avviare una connessione Wi-Fi se si dà all'utente la possibilità di ignorare il normale comportamento di chiedere ogni volta.

Ho scelto di usare tre metodi ...

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

Questo è un controllo rapido se esiste una connessione Internet Wifi o CellData. Da qui puoi scegliere quale azione vuoi intraprendere. È in modalità aereo deve essere controllato anche.

Su un thread separato. Ho impostato una variabile IpAddress su = "" E eseguo il polling fino a quando non ho un indirizzo IP valido.

  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 altro frammento di codice ... Se non è attivo, accenderlo (previa autorizzazione dell'utente)

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

7

Per rilevare lo stato della connessione WIFI, ho usato CONNECTIVITY_ACTION dalla classe ConnectivityManager così:

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

e dal tuo 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: funziona bene per me :)


1
a proposito, con Android 6 quando si dispone di una connessione dati cellulare valida, i cambiamenti nello stato Wi-Fi non attiveranno CONNECTIVITY_ACTION. L'unica ragione per cui lo hanno fatto è stato lo stato di connettività, ora non lo è.
Bruce,

5

Questo codice non richiede alcuna autorizzazione. È limitato solo alle modifiche dello stato di connettività della rete Wi-Fi (qualsiasi altra rete non viene presa in considerazione). Il ricevitore è staticamente pubblicato nel file AndroidManifest.xml e non ha bisogno di essere esportato in quanto verrà richiamato dal sistema protected broadcast, NETWORK_STATE_CHANGED_ACTIONad ogni cambio di stato della rete di connettività.

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

permessi:

None

1
Funziona su dispositivi con <API 26. Come suggerito da @Isham, l'azione non è più supportata in Android O
tiagocarvalho92

3

Ecco un esempio del mio codice, che tiene conto della preferenza degli utenti di consentire le comunicazioni solo quando è collegato a Wifi.

Sto chiamando questo codice da dentro e IntentServiceprima di provare a scaricare roba.

Si noti che NetworkInfolo sarà nullse non esiste alcuna connessione di rete di alcun tipo.

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 ha rimosso la possibilità di ricevere le trasmissioni implicite per un cambio di stato del wifi. Quindi, se la tua app è chiusa, non sarai in grado di riceverli. Il nuovoWorkManager ha la capacità di funzionare quando l'app è chiusa, quindi ho provato un po 'con esso e sembra funzionare abbastanza bene:

Aggiungi questo alle tue dipendenze:

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()
    }
}

Tieni presente che questo è stato solo un test rapido per una notifica singola. C'è ancora molto lavoro da fare per essere sempre avvisato quando il WiFi è acceso e spento.

PS: quando l'app viene chiusa forzatamente , il lavoratore non viene avviato, quindi sembra che WorkManagerstia annullando le richieste.


Esiste un modo per avviare il lavoratore anche se la mia app è forzata a uscire dallo stato. Work Manager sta lavorando con .setRequiredNetworkType (UNMETERED) solo se l'app è aperta. Esiste un modo per attivare il lavoratore anche se l'app è in stato di arresto (forza lo stato chiuso). Perché anche il ricevitore implicito per il cast esteso è in qualche modo limitato. Quale sarà la migliore alternativa?
Suresh,

2

Ho usato questo codice:

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

Ho due metodi per rilevare la connessione WIFI che riceve il contesto dell'applicazione:

1) il mio vecchio metodo

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) il mio nuovo metodo (attualmente sto usando questo metodo):

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

Come posso farlo su Android O come ricevitori di trasmissione impliciti come android.net.wifi.STATE_CHANGE non sarà più permesso di essere registrati nel manifest (vedi developer.android.com/guide/components/… ). Se lo registriamo nell'attività dell'applicazione (ad esempio onCreate), dovrà essere cancellato in onStop () e non riceveremo più eventi relativi al wifi
zafar142003


2

1) Ho provato anche l'approccio Broadcast Receiver anche se so che CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE è obsoleto nell'API 28 e sconsigliato. Anche legato all'uso del registro esplicito, è in ascolto fino a quando l'app è in esecuzione.

2) Ho anche provato Firebase Dispatcher che funziona ma non oltre l'app uccisa.

3) Il modo consigliato trovato è WorkManager per garantire l'esecuzione oltre il processo interrotto e l'utilizzo interno registerNetworkRequest ()

La più grande prova a favore dell'approccio n. 3 è riferita dallo stesso documento Android . Soprattutto per le app in background.

Anche qui

In Android 7.0 stiamo rimuovendo tre trasmissioni implicite di uso comune - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE e ACTION_NEW_VIDEO - poiché possono riattivare contemporaneamente i processi in background di più app e limitare la memoria e la batteria. Se la tua app li sta ricevendo, sfrutta Android 7.0 per migrare a JobScheduler e alle API correlate.

Finora funziona bene per noi usando la richiesta Periodic WorkManager.

Aggiornamento: ho finito per scrivere 2 post medi su questo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.