網(wǎng)站首頁 編程語言 正文
WLAN 掃描流程
掃描流程分為三步:
- 為 SCAN_RESULTS_AVAILABLE_ACTION 注冊一個廣播監(jiān)聽器,系統(tǒng)會在完成掃描請求時調(diào)用此監(jiān)聽器,提供其成功/失敗狀態(tài)。對于搭載 Android 10(API 級別 29)及更高版本的設(shè)備,系統(tǒng)將針對平臺或其他應(yīng)用在設(shè)備上執(zhí)行的所有完整 WLAN 掃描發(fā)送此廣播。應(yīng)用可以使用廣播被動監(jiān)聽設(shè)備上所有掃描的完成情況,無需發(fā)出自己的掃描。
- 使用 WifiManager.startScan() 請求掃描。請務(wù)必檢查方法的返回狀態(tài),因?yàn)檎{(diào)用可能因以下任一原因失敗:
- 由于短時間掃描過多,掃描請求可能遭到節(jié)流。
- 設(shè)備處于空閑狀態(tài),掃描已停用。
- WLAN 硬件報告掃描失敗。 - 使用 WifiManager.getScanResults() 獲取掃描結(jié)果。系統(tǒng)返回的掃描結(jié)果為最近更新的結(jié)果,但如果當(dāng)前掃描尚未完成或成功,可能會返回以前掃描的結(jié)果。也就是說,如果在收到成功的 SCAN_RESULTS_AVAILABLE_ACTION 廣播前調(diào)用此方法,您可能會獲得較舊的掃描結(jié)果。
以下代碼提供了如何實(shí)現(xiàn)這些步驟的示例:
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)引入了有關(guān)權(quán)限和 WLAN 掃描允許頻率的限制。
為了提高網(wǎng)絡(luò)性能和安全性,延長電池續(xù)航時間,Android 9(API 級別 28)收緊了權(quán)限要求,并進(jìn)一步限制 WLAN 掃描頻率。
權(quán)限
注意:在以下提到位置權(quán)限或位置收集邏輯的各個部分中,請記住,當(dāng)應(yīng)用在后臺運(yùn)行時,獲取位置信息訪問權(quán)限對于應(yīng)用的核心功能而言至關(guān)重要,同時需要向用戶提供適當(dāng)?shù)穆暶鳌?br>Android 8.0 和 Android 8.1:
成功調(diào)用 WifiManager.getScanResults() 需要以下任意一項(xiàng)權(quán)限:
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
CHANGE_WIFI_STATE
對于上述權(quán)限,如果調(diào)用應(yīng)用一項(xiàng)都不具備,調(diào)用將會失敗,并顯示 SecurityException。
或者,在搭載 Android 8.0(API 級別 26)及更高版本的設(shè)備上,您可以使用 CompanionDeviceManager 代表應(yīng)用對附近的配套設(shè)備執(zhí)行掃描,而不需要位置權(quán)限。如需詳細(xì)了解此選項(xiàng),請參閱配套設(shè)備配對。
Android 9:
成功調(diào)用 WifiManager.startScan() 需要滿足以下所有條件:
- 應(yīng)用擁有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 權(quán)限。
- 應(yīng)用擁有 CHANGE_WIFI_STATE 權(quán)限。
- 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。
Android 10(API 級別 29)及更高版本:
成功調(diào)用 WifiManager.startScan() 需要滿足以下所有條件:
- 如果您的應(yīng)用以 Android 10(API 級別 29)SDK 或更高版本為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_FINE_LOCATION 權(quán)限。
- 如果您的應(yīng)用以低于 Android 10(API 級別 29)的 SDK 為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 權(quán)限。
- 應(yīng)用擁有 CHANGE_WIFI_STATE 權(quán)限。
- 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。
若要成功調(diào)用 WifiManager.getScanResults(),請確保滿足以下所有條件:
- 如果您的應(yīng)用以 Android 10(API 級別 29)SDK 或更高版本為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_FINE_LOCATION 權(quán)限。
- 如果您的應(yīng)用以低于 Android 10(API 級別 29)的 SDK 為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 權(quán)限。
- 應(yīng)用擁有 ACCESS_WIFI_STATE 權(quán)限。
- 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。
如果調(diào)用應(yīng)用無法滿足上述所有要求,調(diào)用將失敗,并顯示 SecurityException。
節(jié)流
使用 WifiManager.startScan() 掃描的頻率適用以下限制。
Android 8.0 和 Android 8.1:
每個后臺應(yīng)用可以在 30 分鐘內(nèi)掃描一次。
Android 9:
每個前臺應(yīng)用可以在 2 分鐘內(nèi)掃描四次。這樣便可在短時間內(nèi)進(jìn)行多次掃描。
所有后臺應(yīng)用總共可以在 30 分鐘內(nèi)掃描一次。
Android 10 及更高版本:
適用 Android 9 的節(jié)流限制。新增一個開發(fā)者選項(xiàng),用戶可以關(guān)閉節(jié)流功能以便進(jìn)行本地測試(位于開發(fā)者選項(xiàng) > 網(wǎng)絡(luò) > WLAN 掃描調(diào)節(jié)下)。
實(shí)際調(diào)試代碼如下:
package com.mob.testwifi;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
WifiManager wifiManager;
TextView tv;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.result);
if (ContextCompat.checkSelfPermission(
MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// You can use the API that requires the permission.
wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(wifiScanReceiver, intentFilter);
boolean success = wifiManager.startScan();
if (!success) {
// scan failure handling
scanFailure();
}
} else {
// You can directly ask for the permission.
requestPermissions(
new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
},
1);
}
}
BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context c, Intent intent) {
boolean success = intent.getBooleanExtra(
WifiManager.EXTRA_RESULTS_UPDATED, false);
tv.setText("success:\n" + success);
if (success) {
scanSuccess();
} else {
// scan failure handling
scanFailure();
}
}
};
private void scanSuccess() {
List<ScanResult> results = wifiManager.getScanResults();
tv.setText(results.toString());
}
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();
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("scanFailure:\n" + results.toString());
}
});
}
}
注:
本文參考Android官方開發(fā)文檔
原文鏈接:https://blog.csdn.net/chaihuasong/article/details/120281705
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2024-01-15 IDEA 常量字符串過長問題
- 2022-06-02 Kubernetes關(guān)鍵組件與結(jié)構(gòu)組成介紹_云和虛擬化
- 2022-09-16 Numpy中的shape、reshape函數(shù)的區(qū)別_python
- 2024-01-12 JPA實(shí)現(xiàn)不等于查詢
- 2022-02-28 Error: A <Route> is only ever to be used as the ch
- 2023-01-05 find?命令全集_linux shell
- 2022-04-17 sessionStorage與localStorage
- 2022-08-01 MongoDB基礎(chǔ)之文檔操作_MongoDB
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支