【问题标题】:Android 12 - Launching Foreground Service from a background Bluetooth LE scan BroadcastReceiver throws ForegroundServiceStartNotAllowedExceptionAndroid 12 - 从后台蓝牙 LE 扫描 BroadcastReceiver 启动前台服务抛出 ForegroundServiceStartNotAllowedException
【发布时间】:2022-12-08 20:49:09
【问题描述】:

编辑:我认为这是 AOSP 中的错误。请大家给this issue加注星标,这样它会得到更多关注。


我的应用程序使用前台服务捕获 GPS 来记录用户驾驶车辆时的行程。它旨在由 BLE 信标(或活动识别)的存在触发。此应用程序设计为在应用程序关闭时运行,并且工作正常以 API 30 为目标时,但使用 API 31 (Android 12) 时失败。

由于以 API 31 为目标,它被 Android 12 中的新 Background Start Restrictions 捕获 - 当由于 BLE 扫描结果而尝试启动服务时,我现在得到:android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.example.myapp/com.example.myappsdk.trip.RecordingService

但是,我从后台触发前台服务的两个用例都是Permitted Exemptions

  • 您的应用收到需要 BLUETOOTH_CONNECT 或 BLUETOOTH_SCAN 权限的蓝牙广播。
  • 您的应用收到与地理围栏或活动识别转换相关的事件。

...所以我不明白为什么会抛出这个异常。该文档没有描述使其工作所需的任何特定步骤。

这是触发 BLE 扫描的代码,它由 Application 对象调用。此时用户已在运行时明确授予android.permission.BLUETOOTH_SCAN权限:

 BluetoothManager btManager = (BluetoothManager) (appContext.getSystemService(Context.BLUETOOTH_SERVICE));
 ScanSettings settings = new ScanSettings.Builder()
    .setLegacy(false)
    .setScanMode(SCAN_MODE_LOW_LATENCY)
    .setUseHardwareBatchingIfSupported(true)
    .setUseHardwareFilteringIfSupported(true)
    .setReportDelay(5000)
    .build();
 
 List<ScanFilter> filters = new ArrayList<>();
 filters.add(new ScanFilter.Builder().setDeviceAddress("AB:CD:EF:01:23:45").build());
 
 Intent intent = new Intent(appContext, BackgroundScanResultReceiver.class);
 intent.setAction("com.example.BACKGROUND_SCAN_RESULT");
 int flags;
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
      // Must be mutable to allow system to add intent extras
    flags = PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_MUTABLE; 
 else
    flags = PendingIntent.FLAG_UPDATE_CURRENT;
 PendingIntent pi = PendingIntent.getBroadcast(appContext, 1, intent, flags);
 
 BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
 scanner.startScan(filters, settings, appContext, pi);

这是接收扫描结果并启动服务的 ResultReceiver:

public class BackgroundScanResultReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {        
        List<ScanResult> scanResults = intent.getParcelableArrayListExtra(BluetoothLeScannerCompat.EXTRA_LIST_SCAN_RESULT);        
        for (ScanResult result : scanResults) {
            BluetoothDevice btDevice = result.getDevice();
            if (!btDevice.getAddress().equals("AB:CD:EF:01:23:45")) {
                return;
            }
            Intent recordIntent = new Intent(context, RecordingService.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(recordIntent); // <-- Exception thrown here when app in Background
            } else {
                context.startService(recordIntent);
            }
        }
    }
}

RecordingService 在清单中声明如下:

<service
    android:name=".trip.RecordingService"
    android:description="@string/recording_service_description"
    android:enabled="true"
    android:exported="false"
    android:foregroundServiceType="location"
    android:label="@string/recording_service_label" />

BroadcastReceiver 在清单中简单地定义为:

<receiver android:name=".beacon.BackgroundScanResultReceiver"/>

对于可能希望推荐使用 WorkManager 的任何人,我要指出的是,Android 仍然建议使用前台服务而不是 WorkManager in certain use cases,包括“活动跟踪”。

我的 BLE 扫描由 Nordic 的 Android-Scanner-Compat-Library 处理,但在 O+ 上它只是本机 API 的包装器。我试过直接将它换成原生的BluetoothLeScanner,但没有任何区别。

看来我不是唯一在假定允许的情况下遇到此异常的人:How to use activity recognition Exemptions to start foregroundService from background?

【问题讨论】:

  • 您依赖哪一项允许的豁免?
  • @MustafaDakhel “您的应用程序接收到需要 BLUETOOTH_CONNECT 或 BLUETOOTH_SCAN 权限的蓝牙广播”
  • 您可以使用清单中广播接收器的定义更新问题吗?
  • @MustafaDakhel 添加,但我认为这主要是无关紧要的,因为 BroadcastReceiver 正在正常启动。
  • @warbi 你有没有找到任何解决方案,我面临着相同的 ForegroundServiceStartNotAllowedException 豁免“地理围栏或活动识别转换”。

标签: android android-service android-bluetooth foreground-service android-12


【解决方案1】:

我找到的最佳解决方案是从后台启动服务或在设备通过 AlarmManager Android O+ 重新启动后启动服务。

val mgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val i = Intent(context, Service::class.java)
val pi = PendingIntent.getForegroundService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
val calendar: Calendar = Calendar.getInstance()
calendar.timeInMillis = System.currentTimeMillis()
calendar.add(Calendar.SECOND, 3)
mgr.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis ,pi)

此外,在 Notification Builder 中添加:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    notificationBuilder.foregroundServiceBehavior = FOREGROUND_SERVICE_IMMEDIATE
}

notificationBuilder.setPriority(NotificationCompat.PRIORITY_MAX)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多