Wi-Fi scanning overview

You can use the Wi-Fi scanning capabilities provided by the WifiManager API to get a list of Wi-Fi access points that are visible from the device.

Wi-Fi scanning process

There are three steps to the scanning process:

  1. Register a broadcast listener for SCAN_RESULTS_AVAILABLE_ACTION, which is sent when scan requests are completed, providing their success or failure status. For devices running Android 10 (API level 29) and higher, this broadcast will be sent for any full Wi-Fi scan performed on the device by the platform or other apps. Apps can passively listen to all scan completions on device by using the broadcast without issuing a scan of their own.

  2. Request a scan using WifiManager.startScan(). Make sure to check the return status of the method, because the call might fail for any of the following reasons:

    • Scan requests might be throttled because of too many scans in a short time.
    • The device is idle and scanning is disabled.
    • Wi-Fi hardware reports a scan failure.
  3. Get scan results using WifiManager.getScanResults(). The returned scan results are the most recently updated results, which might be from a previous scan if your current scan hasn't completed or succeeded. This means that you might get older scan results if you call this method before receiving a successful SCAN_RESULTS_AVAILABLE_ACTION broadcast.

The following code provides an example of how to implement these steps:

Kotlin

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 ...
}

Restrictions

Android 8.0 (API level 26) introduced restrictions regarding permissions and the allowed frequency of Wi-Fi scans.

To improve network performance, security, and battery life, Android 9 (API level 28) tightened permission requirements and further limited the frequency of Wi-Fi scans.

Permissions

Android 8.0 (API level 26) and Android 8.1 (API level 27):

A successful call to WifiManager.getScanResults() requires any one of the following permissions:

If the calling app does not have any of these permissions, the call fails with a SecurityException.

Alternatively, on devices running Android 8.0 (API level 26) and higher, you can use the CompanionDeviceManager to perform a scan of nearby companion devices on behalf of your app without requiring the location permission. For more on this option, see Companion device pairing.

Android 9 (API level 28):

A successful call to WifiManager.startScan() requires all of the following conditions to be met:

  • Your app has the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission.
  • Your app has the CHANGE_WIFI_STATE permission.
  • Location services are enabled on the device (under Settings > Location).

Android 10 (API level 29) and higher:

A successful call to WifiManager.startScan() requires all of the following conditions to be met:

  • If your app is targeting Android 10 (API level 29) SDK or higher, your app has the ACCESS_FINE_LOCATION permission.
  • If your app is targeting SDK lower than Android 10 (API level 29), your app has the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.
  • Your app has the CHANGE_WIFI_STATE permission.
  • Location services are enabled on the device (under Settings > Location).

To successfully call WifiManager.getScanResults(), ensure all of the following conditions are met:

  • If your app is targeting Android 10 (API level 29) SDK or higher, your app has the ACCESS_FINE_LOCATION permission.
  • If your app is targeting SDK lower than Android 10 (API level 29), your app has the ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.
  • Your app has the ACCESS_WIFI_STATE permission.
  • Location services are enabled on the device (under Settings > Location).

If the calling app doesn't meet all of these requirements, the call fails with a SecurityException.

Throttling

The following limitations apply to the frequency of scans using WifiManager.startScan().

Android 8.0 and Android 8.1:

Each background app can scan one time in a 30-minute period.

Android 9:

Each foreground app can scan four times in a 2-minute period. This allows for a burst of scans in a short time.

All background apps combined can scan one time in a 30-minute period.

Android 10 and higher:

The same throttling limits from Android 9 apply. There is a new developer option to toggle the throttling off for local testing (under Developer Options > Networking > Wi-Fi scan throttling).