设备屏幕关闭时的蓝牙低功耗扫描暂停(在vivo与 POCO设备上)

移动开发 2026-07-09

我正在做一个项目,需要开启对来自Beacon设备的SOS信息的BLE扫描。这个扫描在应用被杀死后也要保持活跃,以监听SOS信息。
为此,我在前台服务中使用了名为connectedType的连接类型,并在下方调用了以下方法。

<service android:name=".ui.service.BeaconForegroundService" android:foregroundServiceType="connectedDevice" android:exported="false"/>

I am using pending intent approach.

    fun startScanBluetoothDevice(pendingIntent: PendingIntent) {
        MyLogger.w(msg = "Scanning started !")

        val builder = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)


        scanner = bluetoothAdapter?.bluetoothLeScanner

        scanner?.let {
            it.startScan(getScanFilter(), builder.build(), pendingIntent)
        }

    }

And pending intent below way

val intent = Intent(context, BleScanReceiver::class.java)

val pendingIntent = PendingIntent.getBroadcast(
    context,
    0,
    intent,
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)

And listening result in broadcast receiver.

@AndroidEntryPoint
class BleScanReceiver : BroadcastReceiver() {

    @Inject lateinit var bleManager: BleManager

    override fun onReceive(context: Context, intent: Intent) {
        MyLogger.d(msg = intent.toString())

    }
}

注:
- 我已经检查过,设备上的所有电池优化都已禁用。
- 我具备所有必要的权限,且蓝牙已开启。
- 我遵循Android官方文档。

我在摩托罗拉设备上测试时工作正常,但在Poco / Vivo设备上不起作用

这意味着扫描似乎会暂停。

日志信息显示,暂停后在屏幕点亮时会恢复。

当屏幕关闭时:

   D  Result Come : ScanResult{device=XX:XX:XX:XX:C8:98, scanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=[0000fff1-0000-1000-8000-00805f9b34fb], mServiceSolicitationUuids=[], mManufacturerSpecificData={}, mServiceData={00000000-0000-1000-8000-00805f9b34fb=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -59, 97]}, mTxPowerLevel=-2147483648, mDeviceName=null, mTDSData=null, mTransportDiscoveryData=null], rssi=-47, timestampNanos=154178666809128, eventType=27, primaryPhy=1, secondaryPhy=0, advertisingSid=255, txPower=127, periodicAdvertisingInterval=0}
2026-04-22 12:00:50.682 14072-14072 VRI[MainActivity]       com.uffizio.androidbledemo           D  visibilityChanged oldVisibility=true newVisibility=false
2026-04-22 12:00:50.772 14072-14072 ViewRootImpl            com.uffizio.androidbledemo           D  AppSizeAfterRelayout, size: Point(720, 1612), rotation: ROTATION_0
2026-04-22 12:00:50.775 14072-14072 BLASTBufferQueue        com.uffizio.androidbledemo           D  [VRI[MainActivity]#3](f:0,a:4) destructor()
2026-04-22 12:00:50.775 14072-14072 BufferQueueConsumer     com.uffizio.androidbledemo           D  [VRI[MainActivity]#3(BLAST Consumer)3](id:36f800000003,api:0,p:-1,c:14072) disconnect

没有扫描结果。

当屏幕点亮时:

 D  Intent { flg=0x10 cmp=com.uffizio.androidbledemo/.ble_new.broadcast.BleScanReceiver (has extras) }
2026-04-22 12:02:19.097 14072-14072 AppFlow                 com.uffizio.androidbledemo           D  Bundle[mParcelledData.dataSize=440] 
Intent { flg=0x10 cmp=com.uffizio.androidbledemo/.ble_new.broadcast.BleScanReceiver (has extras) }
2026-04-22 12:02:19.097 14072-14072 AppFlow                 com.uffizio.androidbledemo           D  type : 1
2026-04-22 12:02:19.097 14072-14072 AppFlow                 com.uffizio.androidbledemo           D  [ScanResult{device=XX:XX:XX:XX:C8:98, scanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=[0000ffe1-0000-1000-8000-00805f9b34fb], mServiceSolicitationUuids=[], mManufacturerSpecificData={}, mServiceData={0000ffe1-0000-1000-8000-00805f9b34fb=[-95, 8, 97, -20, 65, -40, 105, -56, -104, 80, 76, 85, 83]}, mTxPowerLevel=-2147483648, mDeviceName=null, mTDSData=null, mTransportDiscoveryData=null], rssi=-43, timestampNanos=154272727111903, eventType=27, primaryPhy=1, secondaryPhy=0, advertisingSid=255, txPower=127, periodicAdvertisingInterval=0}]

解决方案

## Why This Happens

**Vivo (FuntouchOS/OriginOS) and Poco/Xiaomi (MIUI/HyperOS)** implement **proprietary aggressive power management layers** that are separate from, and in addition to, standard Android battery optimization. These ROMs throttle or completely pause BLE scanning when the screen turns off — even if battery optimization is disabled for the app.

The standard Android "disable battery optimization" (`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`) only controls AOSP-level Doze mode. It does **not** disable OEM-level proprietary kill systems.

---

## Suggested Fixes

### 1. Use Both Approaches Simultaneously
The `PendingIntent` approach alone is unreliable on these OEMs. Inside the foreground service, also use the **callback-based** `startScan()`:
```kotlin
scanner?.startScan(getScanFilter(), settings, scanCallback) // callback inside service
scanner?.startScan(getScanFilter(), settings, pendingIntent) // PendingIntent as backup

2. Acquire a PARTIAL_WAKE_LOCK

Inside the foreground service, hold a wake lock to prevent CPU sleep:

val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "app:BLEScanWakeLock")
wakeLock.acquire()

Release it when scanning stops.

3. Switch Scan Mode to LOW_POWER

SCAN_MODE_LOW_LATENCY ironically triggers more aggressive throttling on some OEMs. Try:

Or use SCAN_MODE_BALANCED as a middle ground.

4. Register Screen-Off Receiver to Restart Scan

// In foreground service
val filter = IntentFilter().apply {
    addAction(Intent.ACTION_SCREEN_OFF)
    addAction(Intent.ACTION_SCREEN_ON)
}
registerReceiver(screenReceiver, filter)

Restart the scan inside onReceive when ACTION_SCREEN_OFF fires.

5. OEM-Specific User Settings (Required for Vivo/Poco)

These OEMs require the user to manually configure additional permissions:

设备 路径
Vivo Settings → Battery → Background app management → Allow your app
Vivo Settings → Battery → High background power consumption → Allow
Poco/MIUI Settings → Apps → Manage apps → Your app → Battery Saver → No restrictions
Poco/MIUI Settings → Battery & performance → Autostart → Enable your app

6. Use the AltBeacon Library

The android-beacon-library handles many OEM-specific BLE quirks internally and has workarounds baked in for these exact scenarios.

7. Reference dontkillmyapp.com

dontkillmyapp.com documents per-OEM APIs and deep-link intents you can use to open the correct settings screen directly from your app, guiding users to the right place programmatically.


关键要点

This is fundamentally an OEM firmware restriction, not a bug in the code. The code shown in the question is correct per Android docs — it just works on stock Android (Motorola) but is blocked by Vivo/Xiaomi's proprietary power systems. A combination of wake lock + callback-based scan inside the service + user guidance to OEM battery settings is the most reliable mitigation.

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章