I'm using Firebase and flutter local notifications to display notifications I get from my server. I wanted to display certain notifications inside the conversation part of the android notifications, so I made a native kotlin call using the method channel to create a shortcut for this:
Dart
static Future<String?> _createConversationShortcut(
String personName, String personIconPath) async {
const platform = MethodChannel('...');
String result;
try {
result = await platform.invokeMethod('createConversationShortcut', {
'personName': personName,
'personIcon': personIconPath,
});
} on PlatformException catch (e) {
return null;
}
return result;
}
I call the method _createConversationShortcut to create a shortcut natively and then use the shortcut ID in the AndroidNotificationDetails so that the notification is in the Conversation part
flutterLocalNotificationsPlugin.show(
int.parse(person.key!),
notification,
text,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
icon: '@drawable/is_notification',
category: 'msg',
shortcutId: shortcutId,
styleInformation: MessagingStyleInformation(
person,
groupConversation: false,
conversationTitle: 'Neue Privatnachricht',
messages: messages,
),
//setAsGroupSummary: true,
),
),
payload: json.encode(payload),
);
Kotlin
class MainActivity: FlutterActivity() {
private val CHANNEL = "..."
private fun createConversationShortcut(personName: String, personIcon: String): String {
val person = Person.Builder()
.setName(personName)
.setIcon(IconCompat.createWithContentUri(personIcon))
.build()
val shortcut = ShortcutInfoCompat.Builder(context, personName.toLowerCase(Locale.ROOT).replace(" ", "_") + "_shortcut")
.setLongLived()
.setIntent(Intent(Intent.ACTION_VIEW))
.setPerson(person)
.setShortLabel(personName)
.build()
ShortcutManagerCompat.addDynamicShortcuts(context, listOf(shortcut))
return shortcut.id
}
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "createConversationShortcut") {
val personName = call.argument<String>("personName")
val personIcon = call.argument<String>("personIcon")
if (personName != null && personIcon != null) {
val shortcutId = createConversationShortcut(personName, personIcon)
result.success(shortcutId)
} else {
result.error("argument-error", "Too few arguments", null)
}
} else {
result.notImplemented()
}
}
}
}
This works perfectly when the app is in the foreground but when my app is in the backgroudn or closed I get an ImplementationError because MainActivity doesn't exist.
My question now is, how can I invoke the method channel, when the app is in the background or closed? I read that I need to create a service for that but I have no clue how I can set the method call handler from inside the service. Can anyone please help my with this?
EDIT:
I tried to start a service after the app is opened for the first time by making a Method call in the dart main file
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "startHeadlessService"){
if (!context.isMyServiceRunning(FlutterService::class.java)) {
Log.d("pushNotificationService", "Service starting")
val intent = Intent(context, FlutterService::class.java)
context.startService(intent)
} else {
Log.d("pushNotificationService", "Service already Running")
}
result.success(null)
} else {
result.notImplemented()
}
}
}
and in the onStartCommand function of my service I tried to setup a methodchannel like this:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("TAG", "Hello foreground service")
FlutterMain.startInitialization(this);
FlutterMain.ensureInitializationComplete(this, null);
val flutterEngine = FlutterEngine(this)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "createConversationShortcut") {
val personName = call.argument<String>("personName")
val personIcon = call.argument<String>("personIcon")
if (personName != null && personIcon != null) {
val shortcutId = createConversationShortcut(personName, personIcon)
result.success(shortcutId)
} else {
result.error("argument-error", "Too few arguments", null)
}
}
}
return super.onStartCommand(intent, flags, startId)
}
But I still get the error:
Unhandled Exception: MissingPluginException(No implementation found for method saveBitmapAsCircle on channel ...)