Android 扫描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

作者:ChenYhong

%s 个评论

要回复文章请先登录注册