1. 为什么要关注 Android 12 蓝牙扫描权限变化

Android 12(API 31)引入的蓝牙扫描权限变更,不是一次简单的 API 升级,而是 Android 隐私保护体系从“粗放授权”向“细粒度、上下文感知授权”转型的关键节点。作为开发者,理解这一变化背后的驱动力、直接风险和自身责任,是确保应用在新版本生态中正常运行的起点。

1.1 新版本隐私保护趋势:从“全有或全无”到“最小化、透明化”

Android 从 6.0 运行时权限模型开始,持续收紧对敏感数据的访问。蓝牙扫描能获取 MAC 地址、设备类型、信号强度甚至位置信息,过去被归类为 ACCESS_FINE_LOCATION 的附属能力。Android 12 将其剥离为独立的 BLUETOOTH_SCAN 权限,并强制与位置权限解耦(部分场景仍需位置,但不再是绑定关系)。这一趋势反映以下原则:

  • 权限最小化:应用只应申请完成功能所需的最小权限集合。扫描蓝牙设备不需要知道精确位置,只需扫描权即可。
  • 运行时透明:用户在授权时能清晰区分“我要允许你扫描附近的蓝牙设备”和“我要允许你获取我的位置”,避免权限滥用。
  • 权限降级与分拆:过去一个权限覆盖多个能力的模式,被拆解为更细粒度的独立权限,每个权限都有明确的语义和使用场景。
概念边界:BLUETOOTH_SCAN 只允许扫描和获取设备信息,不包含连接权限。BLUETOOTH_CONNECT 用于配对和连接,是另一个独立权限。这种拆分让用户能更精确地控制应用的行为。

1.2 应用兼容风险:不升级,就崩溃

对于 targetSdkVersion 低于 31 的应用,Android 12 仍向后兼容旧权限模型(即仍通过位置权限间接获取扫描能力)。但一旦应用将 targetSdkVersion 升级到 31 或更高,必须按照新规则在运行时同时请求 BLUETOOTH_SCAN 和(必要时)位置权限,否则扫描功能将直接失效,且不会收到任何回调或异常提示。

Target SDK蓝牙扫描权限运行时行为兼容状态
30 或更低依赖位置权限旧模型,可扫描兼容,但有废弃警告
31 或更高必须申请 BLUETOOTH_SCAN + 位置权限新模型,否则静默失败不升级则功能中断

除了功能中断,还有以下具体风险:

  • 静默失败陷阱:应用可能仍能正常启动,但所有扫描回调(如 onScanResult)不会触发,调试极其困难。
  • Google Play 审核风险:从 2022 年底,Google Play 要求新应用和更新必须针对 API 31+,且必须正确声明和使用新权限,否则可能被下架或拒绝更新。
  • 多版本适配成本:如果应用仍需支持 Android 11 及以下设备,需要在代码中同时处理两套权限逻辑,增加了条件分支和测试复杂度。
常见误区:有些开发者误以为只在 AndroidManifest.xml 中添加 BLUETOOTH_SCAN 权限声明即可。实际上,Android 12+ 要求该权限必须在运行时通过 requestPermissions() 动态申请,且用户可随时撤销。静态声明 + 动态申请,缺一不可。

1.3 开发者责任边界:从“能用”到“合规”

权限变化的本质是责任前移。过去,系统替开发者决定了“能做什么”;现在,开发者需要主动证明“为什么需要这个权限”、“如何使用该权限”以及“如何保护用户数据”。具体责任边界包括:

  • 权限声明与解释:在 AndroidManifest.xml 中声明权限时,应配合 usesPermissionFlags 和 maxSdkVersion 限制权限仅在必要版本生效。
  • 运行时解释与授权:用户拒绝或撤销权限后,应用应优雅降级(例如显示引导界面,而非直接崩溃)。
  • 数据最小化采集:扫描到的设备 MAC 地址、RSSI 等数据,不应超出功能需求的范围存储或上传。若用于位置推断,必须遵循位置权限规则。
  • 用户撤回权限响应:系统允许用户随时通过设置或运行时弹窗撤销权限。应用需要监听权限变化并动态调整扫描逻辑。
应用边界案例:一个蓝牙防丢器应用,只需要扫描到设备并触发报警,不需要知道设备的精确位置。开发者可以仅申请 BLUETOOTH_SCAN 权限,而不申请位置权限。但如果该应用同时需要在地图上标记设备位置,则必须额外申请 ACCESS_FINE_LOCATION。权限拆分后,用户能准确理解“扫描”和“定位”是两码事。

1.4 核心概念框架图

下图展示了 Android 12 蓝牙权限变化的驱动因素、具体风险以及开发者必须承担的新责任之间的逻辑关系:

Android 12 蓝牙扫描权限变化:动因 · 风险 · 责任 Android 12 权限拆分 隐私保护趋势 最小权限 · 透明授权 · 权限降级 应用兼容风险 静默失败 · Play 审核 · 多版本适配 开发者责任边界 权限声明 + 运行时申请 数据最小化采集 权限撤销响应

1.5 练习题(自我检验)

  1. 单选题:Android 12 中,BLUETOOTH_SCAN 权限的运行时请求策略是什么?
    A. 只需在清单中声明,无需运行时申请
    B. 必须运行时动态申请,且用户可随时撤销
    C. 与位置权限绑定,申请位置即自动获得扫描权
    D. 仅支持系统应用使用,第三方应用无法申请
    答案:B
  2. 多选题:以下哪些属于 Android 12 蓝牙权限变化后的开发者责任?
    A. 确保 targetSdkVersion 30 以下的应用也能运行新权限模型
    B. 在运行时向用户解释为什么需要蓝牙扫描权限
    C. 将扫描到的所有设备信息上传到云端
    D. 监听权限变化并优雅降级
    答案:B、D
  3. 简答题:如果一个蓝牙扫描应用在 Android 12 设备上运行时没有任何错误提示,但始终收不到扫描结果,最可能的原因是什么?如何排查?
    参考答案:最可能的原因是应用未正确申请 BLUETOOTH_SCAN 权限,或未在运行时动态请求。排查时先检查 AndroidManifest.xml 是否声明了新权限,再检查运行时请求流程是否执行,最后检查用户是否已授权。