Como detectar quando a conexão WIFI foi estabelecida no Android?

140

Preciso detectar quando tenho conectividade de rede por WIFI. Qual transmissão é enviada para estabelecer que uma conexão de rede válida foi feita. Preciso validar se existe uma conexão de rede válida para HTTP. O que devo ouvir e que testes adicionais eu preciso fazer para saber que existe uma conexão válida.

Androider
fonte
Partes desta pergunta foram respondidas aqui, encontrei: stackoverflow.com/questions/4238921/…
Androider
1
Mas ainda há a questão de QUANDO verificar essas condições?
Borde
1
Gostaria de receber feedback se houver transmissões que possam ser capturadas por um receptor de transmissão?
Borde
1
Como fazer isso no Android O, já que os receptores de transmissão implícitos como android.net.wifi.STATE_CHANGE não poderão mais ser registrados no manifesto (consulte developer.android.com/guide/components/… ). Se nós registrá-lo na atividade de aplicação (dizem onCreate), então ele terá que ter seus registros cancelados no onStop (), e já não receberá eventos relacionados wi-fi
zafar142003

Respostas:

126

Você pode registrar um BroadcastReceiverpara ser notificado quando uma conexão WiFi for estabelecida (ou se a conexão for alterada).

Registre o BroadcastReceiver:

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

E então no seu BroadcastReceiverfaça algo parecido com isto:

@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 mais informações, consulte a documentação BroadcastReceivereWifiManager

É claro que você deve verificar se o dispositivo já está conectado ao Wi-Fi antes disso.

EDIT: Graças à proibição de geoengenharia, aqui está um método para verificar se o dispositivo já está conectado:

private boolean isConnectedViaWifi() {
     ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
     NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);     
     return mWifi.isConnected();
}
jpm
fonte
1
Por que SUPPLICANT_CONECTION_CHANGE_ACTION? Eu pensei que era JUST CONNECTION_CHANGE transmissão de alteração. Por que SUPPLCANT ??? obrigado
Androider
2
Hã? Não vejo uma ação chamada connection_change ...? Vejo apenas o estado do wifi alterado, mas essa ação indica apenas se o wifi está ativado ou não (ou ativando / desativando) e não se está conectado ... supplicant_connection_change_action não está fazendo o que você precisa?
jpm
9
Para mim, o WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION não funciona no caso em que a conexão a uma estação wifi conhecida foi estabelecida / perdida. Mas o WifiManager.NETWORK_STATE_CHANGED_ACTION funciona.
Yar
1
"android.net.wifi.STATE_CHANGE" funcionou para mim. verifique minha resposta abaixo
M. Usman Khan
1
"Claro que você deve verificar se o dispositivo já está conectado ao WiFi antes disso." - por isso, para obter o estado inicial Wi-Fi, você pode usar esse método ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
ban-geoengenharia
106

O melhor que funcionou para mim:

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

Permissões

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
M. Usman Khan
fonte
1
Eu acho que esta é a melhor resposta para chage estado wifi especificamente. Obrigado
Mikel
4
Para referência fácil futura, essa ação codificada é WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage
3
if (info! = null && info.isConnected ()) = sem espaguete.
gswierczynski
1
precisamos escrever algum código para enviar transmissão na atividade principal?
Nisari Balakrishnan
1
Como fazer isso no Android O, já que os receptores de transmissão implícitos como android.net.wifi.STATE_CHANGE não poderão mais ser registrados no manifesto (consulte developer.android.com/guide/components/… ). Se o registrarmos na atividade de aplicativo (por exemplo, onCreate), será necessário cancelar o registro em onStop () e não receberemos mais eventos relacionados a wifi.
precisa saber é o seguinte
18

Para mim só WifiManager.NETWORK_STATE_CHANGED_ACTIONfunciona.

Registre um receptor de transmissão:

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

e receba:

@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
fonte
1
Para mim, apenas WifiManager.NETWORK_STATE_CHANGED_ACTION funcionou, alguma explicação para a razão pela qual apenas isso funcionará?
benchuk
11

As respostas dos usuários @JPM e @usman são realmente muito úteis. Funciona bem, mas no meu caso, ele vem onReceivevárias vezes no meu caso 4 vezes, então meu código é executado várias vezes.

Eu faço algumas modificações e faço conforme minha exigência e agora chega apenas 1 vez

Aqui está a classe 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 ----- ");
        }

    }
}
}

No 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
fonte
1
o que é wifiState?
precisa saber é
1
Também gostaria de saber o que é wifiState, como foi gerado #
Evan Parsons
1
@behelit agora "wifiState" está lá na resposta editada.
Yog Guru
8

Você pode iniciar uma conexão wifi se der ao usuário a opção de substituir o comportamento normal de perguntar a cada vez.

Eu escolho usar três métodos ...

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

Esta é uma verificação rápida, se houver uma conexão à Internet, Wifi ou CellData. A partir daqui, você pode escolher qual ação deseja executar. É no modo avião também precisa ser verificado.

Em um segmento separado. Defino uma variável IpAddress como = "" E sigo até que eu tenha um endereço IP válido.

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

Outro trecho de código ... Se não estiver ativado, ative-o (com permissão prévia dos usuários)

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

Para detectar o estado da conexão WIFI, usei CONNECTIVITY_ACTION da classe ConnectivityManager para:

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

e do seu 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 bem para mim :)

amina
fonte
1
fyi, com o Android 6 quando você tem uma conexão de dados de célula válida, as alterações no estado wifi não acionam CONNECTIVITY_ACTION. A única razão pela qual eles fizeram foi o estado de conectividade ter sido impactado, agora não é.
Bruce
5

Este código não requer permissão. Ele é restrito apenas às alterações do estado da conectividade da rede Wi-Fi (qualquer outra rede não é levada em consideração). O destinatário é publicado estaticamente no arquivo AndroidManifest.xml e não precisa ser exportado, pois será chamado pelo sistema protected broadcast,NETWORK_STATE_CHANGED_ACTION , a cada mudança de estado de conectividade de rede.

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

Permissões:

None
Codegateway
fonte
1
Funciona em dispositivos executando <API 26. Como @Isham sugeriu que a ação não é mais suportada no Android O
tiagocarvalho92
3

Aqui está um exemplo do meu código, que leva em consideração a preferência do usuário em permitir apenas comunicações quando conectado ao Wifi.

Estou chamando esse código de dentro de um IntentServiceantes de tentar baixar coisas.

Observe que isso NetworkInfoocorrerá nullse não houver nenhum tipo de conexão de rede.

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

O Android O removeu a possibilidade de receber transmissões implícitas para uma alteração de estado do wifi. Portanto, se seu aplicativo estiver fechado, você não poderá recebê-los. O novoWorkManager tem a capacidade de executar quando seu aplicativo é fechado, então eu experimentei um pouco com ele e parece funcionar muito bem:

Adicione isso às suas dependências:

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

Lembre-se de que este foi apenas um teste rápido para uma notificação única. Há mais trabalho a ser feito para sempre ser notificado quando o Wi-Fi está ligado e desligado.

PS: Quando o aplicativo é forçado a sair , o trabalhador não é iniciado, parece que WorkManagerestá cancelando os pedidos.

Marius
fonte
Existe alguma maneira de iniciar o trabalhador, mesmo se meu aplicativo for um estado encerrado à força. O gerente de trabalho está trabalhando com .setRequiredNetworkType (UNMETERED) apenas se o aplicativo estiver aberto. Existe alguma maneira de acionar o trabalhador, mesmo que o aplicativo esteja morto (estado de força fechada). Porque o receptor implícito de elenco amplo também é um pouco restrito. Qual será a melhor alternativa?
Suresh
2

Eu usei 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
fonte
2

Eu tenho dois métodos para detectar a conexão WIFI que recebe o contexto do aplicativo:

1) meu método antigo

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) meu novo método (atualmente estou usando esse 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
fonte
Como fazer isso no Android O, já que os receptores de transmissão implícitos como android.net.wifi.STATE_CHANGE não poderão mais ser registrados no manifesto (consulte developer.android.com/guide/components/… ). Se nós registrá-lo na atividade de aplicação (dizem onCreate), então ele terá que ter seus registros cancelados no onStop (), e já não receberá eventos relacionados wi-fi
zafar142003
2

1) Tentei também a abordagem do Broadcast Receiver, apesar de saber que CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE está obsoleto na API 28 e não é recomendado. Também vinculado ao uso de registro explícito, ele escuta enquanto o aplicativo estiver em execução.

2) Eu também tentei o Firebase Dispatcher, que funciona, mas não além do aplicativo morto.

3) A maneira recomendada encontrada é o WorkManager para garantir a execução além do processo interrompido e internamente usando registerNetworkRequest ()

A maior evidência a favor da abordagem nº 3 é referida pelo próprio documento do Android . Especialmente para aplicativos em segundo plano.

Também aqui

No Android 7.0, estamos removendo três transmissões implícitas comumente usadas - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE e ACTION_NEW_VIDEO -, pois elas podem ativar os processos em segundo plano de vários aplicativos ao mesmo tempo e sobrecarregar a memória e a bateria. Se o seu aplicativo estiver recebendo, aproveite o Android 7.0 para migrar para o JobScheduler e APIs relacionadas.

Até agora, funciona bem para nós usando a solicitação Periodic WorkManager.

Atualização: Acabei escrevendo um post médio de 2 séries sobre isso.

Wahib Ul Haq
fonte