您可以使用 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
權限。 - 如果應用程式指定 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 掃描節流」)。