¿Cómo detectar cuándo se ha establecido la conexión WIFI en Android?

140

Necesito detectar cuándo tengo conectividad de red a través de WIFI. Qué difusión se envía para establecer que se ha realizado una conexión de red válida. Necesito validar que existe una conexión de red válida para HTTP. ¿Qué debo escuchar y qué pruebas adicionales debo hacer para saber que existe una conexión válida?

Androider
fuente
Partes de esta pregunta han sido respondidas aquí. Encontré: stackoverflow.com/questions/4238921/…
Androider
1
Pero todavía queda la cuestión de ¿CUÁNDO verificar estas condiciones?
Androider
1
Me gustaría recibir comentarios sobre si se producirán transmisiones que podrían ser captadas por un receptor de transmisión.
Androider
1
¿Cómo puedo hacer esto en Android O ya que los receptores de transmisión implícitos como android.net.wifi.STATE_CHANGE ya no podrán registrarse en el manifiesto (ver developer.android.com/guide/components/… ). Si lo registramos en la actividad de la aplicación (digamos onCreate), entonces tendrá que darse de baja en onStop (), y ya no recibiremos eventos relacionados con wifi
zafar142003

Respuestas:

126

Puede registrar un BroadcastReceiverpara recibir una notificación cuando se establezca una conexión WiFi (o si la conexión cambió).

Registra el BroadcastReceiver:

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

Y luego en tu BroadcastReceiverhacer algo como esto:

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

Para obtener más información, consulte la documentación para BroadcastReceiveryWifiManager

Por supuesto, debe verificar si el dispositivo ya está conectado a WiFi antes de esto.

EDITAR: Gracias a la prohibición de geoingeniería, aquí hay un método para verificar si el dispositivo ya está conectado:

private boolean isConnectedViaWifi() {
     ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
     NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
     return mWifi.isConnected();
}
jpm
fuente
1
¿Por qué SUPPLICANT_CONECTION_CHANGE_ACTION? Pensé que era JUST CONNECTION_CHANGE cambio de transmisión. ¿Por qué SUPPLCANT ??? gracias
Androider
2
eh? No veo una acción llamada connection_change ...? Solo veo que el estado de wifi ha cambiado, pero esa acción solo indica si wifi está habilitado o no (o activando / desactivando) no si está conectado ... ¿supplicant_connection_change_action no está haciendo lo que necesita?
jpm
9
Para mí, WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION no funciona en caso de que se haya establecido / perdido la conexión a una estación wifi conocida. Pero WifiManager.NETWORK_STATE_CHANGED_ACTION funciona.
Yar
1
"android.net.wifi.STATE_CHANGE" funcionó para mí. revise mi respuesta a continuación
M. Usman Khan
1
"Por supuesto, debe verificar si el dispositivo ya está conectado a WiFi antes de esto". - entonces, para obtener el estado de Wi-Fi inicial, puede usar este método ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
prohibir geoingeniería el
106

Lo mejor que me funcionó:

AndroidManifest

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

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

Permisos

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
M. Usman Khan
fuente
1
Creo que esta es la mejor respuesta para el cambio de estado específicamente wifi. Gracias
Mikel
44
Para futuras referencias fáciles, esa acción codificada es WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage
3
if (info! = nulo && info.isConnected ()) = sin espagueti.
gswierczynski
1
¿Necesitamos escribir algún código para enviar la transmisión en la actividad principal?
Nisari Balakrishnan
1
¿Cómo puedo hacer esto en Android O ya que los receptores de transmisión implícitos como android.net.wifi.STATE_CHANGE ya no podrán registrarse en el manifiesto (ver developer.android.com/guide/components/… ). Si lo registramos en la actividad de la aplicación (digamos onCreate), entonces tendrá que darse de baja en onStop (), y ya no recibiremos eventos relacionados con wifi.
zafar142003
18

Para mi solo WifiManager.NETWORK_STATE_CHANGED_ACTIONfunciona.

Registre un receptor de difusión:

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

y recibir:

@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
fuente
1
Para mí también, solo WifiManager.NETWORK_STATE_CHANGED_ACTION funcionó, ¿alguna explicación de la razón por la que solo esto funcionará?
benchuk
11

La respuesta dada por el usuario @JPM y @usman es realmente muy útil. Funciona bien, pero en mi caso viene en onReceivemúltiples ocasiones en mi caso 4 veces, por lo que mi código se ejecuta varias veces.

Hago algunas modificaciones y las realizo según mi requerimiento y ahora solo viene 1 vez

Aquí está la clase de Java para 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 ----- ");
        }

    }
}
}

En 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
fuente
1
¿Qué es wifiState?
Behelit
1
También me gustaría saber qué es wifiState, cómo se generó
Evan Parsons
1
@behelit ahora "wifiState" está allí en la respuesta editada.
Yog Guru
8

Usted puede iniciar una conexión wifi si se le da al usuario una opción para anular el comportamiento normal de pedir cada vez.

Elijo usar tres métodos ...

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

Esta es una verificación rápida si hay una conexión a Internet, ya sea Wifi o CellData. Desde aquí puedes elegir qué acción quieres tomar. ¿Está en modo avión? También debe verificarse.

En un hilo separado. Establezco una variable IpAddress en = "" Y sondeo hasta que tenga una dirección IP válida.

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

Otro fragmento de código ... Si no está activado, actívelo (con permiso previo de los usuarios)

   if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);  
usuario1445716
fuente
7

Para detectar el estado de la conexión WIFI, he usado CONNECTIVITY_ACTION de la clase ConnectivityManager, así que:

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

y desde su 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: funciona bien para mí :)

amina
fuente
1
Para su información, con Android 6 cuando tiene una conexión de datos celular válida, los cambios en el estado wifi no desencadenarán CONNECTIVITY_ACTION. La única razón por la que lo hicieron es que el estado de conectividad se vio afectado, ahora no lo es.
Bruce
5

Este código no requiere permiso en absoluto. Está restringido solo a los cambios de estado de conectividad de la red Wi-Fi (no se tiene en cuenta ninguna otra red). El receptor se publica de forma estática en el archivo AndroidManifest.xml y no necesita ser exportados, ya que será invocado por el sistema protected broadcast, NETWORK_STATE_CHANGED_ACTION, en cada cambio de estado de la conectividad de red.

Manifiesto de Android:

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

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

Permisos:

None
Codegateway
fuente
1
Funciona en dispositivos que ejecutan <API 26. Como sugirió @Isham, la acción ya no es compatible con Android O
tiagocarvalho92
3

Aquí hay un ejemplo de mi código, que tiene en cuenta la preferencia de los usuarios de permitir solo comunicaciones cuando está conectado a Wifi.

Estoy llamando a este código desde dentro de un IntentService antes de intentar descargar cosas.

Tenga en cuenta que NetworkInfoserá nullsi no hay conexión de red de ningún 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;
}
Justin Phillips
fuente
3

Android O eliminó la posibilidad de recibir las transmisiones implícitas para un cambio de estado wifi. Entonces, si su aplicación está cerrada, no podrá recibirla. El nuevoWorkManager tiene la capacidad de ejecutarse cuando su aplicación está cerrada, por lo que he experimentado un poco con ella y parece funcionar bastante bien:

Agregue esto a sus dependencias:

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

Tenga en cuenta que esto fue solo una prueba rápida para una notificación única. Hay más trabajo por hacer para que siempre se nos notifique cuando WiFi está encendido y apagado.

PD: Cuando la aplicación se cierra por la fuerza , el trabajador no se inicia, parece WorkManagerque cancela las solicitudes en ese momento.

Mario
fuente
¿Hay alguna manera de comenzar a trabajar, incluso si mi aplicación es forzada? El administrador de trabajo está trabajando con .setRequiredNetworkType (UNMETERED) solo si la aplicación está abierta. ¿Hay alguna forma de activar el trabajador? Incluso la aplicación está en estado de inactividad (forzar el estado cerrado). Porque el receptor de reparto implícito también está algo restringido. ¿Cuál será la mejor alternativa?
Suresh
2

Usé este código:

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
fuente
2

Tengo dos métodos para detectar la conexión WIFI que recibe el contexto de la aplicación:

1) mi viejo método

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) mi nuevo método (actualmente estoy usando este método):

public boolean isConnectedWifi(Context context) {
         ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
         return networkInfo.isConnected();
}
Jorgesys
fuente
¿Cómo puedo hacer esto en Android O ya que los receptores de transmisión implícitos como android.net.wifi.STATE_CHANGE ya no podrán registrarse en el manifiesto (ver developer.android.com/guide/components/… ). Si lo registramos en la actividad de la aplicación (digamos onCreate), entonces tendrá que darse de baja en onStop (), y ya no recibiremos eventos relacionados con wifi
zafar142003
2

1) También probé el enfoque de Broadcast Receiver aunque conozco CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE está en desuso en API 28 y no se recomienda. También obligado a usar el registro explícito, escucha mientras la aplicación se esté ejecutando.

2) También probé Firebase Dispatcher que funciona pero no más allá de la aplicación eliminada.

3) La forma recomendada que se encuentra es WorkManager para garantizar la ejecución más allá del proceso finalizado y utilizando internamente registerNetworkRequest ()

El documento de Android mismo hace referencia a la mayor evidencia a favor del enfoque # 3 . Especialmente para aplicaciones en segundo plano.

Tambien aqui

En Android 7.0 estamos eliminando tres transmisiones implícitas de uso común: CONNECTIVITY_ACTION, ACTION_NEW_PICTURE y ACTION_NEW_VIDEO, ya que pueden despertar los procesos en segundo plano de varias aplicaciones a la vez y agotar la memoria y la batería. Si su aplicación recibe estos, aproveche el Android 7.0 para migrar a JobScheduler y API relacionadas en su lugar.

Hasta ahora funciona bien para nosotros usando la solicitud de WorkManager periódico.

Actualización: Terminé escribiendo 2 publicaciones medianas de la serie al respecto.

Wahib Ul Haq
fuente