I am using flutter background service to run a beacon scan in the background and in the foreground when the app is disconnected.
I get the folowing response when the app crashes. The app only occurs when i first close the app and then open it again. And when i open it after the crash then it opens normally
I am ussing flutter_background_service.
And flutter_blue_plus
This problem seems to occur from the android 14 os version.
I seems to occur while the foreground service is trying to start
after reopening the app.
Any suggestions for a possible solution?
D/[FBP-Android](17180): [FBP] onDetachedFromEngine
D/BluetoothAdapter(17180): isLeEnabled(): ON
D/[FBP-Android](17180): [FBP] disconnectAllDevices(onDetachedFromEngine)
D/AndroidRuntime(17180): Shutting down VM
E/AndroidRuntime(17180): FATAL EXCEPTION: main
E/AndroidRuntime(17180): Process: com.dptechnics.test.main_app, PID: 17180
E/AndroidRuntime(17180): android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e156910 u0 com.dptechnics.test.main_app/id.flutter.flutter_background_service.BackgroundService c:com.dptechnics.test.main_app}
E/AndroidRuntime(17180): at android.app.ActivityThread.generateForegroundServiceDidNotStartInTimeException(ActivityThread.java:2243)
E/AndroidRuntime(17180): at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:2214)
E/AndroidRuntime(17180): at android.app.ActivityThread.-$$Nest$mthrowRemoteServiceException(Unknown Source:0)
E/AndroidRuntime(17180): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2520)
E/AndroidRuntime(17180): at android.os.Handler.dispatchMessage(Handler.java:107)
E/AndroidRuntime(17180): at android.os.Looper.loopOnce(Looper.java:232)
E/AndroidRuntime(17180): at android.os.Looper.loop(Looper.java:317)
E/AndroidRuntime(17180): at android.app.ActivityThread.main(ActivityThread.java:8592)
E/AndroidRuntime(17180): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(17180): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
E/AndroidRuntime(17180): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
E/AndroidRuntime(17180): Caused by: android.app.StackTrace: Last startServiceCommon() call for this service was made here
E/AndroidRuntime(17180): at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1953)
E/AndroidRuntime(17180): at android.app.ContextImpl.startForegroundService(ContextImpl.java:1907)
E/AndroidRuntime(17180): at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:832)
E/AndroidRuntime(17180): at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java:1128)
E/AndroidRuntime(17180): at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:700)
E/AndroidRuntime(17180): at id.flutter.flutter_background_service.FlutterBackgroundServicePlugin.start(FlutterBackgroundServicePlugin.java:83)
E/AndroidRuntime(17180): at id.flutter.flutter_background_service.FlutterBackgroundServicePlugin.onMethodCall(FlutterBackgroundServicePlugin.java:135)
E/AndroidRuntime(17180): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:267)
E/AndroidRuntime(17180): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:292)
E/AndroidRuntime(17180): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:319)
E/AndroidRuntime(17180): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/AndroidRuntime(17180): at android.os.Handler.handleCallback(Handler.java:959)
E/AndroidRuntime(17180): at android.os.Handler.dispatchMessage(Handler.java:100)
E/AndroidRuntime(17180): ... 6 more
I/Process (17180): Sending signal. PID: 17180 SIG: 9
My android manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- legacy for Android 11 or lower -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
<!-- legacy for Android 9 or lower -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!--Add this Permissions-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<!-- <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.BLUETOOTH_USE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- foregroundServiceType: dataSync -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<application
...
<service
android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
android:exported="false"
android:stopWithTask="false"/>
<service
android:name="id.flutter.flutter_background_service.BackgroundService"
android:foregroundServiceType="location"/>
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
My main.dart
const notificationId = 888;
const notificationChannelId = 'Main app';
void main() async {
///Set the bluetooth log level for the bluetooth connection
FlutterBluePlus.setLogLevel(LogLevel.none, color: true);
WidgetsFlutterBinding.ensureInitialized();
await initializeNotifications();
await requestPermissions();
await initLocalPrefs();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
await requestPermissionsBluetooth();
await initBeaconScanTask();
runApp(MainApp());
}
///Request the permission of the local notification.
Future<void> requestPermissions() async {
bool? granted = false;
if (Platform.isIOS) {
granted = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
} else if (Platform.isAndroid) {
granted = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.areNotificationsEnabled() ??
false;
if (!granted) {
granted = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!
.requestNotificationsPermission();
}
}
notificationsEnabled = granted!;
logger.d("The notifications are enabled $notificationsEnabled");
}
Future<bool> requestPermissionsBluetooth() async {
if (Platform.isAndroid) {
var status = await [
Permission.bluetooth,
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.locationAlways,
Permission.locationWhenInUse,
].request();
// Check if all permissions are granted
return status.values.every((element) => element.isGranted);
}
return false;
}
Future<void> initializeNotifications() async {
const AndroidNotificationChannel channel = AndroidNotificationChannel(
notificationChannelId,
'Beacon service',
description:
'This channel is used for important notifications.', // description
importance: Importance.low, // importance must be at low or higher level
);
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings(ImageConstant.imgNotIcon);
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: false,
requestSoundPermission: false,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {},
);
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {},
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
}
Future<void> initBeaconScanTask() async {
logger.d("Initializing the beacon scan in the background and foreground");
try {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
autoStart: true,
onStart: beaconScanTask,
notificationChannelId: "This a notification for softener",
isForegroundMode: true,
autoStartOnBoot: true,
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: beaconScanTask,
onBackground: iosBackgroundBeaconScanTask,
),
);
// if (!(await service.isRunning())) {
service.startService();
// }
logger.d("Service started ");
} catch (e) {
logger.e(
"An error occurred when starting service. (${e.hashCode} : ${e.toString()})");
}
}
@pragma('vm:entry-point')
Future<bool> iosBackgroundBeaconScanTask(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
//TODO
return true;
}
@pragma('vm:entry-point')
void beaconScanTask(ServiceInstance service) {
// Set listeners for Android service instance
if (service is AndroidServiceInstance) {
service.setAsForegroundService();
service.setForegroundNotificationInfo(
title: "Scanning for softener",
content: "This service is scanning for softener beacons",
);
service.on('setAsForeground').listen((event) {
logger.i("BLE scanner is running as foreground service");
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
logger.i("BLE scanner is running as background service");
service.setAsBackgroundService();
});
}
service.on('stopService').listen((event) {
logger.i("BLE background service was stopped by OS request");
service.stopSelf();
});
backgroundBeaconScan();
}
I have tried changing the sdk in the build.gradle
android {
compileSdk 34
ndkVersion flutter.ndkVersion
defaultConfig {
minSdkVersion 29
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
I have added the channel id but this does nothing.