0

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 ...)
arzi89
  • 1
  • 2
  • [flutter-run-an-app-as-a-background-service](https://stackoverflow.com/questions/51539893/flutter-run-an-app-as-a-background-service) help you with your background services. – Parth Prajapati Sep 30 '21 at 12:11
  • I already looked at all of this, but it's not really helping me with my problem as I'm not skilled with android app development. I just need a way to make a native method call to create a shortcut when I receive a notification when the app is not in the foreground – arzi89 Oct 01 '21 at 08:59

2 Answers2

0

I couldn't figure out how to make the method channel available without an active activity, but I found out that if you create a plugin the method channel is always accessible, even if the app is closed, so I made a plugin that can be used to create conversation shortcuts as an addition to the flutter_local_notifications plugin.

If anyone is interested: android_conversation_shortcut

arzi89
  • 1
  • 2
0

Use this package if you want to run smoothly: https://pub.dev/packages/background_fetch

Umair Ahmad
  • 21
  • 2
  • 4