随着物联网 (IoT) 和智能设备的普及,BLE (Bluetooth Low Energy) 技术成为了许多 Android 应用程序的重要功能之一。BLE 广泛应用于设备连接、数据传输、位置服务等领域。然而,随着 Android 系统版本的迭代,关于 BLE 的权限管理也变得越来越复杂和严格。如果没有正确处理 BLE 权限,会导致应用运行异常或直接崩溃。
本文将深入解析 Android BLE 权限管理,包括所需权限、申请方式、不同 Android 版本的变化以及开发中的最佳实践。
1. BLE 使用场景及其权限需求
BLE 主要用于以下几个场景:
1. 扫描附近 BLE 设备(BLE Scan)
2. 连接 BLE 设备(GATT 操作)
3. 读取/写入数据(Characteristic 操作)
4. BLE 广播(BLE Advertising)
不同场景下,Android 系统对权限的需求有所不同。
对应的,Tuya App SDK 对其进行封装,分别为:
- 扫描:startLeScan (https://developer.tuya.com/cn/docs/app- ... E%E5%A4%87)
- 连接已配网设备:connectBleDevice(https://developer.tuya.com/cn/docs/app- ... E%E5%A4%87)
- 控制设备:publishDos(https://developer.tuya.com/cn/docs/app- ... E%E5%A4%87)
- 广播: IThingBeaconManager Beacon 相关操作
2. Android BLE 权限需求
Android 的 BLE 权限主要分为 蓝牙操作权限 和 位置信息权限:
2.1 蓝牙操作权限
蓝牙操作是 BLE 功能的核心,包括扫描、连接设备等。以下是关键权限:
• BLUETOOTH
• BLUETOOTH_ADMIN(在 Android 12 以下)
• BLUETOOTH_SCAN(在 Android 12 及以上)
• BLUETOOTH_CONNECT(在 Android 12 及以上)
• BLUETOOTH_ADVERTISE(在 Android 12 及以上)
2.2 位置信息权限
由于扫描 BLE 设备可能间接暴露用户位置,从 Android 6.0 (API 23) 开始,扫描操作需要添加位置信息权限:
• ACCESS_FINE_LOCATION
• ACCESS_COARSE_LOCATION
注意:由于 Tuya 设备存在防丢类型设备,即存在查找功能的 BLE 设备,导致 App SDK 需要定位权限。
另外,iBeacon 类型设备系统认为其常用于定位,因此扫描 iBeacon 广播包需要定位权限。
2.3 特殊权限
• Android 10 (API 29) 引入了 后台位置权限 (ACCESS_BACKGROUND_LOCATION),如果应用需要在后台扫描 BLE 设备,则必须申请该权限。
• Android 12 (API 31) 引入了 精确蓝牙扫描权限。
3. Android 各版本的 BLE 权限变化
3.1 Android 6.0 (API 23)
• 动态权限引入:ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 需要在运行时动态申请。
• BLE 扫描需要 位置权限。
3.2 Android 10 (API 29)
• 后台位置权限要求:后台扫描 BLE 设备需要 ACCESS_BACKGROUND_LOCATION。
• 位置权限使用场景变得更加严格。
3.3 Android 12 (API 31)
• 引入了三个新的蓝牙权限:
• BLUETOOTH_SCAN:扫描设备权限。
• BLUETOOTH_CONNECT:连接设备权限。
• BLUETOOTH_ADVERTISE:广告权限。
• 蓝牙操作权限细化,不再使用 BLUETOOTH_ADMIN。
• 如果应用仅在前台使用蓝牙功能,则不需要申请位置信息权限。
• 增强了权限可见性,用户在权限管理中可以单独看到蓝牙操作权限。
在 Android 12 (API 31) 及以上版本中,如果您的应用通过蓝牙扫描设备但明确声明不会使用蓝牙扫描来获取用户位置信息,可以在 AndroidManifest.xml 文件中为 BLUETOOTH_SCAN 权限添加 neverForLocation="true" 属性。这是 Google 为增强用户隐私保护提供的新机制。
当您配置 neverForLocation="true" 时:
1. 蓝牙扫描与位置功能解耦:系统不会强制关联蓝牙扫描与位置权限。
2. 隐私友好:用户可以更清楚地了解您的应用不会使用蓝牙操作间接获取位置信息。
但是由于 Tuya App 存在 iBeacon 设备,常用于定位,因此 Android 12 及以上版本仍然需要申请定位权限
4. BLE 权限的正确使用方式
4.1 声明权限
在 AndroidManifest.xml 文件中声明所需权限,例如:
Code: Select all
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 12以下 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
4.2 动态申请权限
从 Android 6.0 开始,以下权限需要在运行时动态申请:
• ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION
• BLUETOOTH_SCAN
• BLUETOOTH_CONNECT
• BLUETOOTH_ADVERTISE
以下是申请动态权限的代码示例:
Code: Select all
private val REQUEST_CODE_PERMISSIONS = 1001
private fun checkAndRequestPermissions() {
val requiredPermissions = mutableListOf<String>()
// 检查蓝牙权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
requiredPermissions.add(Manifest.permission.BLUETOOTH_SCAN)
}
if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
requiredPermissions.add(Manifest.permission.BLUETOOTH_CONNECT)
}
}
// 检查位置权限
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requiredPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
// 请求权限
if (requiredPermissions.isNotEmpty()) {
requestPermissions(requiredPermissions.toTypedArray(), REQUEST_CODE_PERMISSIONS)
}
}
4.3 检查权限结果
重写 onRequestPermissionsResult 以处理权限结果:
Code: Select all
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_PERMISSIONS) {
for (i in permissions.indices) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
// 权限被拒绝,处理相应逻辑
Log.e("BLE", "Permission denied: ${permissions[i]}")
}
}
}
}
5. BLE 权限开发中的常见问题与解决方案
5.1 扫描失败问题
• 确保申请了正确的权限(如 BLUETOOTH_SCAN 和位置信息权限)。
• 如果扫描依赖后台运行,需要申请 ACCESS_BACKGROUND_LOCATION。
5.2 权限拒绝后如何提示用户
• 权限被拒绝时,可以通过对话框或跳转至应用设置的方式引导用户:
Code: Select all
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
5.3 Android 12 下蓝牙操作权限分离
• 对于蓝牙扫描、连接和广告功能,分别申请对应权限,避免权限不足导致的崩溃。
6. BLE 权限的最佳实践
1. 按需申请权限:只申请实际需要的权限,避免冗余。
2. 遵守最小权限原则:例如,Android 12 中仅需要扫描功能时,无需申请位置信息权限。
3. 提前检查硬件支持:确保设备支持 BLE,并在代码中动态检查支持情况。
4. 处理用户拒绝:为用户提供明确的说明和操作指引(例如权限用途和重要性)。
5. 优化用户体验:在权限申请时,向用户解释权限的用途,避免因权限弹框引起的不信任。
总结
Android BLE 功能的权限管理是一个动态且复杂的过程,尤其是在 Android 6.0 至 Android 12 的版本迭代中。开发者需要深入理解 BLE 的权限需求,并结合应用的实际场景合理申请权限。同时,遵守 Android 的安全原则和最佳实践,可以有效提升应用的稳定性和用户体验。
BLE 权限的正确管理,不仅能保障应用功能的正常运行,还能帮助开发者适应不同版本的系统要求,为用户提供更加流畅和安全的体验。
Tuya SDK 中 BLE 相关开发文档可以参考 develop 平台:https://developer.tuya.com/cn/docs/app- ... v7r2ju4c21