您可以使用 WifiManager API 提供的 Wi-Fi 扫描功能,获取设备可见的 Wi-Fi 接入点列表。
WLAN 扫描流程
扫描流程分为三步:
为
SCAN_RESULTS_AVAILABLE_ACTION注册广播监听器,该监听器会在扫描请求完成时发送,并提供其成功或失败状态。对于搭载 Android 10(API 级别 29)及更高版本的设备,系统将针对平台或其他应用在设备上执行的所有完整 WLAN 扫描发送此广播。应用可以使用广播被动监听设备上所有扫描的完成情况,无需发出自己的扫描。使用
WifiManager.startScan()请求扫描。请务必检查该方法的返回状态,因为调用可能会因以下任一原因而失败:- 由于短时间内扫描次数过多,扫描请求可能会受到限制。
- 设备处于空闲状态,扫描已停用。
- WLAN 硬件报告扫描失败。
使用
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)引入了有关权限和 WLAN 扫描允许频率的限制。
为了提高网络性能和安全性,延长电池续航时间,Android 9(API 级别 28)收紧了权限要求,并进一步限制 WLAN 扫描频率。
权限
Android 8.0(API 级别 26)和 Android 8.1(API 级别 27):
成功调用 WifiManager.getScanResults() 需要以下任一权限:
对于上述权限,如果调用应用一项都不具备,调用将会失败,并显示 SecurityException。
或者,在搭载 Android 8.0(API 级别 26)及更高版本的设备上,您可以使用 CompanionDeviceManager 代表应用执行附近配套设备扫描,而无需位置信息权限。如需详细了解此选项,请参阅配套设备配对。
Android 9(API 级别 28):
成功调用 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 的节流限制。有一个新的开发者选项,可用于关闭本地测试的限制(在开发者选项 > 网络 > WLAN 扫描限制下)。