Android 扫描WIFI权限详解
作者:ChenYhong 时间:2023-07-03 11:34:32
权限
上篇文章 Android 获取IP和UA中提及了获取WIFI的IP地址,本篇文章介绍下如何扫描WIFI。
官方文档
根据官方文档描述,扫描WIFI需要申请相关权限,如下:
Android 13以上
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--在Android13以上,当usesPermissionFlags设置为neverForLocation时,无需再申请ACCESS_FINE_LOCATION权限-->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation" />
</manifest>
Android 13以下
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
需要注意,在实际测试中,Android 13以上的设备仍然需要申请android.permission.ACCESS_FINE_LOCATION
才能扫描到WIFI,测试设备为小米13。
注册广播监听扫描状态
通过注册广播监听WIFI扫描是否完成,代码如下:
class WIFIExampleActivity : AppCompatActivity() {
private val scanResultReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false) == true) {
// 扫描完成
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 注册广播
registerReceiver(scanResultReceiver, IntentFilter().apply {
addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
})
}
override fun onDestroy() {
super.onDestroy()
// 移除广播
unregisterReceiver(scanResultReceiver)
}
}
扫描WIFI
通过WifiManager扫描WIFI,并获取扫描结果,代码如下:
// 列表适配器
class WIFIAdapter : RecyclerView.Adapter<WIFIAdapter.WIFIViewHolder>() {
private val wifiData = ArrayList<WIFIEntity>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WIFIViewHolder {
return WIFIViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_wifi_item, parent, false))
}
override fun onBindViewHolder(holder: WIFIViewHolder, position: Int) {
wifiData[position].run {
holder.tvWifiName.text = wifiSSID
holder.tvWifiSSID.text = wifiBSSID
holder.ivWifiStrength.setImageResource(getStrengthIcon(wifiStrength))
holder.ivNeedPassword.setImageResource(if (needPassword) R.drawable.icon_lock else R.drawable.icon_unlock)
}
}
override fun getItemCount(): Int {
return wifiData.size
}
fun setNewData(wifiData: ArrayList<WIFIEntity>?) {
val lastItemCount = itemCount
if (lastItemCount != 0) {
this.wifiData.clear()
notifyItemRangeRemoved(0, lastItemCount)
}
wifiData?.let { this.wifiData.addAll(it) }
notifyItemChanged(0, itemCount)
}
private fun getStrengthIcon(wifiStrength: Int): Int {
return when (wifiStrength) {
0 -> R.drawable.wifi_strength_0
1 -> R.drawable.wifi_strength_1
2 -> R.drawable.wifi_strength_2
else -> R.drawable.wifi_strength_3
}
}
interface ItemClickListener {
fun onItemClick(wifiInfo: WIFIEntity)
}
class WIFIViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvWifiName: AppCompatTextView = itemView.findViewById(R.id.tv_wifi_name)
val tvWifiSSID: AppCompatTextView = itemView.findViewById(R.id.tv_wifi_ssid)
val ivNeedPassword: AppCompatImageView = itemView.findViewById(R.id.iv_need_password)
val ivWifiStrength: AppCompatImageView = itemView.findViewById(R.id.iv_wifi_strength)
}
}
class WIFIExampleActivity : AppCompatActivity() {
private lateinit var binding: LayoutWifiExampleActivityBinding
private val wifiAdapter = WIFIAdapter()
private var wifiManager: WifiManager? = null
private var requestPermissionName: String = Manifest.permission.ACCESS_FINE_LOCATION
private val requestSinglePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted: Boolean ->
if (granted) {
// 申请定位权限通过,扫描WIFI
if (wifiManager?.isWifiEnabled == true) {
wifiManager?.startScan()
}
} else {
//未同意授权
if (!shouldShowRequestPermissionRationale(requestPermissionName)) {
//用户拒绝权限并且系统不再弹出请求权限的弹窗
//这时需要我们自己处理,比如自定义弹窗告知用户为何必须要申请这个权限
}
}
}
private val scanResultReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false) == true) {
val wifiData = ArrayList<WIFIEntity>()
wifiManager?.scanResults?.forEach {
val ssid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.wifiSsid.toString()
} else {
it.SSID
}
val bssid = it.BSSID
// 获取WIFI加密类型
val capabilities = it.capabilities
// 获取WIFI信号强度
val level = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
wifiManager?.calculateSignalLevel(it.level) ?: 0
} else {
WifiManager.calculateSignalLevel(it.level, 4)
}
wifiData.add(WIFIEntity(ssid, bssid, capabilities.contains("wpa", true) || capabilities.contains("web", true), capabilities, level))
}
// 根据信号强度降序排列
wifiData.sortByDescending { it.wifiStrength }
wifiAdapter.setNewData(wifiData)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_wifi_example_activity)
wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
binding.includeTitle.tvTitle.text = "WIFI Example"
binding.btnStartScan.setOnClickListener {
// 检测定位权限
if (ActivityCompat.checkSelfPermission(this, requestPermissionName) == PackageManager.PERMISSION_GRANTED) {
if (wifiManager?.isWifiEnabled == true) {
wifiManager?.startScan()
}
} else {
requestSinglePermissionLauncher.launch(requestPermissionName)
}
}
binding.rvWifiInfo.adapter = wifiAdapter
registerReceiver(scanResultReceiver, IntentFilter().apply {
addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
})
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(scanResultReceiver)
}
}
效果如图:
示例
在示例Demo中添加了相关的演示代码。
ExampleDemo github
ExampleDemo gitee
来源:https://juejin.cn/post/7212074532340056123
标签:Android,WIFI,扫描,权限
0
投稿
猜你喜欢
详解SpringCloud mysql实现配置中心
2023-11-02 05:12:57
Java实现多文件压缩加密并重命名压缩文件对象的方法
2021-07-02 15:44:31
SpringCloud实战小贴士之Zuul的路径匹配
2021-05-26 13:26:36
Java多线程编程中使用Condition类操作锁的方法详解
2023-10-19 13:30:55
C#实现自定义双击事件
2023-05-01 16:31:57
深入解析Java并发程序中线程的同步与线程锁的使用
2022-03-19 10:25:38
基于C#实现FTP下载文件
2021-07-09 20:10:01
浅谈MyBatis 如何执行一条 SQL语句
2023-10-17 19:36:03
Android开发简易音乐播放器
2023-12-26 01:07:03
java中Executor,ExecutorService,ThreadPoolExecutor详解
2023-10-31 10:50:56
详解spring-boot集成elasticsearch及其简单应用
2021-08-26 01:09:58
IDEA配置maven环境的详细教程(Unable to import maven project报错问题的解决)
2022-04-09 13:53:40
SWT(JFace)体验之ApplicationWindow
2023-01-02 09:59:43
Android调用外置摄像头的方法
2021-10-19 01:25:13
Java游戏开发拼图游戏经典版
2023-10-10 16:23:08
Android中NestedScrolling滑动机制详解
2022-09-16 22:32:13
详解springboot项目带Tomcat和不带Tomcat的两种打包方式
2023-11-28 08:23:41
SpringCloud Nacos + Ribbon 调用服务的实现方式(两种)
2023-11-18 09:30:38
mybatisPlus实现倒序拼接字符串
2021-11-16 08:50:29
java实现科研信息管理系统
2022-05-13 02:49:41