WLAN 扫描流程
扫描流程分为三步:

  1. 为 SCAN_RESULTS_AVAILABLE_ACTION 注册一个广播监听器,系统会在完成扫描请求时调用此监听器,提供其成功/失败状态。对于搭载 Android 10(API 级别 29)及更高版本的设备,系统将针对平台或其他应用在设备上执行的所有完整 WLAN 扫描发送此广播。应用可以使用广播被动监听设备上所有扫描的完成情况,无需发出自己的扫描。
  2. 使用 WifiManager.startScan() 请求扫描。请务必检查方法的返回状态,因为调用可能因以下任一原因失败:
    - 由于短时间扫描过多,扫描请求可能遭到节流。
    - 设备处于空闲状态,扫描已停用。
    - WLAN 硬件报告扫描失败。
  3. 使用 WifiManager.getScanResults() 获取扫描结果。系统返回的扫描结果为最近更新的结果,但如果当前扫描尚未完成或成功,可能会返回以前扫描的结果。也就是说,如果在收到成功的 SCAN_RESULTS_AVAILABLE_ACTION 广播前调用此方法,您可能会获得较旧的扫描结果。

以下代码提供了如何实现这些步骤的示例:

WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context c, Intent intent) {boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);if (success) {scanSuccess();} else {// scan failure handlingscanFailure();}}
};IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(wifiScanReceiver, intentFilter);boolean success = wifiManager.startScan();
if (!success) {// scan failure handlingscanFailure();
}....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 和 Android 8.1:

成功调用 WifiManager.getScanResults() 需要以下任意一项权限:

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
CHANGE_WIFI_STATE

对于上述权限,如果调用应用一项都不具备,调用将会失败,并显示 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 的节流限制。新增一个开发者选项,用户可以关闭节流功能以便进行本地测试(位于开发者选项 > 网络 > WLAN 扫描调节下)。

实际调试代码如下:

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)@Overrideprotected 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 handlingscanFailure();}} 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() {@Overridepublic 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 handlingscanFailure();}}};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() {@Overridepublic void run() {tv.setText("scanFailure:\n" + results.toString());}});}
}

注:
本文参考Android官方开发文档

Android 获取Wifi列表详解(包含动态权限申请)相关推荐

  1. android wifi动画显示,Android获取WiFi列表的正确用法

    最近有个需求,需要做一个获取WiFi列表的功能,也在网上找了一些资料,但有些资料是有问题的,然后经过自己的摸索,总结如下: 本地环境: Android Studio版本:3.0.1:DEMO APK ...

  2. android 获取wifi的加密类型,Android WIFI开发:获取wifi列表,连接指定wifi,获取wifi加密方式,监听wifi网络变化等...

    下面是 Android 开发中 WiFi 的常用配置,如:获取当前 WiFi ,扫描 WiFi 获取列表,连接指定 WiFi ,监听网络变化等等. 下面是效果图: GitHub 下载地址:https: ...

  3. 博通wifi驱动详解

    1        WLAN技术 WLAN是英文WirelessLAN的缩写,就是无线局域网的意思.无线以太网技术是一种基于无线传输的局域网技术,与有线网络技术相比,具有灵活.建网迅速.个人化等特点.将 ...

  4. Android百度地图实例详解之仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)

    Android百度地图实例详解之仿摩拜单车APP(包括附近车辆.规划路径.行驶距离.行驶轨迹记录,导航等) 标签: android百度地图行驶轨迹记录共享单车行驶距离和时间 2017-03-08 20 ...

  5. Android Gradle 自定义Task 详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/76408024 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  6. android ------- 开发者的 RxJava 详解

    在正文开始之前的最后,放上 GitHub 链接和引入依赖的 gradle 代码: Github:  https://github.com/ReactiveX/RxJava  https://githu ...

  7. Android开发入门一之Android应用程序架构详解

    Android应用程序架构详解如下: src/ java源代码存放目录 gen/自动生成目录 gen 目录中存放所有由Android开发工具自动生成的文件.目录中最重要的就是R.java文件.这个文件 ...

  8. 《Android NFC开发实战详解》——6.4节Android NFC P2P开发进阶

    本节书摘来自异步社区<Android NFC开发实战详解>一书中的第6章,第6.4节Android NFC P2P开发进阶,作者 赵波,更多章节内容可以访问云栖社区"异步社区&q ...

  9. Android NFC卡实例详解

    Android NFC卡实例详解 公司最近在做一个NFC卡片的工程,经过几天的时间,终于写了一个Demo出来,在此记录下在此过程中遇到的问题.由于之前本人是做iOS的,Android写起来并不是那么的 ...

最新文章

  1. 无聊软件-GIT屏幕录制工具_已迁移
  2. 华为精益敏捷专家:DevOps转型中的那些坑
  3. oracle如何升序,oracle排序操作
  4. 后台开发人员面试内容——Redis非关系数据库(三)
  5. geolocation/ 百度地图api Geolocation 定位当前城市信息
  6. lamda 对比两个list_正式支持多线程!Redis 6.0与老版性能对比评测
  7. Atitit 图像资料文档分类器 netpic image 网络图片与人像图片分类 微信图片分类 D:\0workspace\atiplat_img\src\com\attilax\img\ut
  8. 一文了解 Serverless 2021 大事件
  9. boost电路输出电流公式_boost升压电路参数计算
  10. 关于补码与booth算法的想法与逻辑推导
  11. [CTF]学习资源推荐
  12. 1分钟链圈 | 有趣!BM评价V神新共识算法:这是「非拜占庭容错机制」的终结者...
  13. UNIAPP nvue 地图 markers 不显示
  14. Matlab优化工具箱——Optimization Toolbox
  15. krpano实现多语言切换
  16. 10杯水只有一滴有毒,用四只老鼠测试,二进制的方法快速找出哪瓶有毒;
  17. Stripe国际支付平台接入
  18. 多少秒算长镜头_长镜头的作用
  19. 华为p50鸿蒙系统手机价格,华为P50系列屏幕、镜头、芯片、价格全曝光,预装鸿蒙系统?...
  20. JavaScript WebGL 使用图片疑惑点

热门文章

  1. android自定义队列,Android-自定义Router(路由)
  2. 2023.6.26每日一题
  3. 由骂Iphone的一个帖子,想到中国离世界的差距有多大
  4. 2023最新8个电脑必装软件,新电脑装完好用又高效
  5. html5media:兼容、高效的HTML5视频播放器
  6. 新蜀山服务器最新,新蜀山剑侠 最新攻略
  7. 《啥是佩奇》的一些思考
  8. 我叫MT online刷精英方砖攻略
  9. java 黑白皇后算法_不思议迷宫黑白皇后怎么样 值得培养吗
  10. java通过url获取到上传音视频的时长