Обзор сканирования Wi-Fi

Вы можете использовать возможности сканирования Wi-Fi, предоставляемые API WifiManager , чтобы получить список точек доступа Wi-Fi, видимых с устройства.

Процесс сканирования Wi-Fi

Процесс сканирования состоит из трех этапов:

  1. Зарегистрируйте широковещательный прослушиватель для SCAN_RESULTS_AVAILABLE_ACTION , который вызывается после завершения запросов сканирования и предоставляет их статус успеха/неудачи. Для устройств под управлением Android 10 (уровень API 29) и выше эта трансляция будет отправляться при любом полном сканировании Wi-Fi, выполняемом на устройстве платформой или другими приложениями. Приложения могут пассивно прослушивать все завершения сканирования на устройстве, используя широковещательную рассылку, не выполняя собственное сканирование.

  2. Запросите сканирование с помощью WifiManager.startScan() . Обязательно проверьте статус возврата метода, поскольку вызов может завершиться неудачей по любой из следующих причин:

    • Запросы на сканирование могут быть ограничены из-за слишком большого количества сканирований за короткое время.
    • Устройство находится в режиме ожидания, сканирование отключено.
    • Оборудование Wi-Fi сообщает об ошибке сканирования.
  3. Получите результаты сканирования с помощью WifiManager.getScanResults() . Возвращенные результаты сканирования — это самые последние обновленные результаты, которые могут быть результатом предыдущего сканирования, если текущее сканирование не было завершено или не удалось. Это означает, что вы можете получить более старые результаты сканирования, если вызовете этот метод до получения успешного широковещательного сообщения SCAN_RESULTS_AVAILABLE_ACTION .

Следующий код представляет собой пример реализации этих шагов:

Котлин

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } else {
      scanFailure()
    }
  }
}

val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  // scan failure handling
  scanFailure()
}

....

private fun scanSuccess() {
  val results = wifiManager.scanResults
  ... use new scan results ...
}

private fun scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  val results = wifiManager.scanResults
  ... potentially use older scan results ...
}

Ява

WifiManager wifiManager = (WifiManager)
                   context.getSystemService(Context.WIFI_SERVICE);

BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context c, Intent intent) {
    boolean success = intent.getBooleanExtra(
                       WifiManager.EXTRA_RESULTS_UPDATED, false);
    if (success) {
      scanSuccess();
    } else {
      // scan failure handling
      scanFailure();
    }
  }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(wifiScanReceiver, intentFilter);

boolean success = wifiManager.startScan();
if (!success) {
  // scan failure handling
  scanFailure();
}

....

private void scanSuccess() {
  List<ScanResult> results = wifiManager.getScanResults();
  ... use new scan results ...
}

private void scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  List<ScanResult> results = wifiManager.getScanResults();
  ... potentially use older scan results ...
}

Ограничения

В Android 8.0 (уровень API 26) введены ограничения относительно разрешений и разрешенной частоты сканирования Wi-Fi.

Чтобы улучшить производительность сети, безопасность и время автономной работы, Android 9 (уровень API 28) ужесточил требования к разрешениям и еще больше ограничил частоту сканирования Wi-Fi.

Разрешения

Android 8.0 и Android 8.1:

Для успешного вызова WifiManager.getScanResults() требуется любое из следующих разрешений:

Если вызывающее приложение не имеет ни одного из этих разрешений, вызов завершается с ошибкой SecurityException .

Кроме того, на устройствах под управлением Android 8.0 (уровень API 26) и выше вы можете использовать CompanionDeviceManager для сканирования близлежащих сопутствующих устройств от имени вашего приложения, не требуя разрешения на определение местоположения. Дополнительную информацию об этой опции см. в разделе Сопряжение устройств-компаньонов .

Андроид 9:

Для успешного вызова WifiManager.startScan() необходимо выполнение всех следующих условий:

  • Ваше приложение имеет разрешение ACCESS_FINE_LOCATION или ACCESS_COARSE_LOCATION .
  • Ваше приложение имеет разрешение CHANGE_WIFI_STATE .
  • На устройстве включены службы определения местоположения (в разделе «Настройки» > «Местоположение» ).

Android 10 (уровень API 29) и выше:

Для успешного вызова WifiManager.startScan() необходимо выполнение всех следующих условий:

  • Если ваше приложение ориентировано на SDK Android 10 (уровень API 29) или более поздней версии, у вашего приложения есть разрешение ACCESS_FINE_LOCATION .
  • Если ваше приложение ориентировано на SDK ниже Android 10 (уровень API 29), у вашего приложения есть разрешение ACCESS_COARSE_LOCATION или ACCESS_FINE_LOCATION .
  • Ваше приложение имеет разрешение CHANGE_WIFI_STATE .
  • На устройстве включены службы определения местоположения (в разделе «Настройки» > «Местоположение »).

Чтобы успешно вызвать WifiManager.getScanResults() , убедитесь, что выполнены все следующие условия:

  • Если ваше приложение ориентировано на SDK Android 10 (уровень API 29) или более поздней версии, у вашего приложения есть разрешение ACCESS_FINE_LOCATION .
  • Если ваше приложение ориентировано на SDK ниже Android 10 (уровень API 29), у вашего приложения есть разрешение ACCESS_COARSE_LOCATION или ACCESS_FINE_LOCATION .
  • Ваше приложение имеет разрешение ACCESS_WIFI_STATE .
  • На устройстве включены службы определения местоположения (в разделе «Настройки» > «Местоположение »).

Если вызывающее приложение не соответствует всем этим требованиям, вызов завершается с ошибкой SecurityException .

Регулирование

Следующие ограничения применяются к частоте сканирования с помощью WifiManager.startScan() .

Android 8.0 и Android 8.1:

Каждое фоновое приложение может сканировать один раз в 30 минут.

Андроид 9:

Каждое приложение переднего плана может сканировать четыре раза за 2 минуты. Это позволяет выполнить серию сканирований за короткое время.

Все фоновые приложения в совокупности могут сканировать один раз в 30 минут.

Android 10 и выше:

Применяются те же ограничения регулирования, что и в Android 9. Появилась новая опция для разработчиков, позволяющая отключить регулирование для локального тестирования (в разделе «Параметры разработчика» > «Сеть» > «Регулирование сканирования Wi-Fi »).