您可以使用 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 (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權限。 - 如果應用程式指定的 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 的調節限制同樣適用。我們新增了開發人員選項,可關閉本機測試的節流功能 (位於「Developer Options」>「Networking」>「Wi-Fi scan throttling」)。