Обзор сканирования 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() необходимо выполнение всех следующих условий:

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

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

  • Если ваше приложение ориентировано на Android 10 (API уровня 29) SDK или выше, у вашего приложения есть разрешение 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:

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

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

Android 10 и выше:

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