【发布时间】: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