第4章:BLUETOOTH_CONNECT 与 BLUETOOTH_ADVERTISE 权限——用途区别、典型场景、声明要求
Android 12 将旧版 BLUETOOTH 权限拆分为三个细粒度权限:BLUETOOTH_SCAN、BLUETOOTH_CONNECT 和 BLUETOOTH_ADVERTISE。本章聚焦后两个权限:BLUETOOTH_CONNECT 管理蓝牙连接的建立与数据交互,BLUETOOTH_ADVERTISE 管理设备以广播形式向周围宣告自身存在(即周边模式/外围模式)。
拆分的核心目的:让用户能够按“扫描→连接→广播”三个独立阶段分别授权,从而在隐私和功能颗粒度上远超旧版单一大权限。
4.1 概念对比:CONNECT vs ADVERTISE
| 维度 | BLUETOOTH_CONNECT | BLUETOOTH_ADVERTISE |
|---|---|---|
| 核心能力 | 建立 ACL 连接、读写 GATT 属性、发起服务发现、绑定配对、连接参数更新等双向通信操作 | 以 BLE 广播包向周围广播设备信息(包括厂商自定义数据、扫描响应数据)、启动外围模式(Peripheral Mode) |
| 典型角色 | 中央设备(Central / GATT Client) | 外围设备(Peripheral / GATT Server) |
| 是否需要位置权限 | Android 12+ 不再强制位置权限(连接阶段已不需要 Wi-Fi/蓝牙扫描结果) | 仅广播不需要位置;但若广播后期望其他设备发现并连接,通常仍需配合 BLUETOOTH_CONNECT |
| 运行时请求时机 | 在尝试连接或绑定之前请求 | 在开始广播之前请求 |
| API 示例 | BluetoothDevice.createBond()、BluetoothGatt.connect() | BluetoothLeAdvertiser.startAdvertising() |
4.2 生活类比
🎙️ 广播员 vs 📞 通话者
- BLUETOOTH_ADVERTISE 就像在广场上举着牌子宣传:“我在这里!我的名字是XX,可以提供这些服务!” —— 只负责宣告,不建立连接。
- BLUETOOTH_CONNECT 就像有人看到广告后主动走过来与你握手、交换名片、建立对话通道 —— 此时才涉及连接与数据传输。
在实际设备上,一个 BLE 外围设备(如智能手环)同时需要 ADVERTISE(广播自身)和 CONNECT(接受手机连接请求并传输数据)。
4.3 常见误区
- 误区1:只要声明了 BLUETOOTH_CONNECT 就能自动广播。—— 错的。广播必须单独申请
BLUETOOTH_ADVERTISE,两者互不替换。 - 误区2:BLUETOOTH_ADVERTISE 只用于手机做外围模式。—— 部分成立但不全面。手机也可以作为中央设备主动扫描并连接外围设备,但若手机作为外围设备被其他设备连接,仍然需要
ADVERTISE权限发广播宣告自身。 - 误区3:两个权限都必须动态请求,且不能同时请求。—— 可以同时请求。系统会分别弹窗授权,用户可以选择全部同意、拒绝其中任意一个。
- 误区4:CONNECT 权限与扫描权限重复。—— 不重复。扫描(
BLUETOOTH_SCAN)仅可获得设备存在性信息;连接(CONNECT)才能读取具体服务、特性、描述符。 - 误区5:声明了 ADVERTISE 就可以在后台无限广播。—— Android 12+ 限制后台广播时长和频率,还需注意
startAdvertising()回调的延迟和唤醒锁策略。
4.4 典型声明与使用场景
- 场景1:经典 BLE 外围设备(如心率带) —— 应用需要
BLUETOOTH_ADVERTISE发送广播,同时需要BLUETOOTH_CONNECT接受手机连接并传输心率数据。 - 场景2:手机作为中央设备连接已配对的蓝牙键盘 —— 仅需要
BLUETOOTH_CONNECT(不需要广播)。 - 场景3:BLE 信标(Beacon)广播 —— 仅需要
BLUETOOTH_ADVERTISE,不建立连接。 - 场景4:点对点文件传输(经典蓝牙) —— 需要
BLUETOOTH_CONNECT,不需要广播(经典蓝牙使用 Inquiry/Page 配对流程与 BLE 广播不同)。
4.5 声明要求(AndroidManifest + 运行时)
| 声明类型 | 代码/配置 | 说明 |
|---|---|---|
| 静态声明 | |
Android 12+ 必须在 manifest 中显式声明这两个 normal 权限(与旧版危险权限不同) |
| 运行时请求(典型) | |
尽管是 normal 权限,但 Android 12+ 对于 BLUETOOTH_CONNECT 仍要求运行时请求(ADVERTISE 在部分设备上可能静默授权,仍需 manifest 声明) |
| 特殊场景:仅广播 | |
如果应用只作为信标发送广播,不需要连接,则只声明 ADVERTISE 即可,但仍需确保 BLE 可用且位置服务不强制(Android 12+ 已取消位置依赖) |
💡 最小权限原则:
- 只进行扫描 → 仅
BLUETOOTH_SCAN - 只发起连接(已知设备)→
BLUETOOTH_CONNECT - 只做广播(如信标)→
BLUETOOTH_ADVERTISE - 如果需要扫描后再连接(从发现到交互),则同时申请
SCAN + CONNECT
4.6 自我检测
题目1(单选): 你正在开发一个 BLE 外围设备 App,它需要定期广播温度数据,并且也允许其他 App 连接它来读取历史记录。这个 App 应该请求哪些蓝牙权限?
- 仅
BLUETOOTH_ADVERTISE - 仅
BLUETOOTH_CONNECT - 同时请求
BLUETOOTH_ADVERTISE和BLUETOOTH_CONNECT BLUETOOTH_SCAN+BLUETOOTH_ADVERTISE
✅ 答案:C —— 广播需要 ADVERTISE,接受连接并交互数据需要 CONNECT。注意这里 App 自己不需要扫描,因此不需要 BLUETOOTH_SCAN。
题目2(判断): 在 Android 12+ 上,只要在 manifest 中声明了 BLUETOOTH_CONNECT,就可以调用 startAdvertising() 方法。
❌ 错误 — startAdvertising() 属于 BLUETOOTH_ADVERTISE 权限保护的方法,仅有 CONNECT 无法调用,会抛出 SecurityException。
4.7 应用边界与注意事项
- 硬件依赖: 即使拥有
ADVERTISE权限,若设备 BLE 不支持 Peripheral 模式(部分旧款手机仅支持 Central),广播将失败。通过BluetoothAdapter.isMultipleAdvertisementSupported()检测。 - 版本兼容: Android 12 以下设备不识别这两个新权限,运行时请求会因
Build.VERSION.SDK_INT < Build.VERSION_CODES.S而跳过。可降级使用旧版BLUETOOTH权限。 - 用户撤销: 用户可以在系统设置中单独关闭
BLUETOOTH_CONNECT或BLUETOOTH_ADVERTISE,应用应当通过checkSelfPermission()持续校验。 - 与位置权限的关联: 在 Android 12+ 中,扫描需要位置但连接和广播不再需要位置。但在部分定制厂商系统上,若启用 “始终允许” 位置的旧策略,仍可能需要位置权限才能正常配对。
📌 关键行动点:
- 更新 targetSdkVersion 到 31+ 后请立即迁移至新权限体系。
- 在 manifest 中声明你需要的每个细粒度权限,不要隐藏。
- 运行时分别处理每个权限的授权回调,避免笼统假设。