Як виявити, коли в Android встановлено підключення WIFI?


140

Мені потрібно виявити наявність у мене підключення до мережі через 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 (), і ми більше не будемо отримувати події, пов’язані з wifi
zafar142003

Відповіді:


126

Ви можете зареєструвати BroadcastReceiverсповіщення, коли буде встановлено з'єднання Wi-Fi (або якщо з'єднання було змінено).

Зареєструйте 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 до цього.

EDIT: Завдяки забороні геоінженерії, ось метод перевірити, чи пристрій вже підключено:

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 зміни мовлення. Чому SUPPLCANT ??? дякую
Androider

2
так? Я не бачу дії, яка називається connection_change ...? Я бачу лише зміну стану Wi-Fi, але ця дія вказує лише на те, чи увімкнено Wi-Fi (чи ввімкнено / відключено), чи не підключено він ... чи не працює те, що потрібно?
jpm

9
Для мене WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION не працює у випадку, коли підключення до відомої wifi станції було встановлено / втрачено. Але WifiManager.NETWORK_STATE_CHANGED_ACTION дійсно працює.
Яр

1
"android.net.wifi.STATE_CHANGE" працював на мене. перевіри мою відповідь нижче
М. Усман Хан

1
"Звичайно, ви повинні перевірити, чи пристрій вже підключено до WiFi до цього." - тож, щоб отримати початковий стан Wi-Fi, ви можете скористатися цим методом ...private boolean isConnectedViaWifi() { ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi.isConnected(); }
заборона-геоінженерія

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
Я вважаю, що це найкраща відповідь для конкретної передачі стану wifi. Спасибі
Мікель

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 (), і ми більше не будемо отримувати події, пов’язані з wifi.
zafar142003

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?
бехеліт

1
Також хотіли б знати, що таке wifiState, як він створювався
Еван Парсонс,

1
@behelit зараз "wifiState" є в редагованій відповіді.
Йогу Гуру

8

Ви можете запустити з'єднання через Wi-Fi, якщо надавати користувачеві вибір, щоб перекрити нормальну поведінку запиту кожного разу.

Я вирішив використовувати три методи ...

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

Це швидка перевірка, чи є підключення до Інтернету або Wifi, або 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
fyi, на Android 6, коли у вас є дійсне з'єднання для передачі даних в стільникові, зміни стану wifi не спричинить 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

3

Ось приклад мого коду, який враховує перевагу користувачів, які дозволяють створювати комікси лише під час підключення до Wifi.

Я телефоную цьому коду зсередини, 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

Android O усунув можливість отримувати неявні трансляції для зміни стану wifi. Тож якщо ваш додаток закрито, ви не зможете їх отримувати. Новий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()
    }
}

Майте на увазі, що це був лише швидкий тест на разове повідомлення. Є ще робота, щоб завжди отримувати сповіщення, коли WiFi вмикається та вимикається.

PS: Коли додаток примусово виходить, працівник не запускається, схоже WorkManager, скасовує запити тоді.


Чи є спосіб запустити працівника, навіть якщо в моєму додатку закрито стан. Менеджер роботи працює з .setRequiredNetworkType (UNMETERED), лише якщо програма відкрита. Чи є спосіб запускати працівника, навіть програма вбита (сила закрита). Тому що неявний широкосмуговий приймач також дещо обмежений. Яка буде найкраща альтернатива?
Суреш

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

У мене є два способи виявлення 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 (), і ми більше не будемо отримувати події, пов’язані з wifi
zafar142003


2

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

2) Я також спробував Firebase Dispatcher, який працює, але не виходить за межі програми.

3) Рекомендований спосіб знайдеться WorkManager для гарантування виконання поза процесом вбитого та внутрішньо за допомогою registerNetworkRequest ()

Найбільші докази на користь підходу №3 наводить сам Android doc . Спеціально для програм у фоновому режимі.

Також тут

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

Поки що це працює добре для нас за допомогою періодичного запиту WorkManager.

Оновлення: я закінчив писати про це 2-х серійних середніх публікацій .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.