Android12(targetSDK31)前台服务BLE后台扫描30秒后停止求助
Android 12(targetSDK31)前台服务BLE后台扫描停止问题解决方案
权限调整
补充必要权限
- 添加
FOREGROUND_SERVICE和FOREGROUND_SERVICE_CONNECTED_DEVICE权限(Android 12+要求BLE相关前台服务声明此类型):<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> - 修正
BLUETOOTH_SCAN权限:如果扫描不需要获取设备位置,添加neverForLocation标记避免位置权限依赖导致的扫描限制;若需位置信息,必须申请ACCESS_FINE_LOCATION权限:<!-- 无需位置的扫描配置 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- 需要位置的扫描配置 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> - 删除无效权限:
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND仅适用于Companion设备应用,普通APP无需;自定义的START_ACTIVITIES_FROM_BACKGROUND权限无实际作用,直接移除。
- 添加
前台服务声明优化
在Manifest的Service标签中指定前台服务类型:<service android:name=".YourBleScanForegroundService" android:foregroundServiceType="connectedDevice" />
扫描方式调整
- 改用周期性扫描
Android 12对后台连续BLE扫描有严格限制,即使前台服务也会在30秒后终止。建议采用扫描+休眠的周期性策略,例如扫描10秒、休眠20秒循环执行:private void startPeriodicScan() { Handler handler = new Handler(Looper.getMainLooper()); Runnable scanRunnable = new Runnable() { @Override public void run() { // 启动BLE扫描 bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback); // 10秒后停止扫描 handler.postDelayed(() -> { bluetoothLeScanner.stopScan(scanCallback); // 20秒后再次启动扫描 handler.postDelayed(this, 20000); }, 10000); } }; scanRunnable.run(); } - 调整扫描参数
使用低功耗或平衡模式的扫描设置,避免后台不允许的高功耗扫描:ScanSettings scanSettings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) // 或SCAN_MODE_BALANCED .build();
前台服务启动合规性
启动前台服务时,Android 12+必须指定FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE类型,同时确保通知符合系统要求:
Notification notification = new NotificationCompat.Builder(this, "BLE_SCAN_CHANNEL") .setContentTitle("BLE扫描中") .setContentText("正在扫描周边BLE设备") .setSmallIcon(R.drawable.ic_scan) .setCategory(Notification.CATEGORY_SERVICE) .build(); // 适配Android 12+前台服务类型 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE); } else { startForeground(NOTIFICATION_ID, notification); }
内容的提问来源于stack exchange,提问作者KK_07k11A0585
相关产品推荐
相关产品推荐

