Wie erkenne ich, wann eine WIFI-Verbindung in Android hergestellt wurde?

140

Ich muss erkennen, wann ich über WIFI eine Netzwerkverbindung habe. Welche Sendung wird gesendet, um festzustellen, ob eine gültige Netzwerkverbindung hergestellt wurde. Ich muss überprüfen, ob eine gültige Netzwerkverbindung für HTTP vorhanden ist. Worauf muss ich achten und welche zusätzlichen Tests muss ich durchführen, um zu wissen, dass eine gültige Verbindung besteht.

Androider
quelle
Teile dieser Frage wurden hier beantwortet, die ich gefunden habe: stackoverflow.com/questions/4238921/…
Androider
1
Es bleibt jedoch die Frage, wann diese Bedingungen überprüft werden sollen.
Androider
1
Ich möchte eine Rückmeldung darüber, ob Sendungen auftreten, die von einem Rundfunkempfänger empfangen werden könnten.
Androider
1
Wie kann ich dies unter Android O tun, da implizite Rundfunkempfänger wie android.net.wifi.STATE_CHANGE nicht mehr im Manifest registriert werden dürfen (siehe developer.android.com/guide/components/… ). Wenn wir es in der Anwendungsaktivität registrieren (z. B. onCreate), muss es in onStop () abgemeldet werden, und wir erhalten keine
wifi-

Antworten:

126

Sie können eine registrieren BroadcastReceiver, um benachrichtigt zu werden, wenn eine WiFi-Verbindung hergestellt wird (oder wenn sich die Verbindung geändert hat).

Registrieren Sie die BroadcastReceiver:

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

Und dann BroadcastReceivermachst du so etwas:

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

Weitere Informationen finden Sie in der Dokumentation zu BroadcastReceiverundWifiManager

Natürlich sollten Sie vorher prüfen, ob das Gerät bereits mit WiFi verbunden ist.

BEARBEITEN: Dank Ban-Geoengineering können Sie hier überprüfen, ob das Gerät bereits angeschlossen ist:

private boolean isConnectedViaWifi() {
     ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
     NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
     return mWifi.isConnected();
}
jpm
quelle
1
Warum SUPPLICANT_CONECTION_CHANGE_ACTION? Ich dachte, es wäre JUST CONNECTION_CHANGE Change Broadcast. Warum SUPPLCANT ??? danke
Androider
2
huh? Ich sehe keine Aktion namens connection_change ...? Ich sehe nur, dass sich der WLAN-Status geändert hat, aber diese Aktion zeigt nur an, ob WLAN aktiviert ist oder nicht (oder aktiviert / deaktiviert), nicht, ob es verbunden ist. Tut Supplicant_connection_change_action nicht das, was Sie benötigen?
jpm
9
Für mich funktioniert WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION nicht, wenn die Verbindung zu einer bekannten WLAN-Station hergestellt wurde / unterbrochen wurde. Aber WifiManager.NETWORK_STATE_CHANGED_ACTION funktioniert.
Yar
1
"android.net.wifi.STATE_CHANGE" hat bei mir funktioniert. Überprüfen Sie meine Antwort unten
M. Usman Khan
1
"Natürlich sollten Sie vorher prüfen, ob das Gerät bereits mit WiFi verbunden ist." - Um den anfänglichen Wi-Fi-Status zu erhalten, können Sie diese Methode verwenden ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
Ban-Geoengineering
106

Das Beste, was für mich funktioniert hat:

AndroidManifest

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

BroadcastReceiver-Klasse

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

Berechtigungen

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
M. Usman Khan
quelle
1
Ich denke, dies ist die beste Antwort für speziell WiFi State Chage. Vielen Dank
Mikel
4
Für zukünftige einfache Referenz ist diese fest codierte Aktion WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage
3
if (info! = null && info.isConnected ()) = keine Spaghetti.
gswierczynski
1
Müssen wir Code schreiben, um die Sendung in der Hauptaktivität zu senden?
Nisari Balakrishnan
1
Wie kann ich dies unter Android O tun, da implizite Rundfunkempfänger wie android.net.wifi.STATE_CHANGE nicht mehr im Manifest registriert werden dürfen (siehe developer.android.com/guide/components/… ). Wenn wir es in der Anwendungsaktivität registrieren (z. B. onCreate), muss es in onStop () abgemeldet werden, und wir erhalten keine wifi-bezogenen Ereignisse mehr.
zafar142003
18

Bei mir WifiManager.NETWORK_STATE_CHANGED_ACTIONfunktioniert nur .

Registrieren Sie einen Rundfunkempfänger:

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

und erhalten:

@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
    }      
}
Yar
quelle
1
Auch für mich hat nur WifiManager.NETWORK_STATE_CHANGED_ACTION funktioniert. Gibt es Erklärungen, warum nur dies funktioniert?
Benchuk
11

Die Antworten der Benutzer @JPM und @usman sind wirklich sehr nützlich. Es funktioniert gut, aber in meinem Fall kommt es onReceivein meinem Fall 4 Mal mehrfach vor , sodass mein Code ausgeführt wird.

Ich mache einige Modifikationen und mache nach meinen Anforderungen und jetzt kommt es nur noch 1 Mal

Hier ist Java-Klasse für 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"/>
Yog Guru
quelle
1
Was ist WiFiState?
siehe
1
Würde auch gerne wissen, was wifiState ist, wie es generiert wurde
Evan Parsons
1
@behelit jetzt "wifiState" ist dort in bearbeiteter Antwort.
Yog Guru
8

Sie können eine WLAN-Verbindung herstellen, wenn Sie dem Benutzer die Möglichkeit geben, das normale Verhalten beim erneuten Fragen zu überschreiben.

Ich wähle drei Methoden ...

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

Dies ist eine schnelle Überprüfung, ob eine Internetverbindung zwischen Wifi oder CellData besteht. Von hier aus können Sie auswählen, welche Aktion Sie ausführen möchten. Ist es im Flugzeugmodus muss auch überprüft werden.

Auf einem separaten Thread. Ich setze eine Variable IpAddress auf = "" und frage ab, bis ich eine gültige IP-Adresse habe.

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

Ein weiteres Code-Snippet ... Wenn es nicht aktiviert ist, schalten Sie es ein (mit vorheriger Genehmigung des Benutzers).

   if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);  
user1445716
quelle
7

Um den WIFI-Verbindungsstatus zu erkennen, habe ich CONNECTIVITY_ACTION aus der ConnectivityManager-Klasse verwendet, also:

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

und von Ihrem 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: funktioniert gut für mich :)

Amin
quelle
1
Zu Ihrer Information: Wenn Sie mit Android 6 eine gültige Zellendatenverbindung haben, lösen Änderungen im WLAN-Status keine CONNECTIVITY_ACTION aus. Der einzige Grund, warum sie dies getan haben, ist, dass der Konnektivitätsstatus beeinträchtigt wurde, jetzt ist dies nicht mehr der Fall.
Bruce
5

Dieser Code erfordert überhaupt keine Erlaubnis. Es ist nur auf Änderungen des Wi-Fi-Netzwerkverbindungsstatus beschränkt (jedes andere Netzwerk wird nicht berücksichtigt). Der Empfänger wird statisch in der Datei AndroidManifest.xml veröffentlicht und muss nicht exportiert werden, da er vom System aufgerufen wird protected broadcast.NETWORK_STATE_CHANGED_ACTION bei jeder Netzwerkkonnektivität Zustandsänderung.

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>

BroadcastReceiver-Klasse:

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

Berechtigungen:

None
Codegateway
quelle
1
Das funktioniert auf Geräten, auf denen <API 26 ausgeführt wird. Wie @Isham vorschlug, wird die Aktion in Android O
tiagocarvalho92
3

Hier ist ein Beispiel für meinen Code, der die Präferenz des Benutzers berücksichtigt, nur Kommunikation zuzulassen, wenn eine Verbindung zu Wifi besteht.

Ich rufe diesen Code aus einem IntentService bevor ich versuche, etwas herunterzuladen.

Beachten Sie, dass dies NetworkInfoder Fall ist, nullwenn keine Netzwerkverbindung besteht.

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;
}
Justin Phillips
quelle
3

Android O hat die Möglichkeit entfernt, die impliziten Sendungen für eine Änderung des WLAN-Status zu empfangen. Wenn Ihre App geschlossen ist, können Sie sie nicht empfangen. Das neueWorkManager Gerät kann ausgeführt werden, wenn Ihre App geschlossen ist. Ich habe also ein wenig damit experimentiert und es scheint recht gut zu funktionieren:

Fügen Sie dies Ihren Abhängigkeiten hinzu:

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

Beachten Sie, dass dies nur ein schneller Test für eine einmalige Benachrichtigung war. Es gibt noch viel zu tun, um immer benachrichtigt zu werden, wenn WLAN ein- und ausgeschaltet wird.

PS: Wenn die App zwangsweise beendet wird , wird der Worker anscheinend nicht gestartetWorkManager die Anforderungen dann abgebrochen.

Marius
quelle
Gibt es eine Möglichkeit, den Worker zu starten, selbst wenn meine App den Status "Force Quited" hat? Der Arbeitsmanager arbeitet nur mit .setRequiredNetworkType (UNMETERED), wenn die App geöffnet ist. Gibt es eine Möglichkeit, einen Worker auszulösen, selbst wenn die App getötet wurde (erzwungener geschlossener Zustand)? Weil impliziter Rundfunkempfänger auch etwas eingeschränkt ist. Was ist die beste Alternative?
Suresh
2

Ich habe diesen Code verwendet:

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
                    }
                }
            }
        };
    }
Cuarcuiu
quelle
2

Ich habe zwei Methoden, um eine WIFI-Verbindung zu erkennen, die den Anwendungskontext empfängt:

1) meine alte Methode

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) meine neue Methode (ich verwende derzeit diese Methode):

public boolean isConnectedWifi(Context context) {
         ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
         return networkInfo.isConnected();
}
Jorgesys
quelle
Wie kann ich dies unter Android O tun, da implizite Rundfunkempfänger wie android.net.wifi.STATE_CHANGE nicht mehr im Manifest registriert werden dürfen (siehe developer.android.com/guide/components/… ). Wenn wir es in der Anwendungsaktivität registrieren (z. B. onCreate), muss es in onStop () abgemeldet werden, und wir erhalten keine
wifi-
2

1) Ich habe auch den Broadcast Receiver-Ansatz ausprobiert, obwohl ich CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE kenne in API 28 veraltet und nicht empfohlen ist. Es ist auch an die Verwendung eines expliziten Registers gebunden und hört zu, solange die App ausgeführt wird.

2) Ich habe auch Firebase Dispatcher ausprobiert, der funktioniert, aber nicht über die getötete App hinaus.

3) Der empfohlene Weg ist WorkManager, um die Ausführung über den abgebrochenen Prozess hinaus und intern mit registerNetworkRequest () zu gewährleisten.

Der größte Beweis für den # 3-Ansatz wird von Android doc selbst verwiesen . Besonders für Apps im Hintergrund.

Auch hier

In Android 7.0 entfernen wir drei häufig verwendete implizite Broadcasts - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE und ACTION_NEW_VIDEO - da diese die Hintergrundprozesse mehrerer Apps gleichzeitig aktivieren und Speicher und Akku belasten können. Wenn Ihre App diese empfängt, nutzen Sie Android 7.0, um stattdessen auf JobScheduler und verwandte APIs zu migrieren.

Bisher funktioniert es für uns mit der periodischen WorkManager-Anfrage einwandfrei.

Update: Am Ende habe ich 2 mittlere Medienbeiträge darüber geschrieben.

Wahib Ul Haq
quelle