您可以使用 WifiManager API 提供的 Wi-Fi 扫描功能,获取设备可见的 Wi-Fi 接入点列表。
Wi-Fi 扫描过程
扫描过程分为三个步骤:
注册广播监听器以接收
SCAN_RESULTS_AVAILABLE_ACTION
。当扫描请求完成时,会调用此监听器,并提供其成功/失败状态。对于运行 Android 10(API 级别 29)及更高版本的设备,此广播将针对平台或其他应用在设备上执行的任何完整 Wi-Fi 扫描发送。应用可以通过使用此广播被动监听设备上所有扫描完成情况,而无需自行发起扫描。使用
WifiManager.startScan()
请求扫描。务必检查方法的返回状态,因为调用可能会因以下任何原因失败:- 短时间内扫描次数过多,扫描请求可能受到限制。
- 设备处于空闲状态且扫描已禁用。
- Wi-Fi 硬件报告扫描失败。
使用
WifiManager.getScanResults()
获取扫描结果。返回的扫描结果是最新的结果,如果当前扫描尚未完成或成功,则可能来自之前的扫描。这意味着,如果您在收到成功的SCAN_RESULTS_AVAILABLE_ACTION
广播之前调用此方法,则可能会获取较旧的扫描结果。
以下代码提供了如何实现这些步骤的示例:
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 ... }
限制
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
权限。 - 如果您的应用面向低于 Android 10(API 级别 29)的 SDK,则您的应用具有
ACCESS_COARSE_LOCATION
或ACCESS_FINE_LOCATION
权限。 - 您的应用具有
CHANGE_WIFI_STATE
权限。 - 设备上已启用定位服务(在设置 > 位置信息下)。
要成功调用 WifiManager.getScanResults()
,请确保满足以下所有条件:
- 如果您的应用面向 Android 10(API 级别 29)SDK 或更高版本,则您的应用具有
ACCESS_FINE_LOCATION
权限。 - 如果您的应用面向低于 Android 10(API 级别 29)的 SDK,则您的应用具有
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 扫描限制下)。