Как определить, что в Android установлено WIFI-соединение?


142

Мне нужно определить, есть ли у меня подключение к сети через WIFI. Какая трансляция отправляется, чтобы установить, что установлено действительное сетевое соединение. Мне нужно убедиться, что существует допустимое сетевое соединение для HTTP. Что я должен слушать и какие дополнительные тесты мне нужно сделать, чтобы узнать, существует ли действительное соединение.


Здесь я нашел ответы на некоторые части этого вопроса: stackoverflow.com/questions/4238921/…
Androider

1
Но все еще остается вопрос, КОГДА проверять эти условия?
Androider

1
Я хотел бы получить отзывы о том, будут ли происходить трансляции, которые могут быть пойманы приемником трансляции?
Androider

1
Как я могу сделать это на Android O, поскольку приемники неявного вещания, такие как android.net.wifi.STATE_CHANGE, больше не смогут быть зарегистрированы в манифесте (см. Developer.android.com/guide/components/… ). Если мы зарегистрируем его в активности приложения (скажем, onCreate), то его придется отменить в onStop (), и мы больше не будем получать события, связанные с Wi-Fi,
zafar142003

Ответы:


127

Вы можете зарегистрировать, BroadcastReceiverчтобы получать уведомления, когда соединение WiFi установлено (или если соединение изменилось).

Зарегистрируйте BroadcastReceiver:

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

А затем в вашем 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)) {
            //do stuff
        } else {
            // wifi connection was lost
        }
    }
}

Для получения дополнительной информации см. Документацию для BroadcastReceiverиWifiManager

Конечно, перед этим вы должны проверить, подключено ли устройство к WiFi.

РЕДАКТИРОВАТЬ: Благодаря ban-geoengineering вот способ проверить, подключено ли уже устройство:

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

1
Почему SUPPLICANT_CONECTION_CHANGE_ACTION? Я думал, что это просто трансляция изменения CONNECTION_CHANGE. Почему СЛАДКА ??? спасибо
Androider

2
а? Я не вижу действия с именем connection_change ...? Я вижу только изменение состояния Wi-Fi, но это действие только указывает, включен ли Wi-Fi (или включение / отключение), а не подключен ли он ... supplicant_connection_change_action не делает то, что вам нужно?
jpm

9
Для меня WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION не работает в случае, если соединение с известной Wi-Fi станцией было установлено / потеряно. Но WifiManager.NETWORK_STATE_CHANGED_ACTION действительно работает.
Яр

1
"android.net.wifi.STATE_CHANGE" работал у меня. проверьте мой ответ ниже
М. Усман Хан

1
«Конечно, перед этим вы должны проверить, подключено ли устройство к Wi-Fi». - Итак, чтобы получить начальное состояние Wi-Fi, вы можете использовать этот метод ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
ban-geoengineering

106

Лучшее, что сработало для меня:

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 класс

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

Разрешения

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

1
Я думаю, что это лучший ответ на конкретное изменение состояния Wi-Fi. Спасибо
Mikel

4
Для удобства использования в будущем это жестко запрограммированное действие - WifiManager.NETWORK_STATE_CHANGED_ACTION .
Anonsage

3
if (info! = null && info.isConnected ()) = без спагетти.
gswierczynski

1
нам нужно написать какой-либо код для отправки трансляции в основной деятельности ??
Нисари Балакришнан

1
Как я могу сделать это на Android O, поскольку приемники неявного вещания, такие как android.net.wifi.STATE_CHANGE, больше не смогут быть зарегистрированы в манифесте (см. Developer.android.com/guide/components/… ). Если мы зарегистрируем его в активности приложения (скажем, onCreate), то его нужно будет отменить в onStop (), и мы больше не будем получать события, связанные с Wi-Fi.
zafar142003 03

18

У меня только WifiManager.NETWORK_STATE_CHANGED_ACTIONработает.

Зарегистрируйте широковещательный приемник:

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

и получите:

@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
Для меня также работал только WifiManager.NETWORK_STATE_CHANGED_ACTION, какие-либо объяснения причины, почему только это будет работать?
бенчук

11

Ответ пользователя @JPM и @usman действительно очень полезен. Он работает нормально, но в моем случае это происходит onReceiveнесколько раз, в моем случае 4 раза, поэтому мой код выполняется несколько раз.

Я делаю некоторые модификации и делаю согласно моим требованиям, и теперь это приходит только 1 раз

Вот класс Java для трансляции.

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

    }
}
}

В 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
что такое wifiState?
behelit

1
Также хотел бы знать, что такое wifiState, как он был сгенерирован
Эван Парсонс

1
@behelit теперь "wifiState" присутствует в отредактированном ответе.
Yog Guru

8

Вы можете запустить Wi-Fi-соединение, если дадите пользователю возможность переопределить нормальное поведение запроса каждый раз.

Я предпочитаю использовать три метода ...

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

Это быстрая проверка, есть ли подключение к Интернету: Wi-Fi или CellData. Отсюда вы можете выбрать, какое действие вы хотите предпринять. Также необходимо проверить, находится ли он в режиме полета.

В отдельной ветке. Я устанавливаю для переменной IpAddress значение = "" и опрашиваю, пока не получу действующий IP-адрес.

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

Другой фрагмент кода ... Если он не включен, включите его (с предварительного разрешения пользователя)

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

7

Чтобы определить состояние подключения WIFI, я использовал CONNECTIVITY_ACTION из класса ConnectivityManager, поэтому:

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

и из вашего 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: у меня отлично работает :)


1
К вашему сведению, с Android 6, когда у вас есть действующее соединение для передачи данных в ячейке, изменения в состоянии Wi-Fi не будут вызывать CONNECTIVITY_ACTION. Единственная причина, по которой они это сделали, - это повлияло на состояние подключения, теперь это не так.
Брюс

5

Этот код вообще не требует разрешения. Это ограничено только изменением состояния подключения к сети Wi-Fi (другие сети не учитываются). Приемник статически публикуется в файле AndroidManifest.xml и не должен быть экспортирован как она будет вызываться системой protected broadcast, NETWORK_STATE_CHANGED_ACTIONпри каждом изменении состояния сети связи.

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:

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

Разрешения:

None

1
Работает на устройствах с <API 26. Как предположил @Isham, это действие больше не поддерживается в Android O
tiagocarvalho92

4

Android O удалил возможность получать неявные трансляции для изменения состояния Wi-Fi. Поэтому, если ваше приложение закрыто, вы не сможете их получить. У нового WorkManagerесть возможность запускаться, когда ваше приложение закрыто, поэтому я немного поэкспериментировал с ним, и, похоже, он работает довольно хорошо:

Добавьте это в свои зависимости:

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

Имейте в виду, что это была всего лишь быстрая проверка одноразового уведомления. Чтобы всегда получать уведомления, когда Wi-Fi включается и выключается, нужно еще поработать.

PS: Когда приложение закрывается принудительно , рабочий не запускается, похоже WorkManager, тогда отменяет запросы.


Есть ли способ запустить worker, даже если мое приложение принудительно завершено. Диспетчер работ работает с .setRequiredNetworkType (UNMETERED), только если приложение открыто. Есть ли способ вызвать работника, даже если приложение убито (принудительное закрытое состояние). Потому что неявный широковещательный приемник тоже несколько ограничен. Что будет лучшей альтернативой?
Суреш

3

Вот пример моего кода, который учитывает предпочтения пользователей разрешать связь только при подключении к Wi-Fi.

Я вызываю этот код изнутри, IntentServiceпрежде чем попытаюсь загрузить материал.

Обратите внимание, что NetworkInfoэто будет, nullесли нет какого-либо сетевого подключения.

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

У меня есть два метода обнаружения WIFI-соединения, получающего контекст приложения:

1) мой старый метод

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) мой Новый метод (сейчас я использую этот метод):

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

Как я могу сделать это на Android O, поскольку приемники неявного вещания, такие как android.net.wifi.STATE_CHANGE, больше не смогут быть зарегистрированы в манифесте (см. Developer.android.com/guide/components/… ). Если мы зарегистрируем его в активности приложения (скажем, onCreate), то его нужно будет отменить в onStop (), и мы больше не будем получать события, связанные с Wi-Fi
zafar142003

2

Я использовал этот код:

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

1) Я также пробовал подход Broadcast Receiver, хотя я знаю, что CONNECTIVITY_ACTION / CONNECTIVITY_CHANGE устарело в API 28 и не рекомендуется. Также привязан к использованию явного регистра, он прослушивает, пока приложение работает.

2) Я также попробовал Firebase Dispatcher, который работает, но не за пределами приложения.

3) Рекомендуемый найденный способ - WorkManager, чтобы гарантировать выполнение за пределами убитого процесса и внутренне с помощью registerNetworkRequest ()

Самым большим доказательством в пользу подхода №3 является сам документ Android . Специально для приложений, работающих в фоновом режиме.

Также здесь

В Android 7.0 мы удаляем три часто используемых неявных трансляции - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE и ACTION_NEW_VIDEO - поскольку они могут разбудить фоновые процессы сразу нескольких приложений и нагружать память и батарею. Если ваше приложение получает их, воспользуйтесь преимуществами Android 7.0 для перехода на JobScheduler и связанные с ним API.

Пока у нас все работает с использованием Periodic WorkManager request.

Обновление: в итоге я написал об этом средний пост из 2 серий .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.