Android开发中如何正确实现BLE权限分版本检查适配?
Android BLE跨版本权限适配方案
在Android应用开发中使用Bluetooth Low Energy(BLE,蓝牙低功耗)功能时,需要在Manifest文件中声明多项相关权限,并在运行时校验用户是否已授予对应权限。
开发过程中常见的运行时崩溃问题:BLE功能一共涉及6项可能用到的权限,如果尝试对全部6项权限统一执行运行时校验,会直接运行失败。根本原因是不同Android版本的权限规则存在差异,部分系统版本不会授予、也不要求申请不属于该版本规则的运行时权限。
Manifest权限声明
首先需要在应用的Manifest文件中声明所有涉及的BLE相关权限:
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
感谢@Kozmotronik提供的简易解决思路:仅针对当前设备的Android系统版本,匹配校验该版本要求的对应权限,即可适配全版本系统。
运行时权限申请逻辑
以下实现逻辑会自动识别当前系统版本所需的权限,将尚未授予的权限加入待申请列表,随后统一发起缺失权限的申请请求:
private fun checkAndRequestMissingPermissions() { // 校验所需权限,收集未授权的权限 val missingPermissionsToBeRequested = ArrayList<String>() if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.BLUETOOTH) if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.BLUETOOTH_ADMIN) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12及以上版本需要BLUETOOTH_CONNECT和BLUETOOTH_SCAN权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.BLUETOOTH_CONNECT) if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.BLUETOOTH_SCAN) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10及以上版本需要精确定位权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.ACCESS_FINE_LOCATION) } else { // Android 10以下版本申请粗略定位权限即可 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) missingPermissionsToBeRequested.add(Manifest.permission.ACCESS_COARSE_LOCATION) } if (missingPermissionsToBeRequested.isNotEmpty()) { writeToLog("Missing the following permissions: $missingPermissionsToBeRequested") ActivityCompat.requestPermissions(this, missingPermissionsToBeRequested.toArray(arrayOfNulls<String>(0)), REQUEST_MULTIPLE_PERMISSIONS) } else { writeToLog("All required permissions GRANTED !") } }
权限申请结果回调
权限申请弹窗交互完成后,可通过重写onRequestPermissionsResult()回调方法,校验用户是否批准了所需权限,对应实现代码如下:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_MULTIPLE_PERMISSIONS) { for (idx in permissions.indices) { var result = if (grantResults[idx] == PackageManager.PERMISSION_GRANTED) "Granted" else "Denied" writeToLog("REQUEST_MULTIPLE_PERMISSIONS Permission ${permissions[idx]} $result}") } } }
BLE功能调用注意事项
Android系统强制要求,调用部分BLE功能前必须完成对应权限校验;对于特定系统版本不会授予的权限,无需强行申请,但必须增加Android版本判断分支做校验,避免触发运行时异常。
以BLE扫描功能为例,调用前的权限校验逻辑如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { writeToLog("Scan permission denied") } else { bluetoothScanner.startScan(filters, scanSettings, scanCallback) writeToLog("Bluetooth Scan Started") }
@Kozmotronik近期也对该方案做了进一步优化改进,优化后的实现可基于上述基础逻辑按需扩展。
内容的提问来源于stack exchange,提问作者RatherBeSailing
相关产品推荐
相关产品推荐

