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)
   }
}

效果如图:

Android 扫描WIFI权限详解

示例

在示例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
  • asp之家 软件编程 m.aspxhome.com