Обзор сканирования 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 ...
}

Java

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 для сканирования ближайших устройств-компаньонов от имени вашего приложения без запроса разрешения на определение местоположения. Подробнее об этой опции см. в разделе «Сопряжение устройств-компаньонов» .

Android 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 минут.

Android 9:

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

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

Android 10 и выше:

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