Android 13后台BLE扫描失效问题求助(对比Android 9正常)
问题:Android 13后台BLE扫描无设备返回(Android 9正常)
我使用Jetpack WorkManager调度BLEScanWorker类,每15分钟在后台扫描BLE设备10秒并将设备存入列表。该逻辑在Android 9三星平板上,无论应用前台、后台、关闭甚至重启后都能正常返回所有BLE设备;但在Android 13三星S22手机上,仅应用前台时能正常返回设备,应用隐藏或关闭时扫描启动停止正常但无任何设备返回。
build.gradle中compileSdkVersion为33,已授予ACCESS_FINE_LOCATION、BLUETOOTH_SCAN和BLUETOOTH_ADMIN权限。
调度Worker代码
Constraints constraints = new Constraints.Builder() .setRequiresCharging(false) .setRequiresDeviceIdle(false) .setRequiresBatteryNotLow(true) .setRequiredNetworkType(NetworkType.NOT_REQUIRED) .build(); PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder( BLEScanWorker.class, 15, TimeUnit.MINUTES) .setConstraints(constraints) .build(); mWorkManager.enqueueUniquePeriodicWork( SCAN_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, //Existing Periodic Work policy periodicWorkRequest //work request );
BLEScanWorker类代码
public class BLEScanWorker extends Worker { private static final String TAG = BLEScanWorker.class.getName(); private static final long SCAN_PERIOD = 10000; List<BluetoothDevice> mBLEDeviceList= new ArrayList<>(); private Context mContext; public BLEScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); mContext = context; } private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); // save BLE device returned by result.getDevice() in mBLEDeviceList } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); for (ScanResult result : results) { // save BLE device returned by result.getDevice() in mBLEDeviceList } } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); Log.e("onScanFailed", "Error code = " + errorCode); } }; @NonNull @Override public Result doWork() { final BluetoothLeScanner bluetoothLeScanner; final ScanSettings settings; final List<ScanFilter> filters; BluetoothAdapter bluetoothAdapter; // It has been declared BLE required in the manifests. BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService (Context.BLUETOOTH_SERVICE); if (bluetoothManager != null) bluetoothAdapter = bluetoothManager.getAdapter(); else { Log.e(TAG, "failed to get BluetoothManager"); return Result.failure(); } try { bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) .build(); filters = new ArrayList<ScanFilter>(); } catch (SecurityException se) { Log.e(TAG, se.getMessage()); return Result.failure(); } try { Log.d(TAG, Calendar.getInstance().getTime() + " " + "doWork Called"); mBLEDeviceList.clear(); try { bluetoothLeScanner.startScan(filters, settings, mScanCallback); } catch (SecurityException se) { Log.e(TAG, se.getMessage()); } Log.i(TAG, Calendar.getInstance().getTime() + " start scan"); Thread.sleep(SCAN_PERIOD); // sleep for 10 sec while scanning Log.i(TAG, Calendar.getInstance().getTime() + " stop scan"); try { bluetoothLeScanner.stopScan(mScanCallback); } catch (SecurityException se) { Log.e(TAG, se.getMessage()); } if (!mBLEDeviceList.isEmpty()) { // do something if the BLE device list is not empty } Log.i(TAG, "doWork finished"); return Result.success(); } catch (Throwable throwable) { Log.d(TAG, "Error Sending Notification " + throwable.getMessage()); return Result.failure(); } } }
问题原因分析
- Android 13后台BLE扫描权限限制:API 33新增了
BLUETOOTH_SCAN的后台权限控制,仅申请前台权限时,应用后台无法获取扫描结果。当前权限配置未覆盖后台场景。 - 扫描模式适配问题:
ScanSettings.SCAN_MODE_LOW_POWER在Android 13后台环境中,系统会大幅限制扫描频率和结果返回,导致无法发现设备。 - 后台任务优先级限制:Android 13对后台任务调度的管控更严格,WorkManager周期性任务在后台执行时优先级降低,BLE扫描资源被系统限制。
解决方案
1. 补充后台BLE扫描权限
在AndroidManifest.xml中添加后台权限声明:
<!-- Android 13及以上的后台BLE扫描权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="always" /> <!-- 兼容低版本的权限声明 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:maxSdkVersion="32" />
同时在代码中动态申请后台权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { String[] permissions = { Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_SCAN + ".BACKGROUND" }; if (ContextCompat.checkSelfPermission(mContext, permissions[0]) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(mContext, permissions[1]) != PackageManager.PERMISSION_GRANTED) { ActivityResultLauncher<String[]> launcher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> { boolean scanGranted = result.getOrDefault(permissions[0], false); boolean scanBgGranted = result.getOrDefault(permissions[1], false); if (!scanGranted || !scanBgGranted) { // 处理权限申请失败逻辑 } }); launcher.launch(permissions); } }
2. 调整扫描模式
将扫描模式改为SCAN_MODE_LOW_LATENCY,提升后台扫描的设备发现概率:
settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
3. 将Worker升级为前台服务
通过ForegroundInfo把Worker标记为前台任务,避免系统限制后台资源:
@NonNull @Override public Result doWork() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道 NotificationChannel channel = new NotificationChannel( "BLE_SCAN_CHANNEL", "BLE扫描服务", NotificationManager.IMPORTANCE_LOW ); NotificationManager manager = (NotificationManager) getApplicationContext() .getSystemService(Context.NOTIFICATION_SERVICE); manager.createNotificationChannel(channel); // 创建前台通知 Notification notification = new NotificationCompat.Builder(getApplicationContext(), "BLE_SCAN_CHANNEL") .setContentTitle("正在扫描BLE设备") .setSmallIcon(R.drawable.ic_scan) .build(); // 设置前台服务 setForegroundAsync(new ForegroundInfo(1001, notification)); } // 原有扫描逻辑... }
4. 检查位置后台权限(若需要)
如果扫描依赖位置信息,需补充ACCESS_BACKGROUND_LOCATION权限:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
动态申请时需将该权限加入申请列表。
内容的提问来源于stack exchange,提问作者user22020238
相关产品推荐
相关产品推荐

