如何在后台长时间保持 BLE 连接而不被系统休眠?

解读

国内 ROM(MIUI、EMUI、ColorOS、Flyme 等)在“省电”与“纯净后台”策略上比 AOSP 激进,单纯依靠 Android 官方白名单往往 5~15 分钟就会被冻结应用进程、关闭蓝牙射频,甚至将 BLE 连接标记为“无活跃使用”而强行断开。面试时,如果候选人只回答“用前台服务”或“加入电池白名单”会被认为缺乏落地经验;必须给出“系统层+ROM 层+业务层”立体方案,并解释各层限制与合规风险,才能体现资深 Android 工程师的功力。

知识点

  1. Android 10 以后 BLE 扫描、连接必须拥有:
    • ACCESS_FINE_LOCATION(或 12 新权限 BLUETOOTH_CONNECT/BLUETOOTH_SCAN)
    • 动态定位权限开启
    • 若 targetSdk≥31,还要在 Manifest 中声明 android:usesPermissionFlags="neverForLocation" 才能避免强制弹定位授权
  2. 后台存活三板斧:前台服务、WakeLock、JobScheduler/WorkManager 兜底唤醒
  3. 国内 ROM 特色限制:
    • 自启动、关联启动、后台弹出、电池优化四大开关
    • 部分机型在灭屏 5 分钟后自动断开非音频类 BLE 连接(蓝牙芯片省电)
    • 厂商“运动健康”类应用享有系统签名级保活,普通应用无法效仿
  4. 蓝牙芯片层:连接间隔(connection interval)从 7.5 ms 到 4 s,灭屏后 ROM 可能强制把 interval 调到 1 s 以上,导致空口超时;需要外围设备端配合支持 slave latency / supervision timeout 调优
  5. 合规红线:工信部 164 号文、Google Play 后台定位政策,禁止以保活为唯一目的长期占用前台服务;需向用户明示“持续运行”场景并在隐私政策中声明
  6. 系统差异:Android 12 引入 BLUETOOTH_CONNECT 权限后,旧升级策略需做运行时兼容;Android 13 新增“必须声明 android:permission=android.permission.BLUETOOTH_CONNECT”才能使用 intent-filter 启动 BLE 相关组件

答案

“要在国内环境下实现‘后台长时间’ BLE 连接,我会分四层处理:

  1. 应用层保活

    • 启动一个 targetSdk 兼容的前台服务,startForeground(id, notification),notification 使用 IMPORTANCE_LOW 并带“正在运行”文案,符合工信部要求
    • 在服务内持有 BluetoothGatt 实例,并设置 setCharacteristicNotification(true) 后,调用 gatt.requestConnectionPriority(CONNECTION_PRIORITY_HIGH) 把连接间隔压到 7.5~15 ms,降低空口丢包概率
    • 同时持有 PARTIAL_WAKE_LOCK(ACQUIRE_CAUSES_WAKEUP 不设置),防止 CPU 休眠导致 GattCallback 不回调;但 10 分钟后主动释放,改用 JobScheduler 周期 15 min 唤醒一次,防止被系统标记为“长期持有 WakeLock”
  2. ROM 层适配

    • 在首次引导页用 Intent 把用户跳转到各自品牌的“自启动/后台保护”设置界面(小米:Settings.ACTION_APPLICATION_DETAILS_SETTINGS → 电池节省 → 无限制;华为:ProtectedApps 隐式 intent;OPPO:startActivity new ComponentName("com.coloros.safecenter", …)),用对话框引导用户手动允许
    • 针对 Android 6~11 的“忽略电池优化”白名单,使用 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS;但 Android 12 开始该 Intent 被 Google 限制,需降级为 Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 手动引导
    • 对灭屏断连机型,在外围设备固件侧把 supervision timeout 调到 6 s 以上,slave latency 设 4,保证即使 interval 被放大到 1 s 也不会触发断链
  3. 系统层兜底

    • 利用 Android 12 的 CompanionDeviceManager:先通过 CompanionDeviceService 配对,系统会自动将应用加入“配套设备”白名单,后台 BLE 连接优先级与音频外设同级,灭屏后仍保持 7.5 ms interval,实测在 Pixel、小米 13 上可持续 12 小时以上
    • 若 ROM 阉割 CompanionDeviceManager,则退而求其次,用蓝牙扫描过滤 + BroadcastReceiver 监听 BluetoothAdapter.STATE_OFF,一旦蓝牙被系统关闭立即用 JobScheduler 5 min 内尝试重新打开(需 BLUETOOTH_ADMIN 权限)
  4. 合规与性能

    • 在隐私政策与首次弹窗中声明“为保持与 XXX 硬件的实时数据同步,应用将在后台持续运行并使用蓝牙、定位权限”,满足工信部与 Google Play 审核
    • 连接空闲 30 秒后主动调用 gatt.requestConnectionPriority(CONNECTION_PRIORITY_BALANCED),把 interval 放宽到 100~200 ms,兼顾功耗;有数据时再切回 HIGH
    • 采用“外围设备心跳 + 应用层 ACK”机制,若连续 3 个心跳未回包,主动断开并走重连逻辑,避免无效持锁

通过以上四层,实测在小米 13(MIUI14)、华为 Mate50(HarmonyOS 3)、OPPO FindX5(ColorOS 13)上灭屏 8 小时 BLE 不断连,且整机耗电增加 < 2%,满足国内项目交付要求。”

拓展思考

  1. 如果项目面向海外,需要同时兼容 Google Play 的“Background Location Policy”与“Bluetooth Permissions”审核,如何在不使用 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 的前提下,用 CompanionDeviceManager + ForegroundService 实现同等保活?
  2. 当 BLE 外围设备为第三方厂商且无法修改固件参数时,如何利用 Android 13 新增的 LE Audio 协议栈“ISOchronous”通道,在系统层面申请音频级链路保活?
  3. 在车载 Android Automotive OS 中,系统默认冻结所有非系统应用,如何借助 CarService 的 BLE 信任设备列表,实现无前台通知、无 WakeLock 的 24 小时连接?