How do I correctly register a plugin with the FCM plugin
Turns out it was just the plugin after my first edit! Just tried it with shared preferences and it works!
MY_PACKAGE_NAME
import `in`.jvapps.system_alert_window.SystemAlertWindowPlugin
import fr.g123k.deviceapps.DeviceAppsPlugin
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin
import io.flutter.view.FlutterMain
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
import android.os.Build
import android.app.NotificationManager
import android.app.NotificationChannel
public class Application: FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
SystemAlertWindowPlugin.setPluginRegistrant(this);
createNotificationChannels();
FlutterMain.startInitialization(this);
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.firebasemessaging")) {
FirebaseMessagingPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
if (!registry!!.hasPlugin("in.jvapps.system_alert_window")) {
SystemAlertWindowPlugin.registerWith(registry!!.registrarFor("in.jvapps.system_alert_window"));
}
if (!registry!!.hasPlugin("plugins.flutter.io.shared_preferences")) {
SharedPreferencesPlugin.registerWith(registry!!.registrarFor("plugins.flutter.io.shared_preferences"));
}
}
fun createNotificationChannels() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "groupChannel";
val descriptionText = "This is the group channel";
val importance = NotificationManager.IMPORTANCE_HIGH;
val mChannel = NotificationChannel("59054", name, importance);
mChannel.description = descriptionText;
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager;
notificationManager.createNotificationChannel(mChannel);
}
}
}
anonymous-dev
Updated on December 22, 2022Comments
-
anonymous-dev over 1 year
I am using https://pub.dev/packages/firebase_messaging v6.0.16 and flutter v1.17.5
[√] Flutter (Channel stable, v1.17.5, on Microsoft Windows [Version 10.0.18362.900], locale en-US) [√] Android toolchain - develop for Android devices (Android SDK version 29.0.3) [√] Android Studio (version 4.0) [√] VS Code (version 1.47.0)
And I am trying to call a plugin inside my myBackgroundMessageHandler on the line where it says
AppAvailability.launchApp('com.companyname.appname');
class CloudMessagingService extends NotificationService { final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); void configure() { if (Platform.isIOS) _firebaseMessaging.requestNotificationPermissions(IosNotificationSettings()); _firebaseMessaging.configure( onMessage: (Map<String, dynamic> message) async { if (isDataNotification(message)) return; print('onMessage'); }, onLaunch: (Map<String, dynamic> message) async { if (isDataNotification(message)) return; print('onLaunch'); }, onResume: (Map<String, dynamic> message) async { if (isDataNotification(message)) return; print('onResume'); }, onBackgroundMessage: myBackgroundMessageHandler, ); } static Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async { print('on background message'); AppAvailability.launchApp('com.companyname.appname'); // it will throw an error when it tries to call the method channel in the app availability plugin return message; }
But I get the following error
E/flutter (28000): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method launchApp on channel com.pichillilorenzo/flutter_appavailability) E/flutter (28000): #0 MethodChannel._invokeMethod package:flutter/…/services/platform_channel.dart:154 E/flutter (28000): <asynchronous suspension> E/flutter (28000): #1 MethodChannel.invokeMethod package:flutter/…/services/platform_channel.dart:329 E/flutter (28000): #2 AppAvailability.launchApp package:flutter_appavailability/flutter_appavailability.dart:95 E/flutter (28000): #3 CloudMessagingService.myBackgroundMessageHandler package:moto_picto/…/firebase/cloud_messaging_service.dart:43 E/flutter (28000): #4 _fcmSetupBackgroundChannel.<anonymous closure> package:firebase_messaging/firebase_messaging.dart:38 E/flutter (28000): #5 MethodChannel._handleAsMethodCall package:flutter/…/services/platform_channel.dart:409 E/flutter (28000): #6 MethodChannel.setMethodCallHandler.<anonymous closure> package:flutter/…/services/platform_channel.dart:377 E/flutter (28000): #7 _DefaultBinaryMessenger.handlePlatformMessage package:flutter/…/services/binding.dart:199 E/flutter (28000): #8 _invoke3.<anonymous closure> (dart:ui/hooks.dart:290:15) E/flutter (28000): #9 _rootRun (dart:async/zone.dart:1184:13) E/flutter (28000): #10 _CustomZone.run (dart:async/zone.dart:1077:19) E/flutter (28000): #11 _CustomZone.runGuarded (dart:async/zone.dart:979:7) E/flutter (28000): #12 _invoke3 (dart:ui/hooks.dart:289:10) E/flutter (28000): #13 _dispatchPlatformMessage (dart:ui/hooks.dart:164:5)
The plugins work without any trouble in the app scope. This is happening for every plugin I tried!
So I think the problem is that the isolate that FCM makes isn't wrapped with the flutter engine from what I understand from this post.
https://github.com/flutter/flutter/issues/13937#issuecomment-656239596
but you need to create a custom Application class that hooks into the initialisation of the plugin's background FlutterNativeView.
I did follow the instructions and changed my Application.kt to the following
package com.companyname.appname import `in`.jvapps.system_alert_window.SystemAlertWindowPlugin import io.flutter.app.FlutterApplication import io.flutter.plugin.common.PluginRegistry import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService import io.flutter.view.FlutterMain import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin import android.os.Build import android.app.NotificationManager import android.app.NotificationChannel public class Application: FlutterApplication(), PluginRegistrantCallback { override fun onCreate() { super.onCreate(); FlutterFirebaseMessagingService.setPluginRegistrant(this); createNotificationChannels(); SystemAlertWindowPlugin.setPluginRegistrant(this); FlutterMain.startInitialization(this); } override fun registerWith(registry: PluginRegistry) { if (!registry!!.hasPlugin("io.flutter.plugins.firebasemessaging")) { FirebaseMessagingPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin")); } if (!registry!!.hasPlugin("in.jvapps.system_alert_window")) { SystemAlertWindowPlugin.registerWith(registry!!.registrarFor("in.jvapps.system_alert_window")); } } fun createNotificationChannels() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val name = "groupChannel"; val descriptionText = "This is the group channel"; val importance = NotificationManager.IMPORTANCE_HIGH; val mChannel = NotificationChannel("59054", name, importance); mChannel.description = descriptionText; val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager; notificationManager.createNotificationChannel(mChannel); } } }
and my MainActivity.kt
package com.companyname.appname import androidx.annotation.NonNull; import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugins.GeneratedPluginRegistrant class MainActivity: FlutterActivity() { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); } }
And my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.companyname.appname"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE " /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- io.flutter.app.FlutterApplication is an android.app.Application that calls FlutterMain.startInitialization(this); in its onCreate method. In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> <application android:name=".Application" android:label="App Name" android:icon="@mipmap/ic_launcher"> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> <action android:name="FLUTTER_NOTIFICATION_CLICK" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Light.NoActionBar"/> <!-- Don't delete the meta-data below. This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> <meta-data android:name="flutterEmbedding" android:value="2" /> <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id"/> </application> </manifest>
The notifications seem to be appearing correctly as heads up notifications, and I can call my BackgroundMessageHandler and execute code, it's just that I cannot do anything with any plugin in the myBackgroundMessageHandler. Did I implement it correctly?
It will always throw the error on this line
AppAvailability.launchApp('com.companyname.appname');
in themyBackgroundMessageHandler
because a method channel cannot be called by a isolate if the plugin is not registered.I also checked out this github post
But my Application.kt is setup like that
I tried doing flutter clean -> uninstalling the app -> installing the app as well. And the problem remains. Like they describe here
EDIT: When I use the DeviceApp plugin the same thing happens. I replaced
AppAvailability.launchApp('com.companyname.appname');
with
DeviceApps.openApp('com.companyname.appname');
So I added the following 2 lines to the registerWith method of Application.kt, and it seems to revolve the missing plugin exception
if (!registry!!.hasPlugin("fr.g123k.deviceapps")) { DeviceAppsPlugin.registerWith(registry!!.registrarFor("fr.g123k.deviceapps")); }
But the error changes to
E/flutter (25583): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()' on a null object reference, null) E/flutter (25583): #0 StandardMethodCodec.decodeEnvelope package:flutter/…/services/message_codecs.dart:569 E/flutter (25583): #1 MethodChannel._invokeMethod package:flutter/…/services/platform_channel.dart:156 E/flutter (25583): <asynchronous suspension> E/flutter (25583): #2 MethodChannel.invokeMethod package:flutter/…/services/platform_channel.dart:329 E/flutter (25583): #3 DeviceApps.openApp package:device_apps/device_apps.dart:81 E/flutter (25583): #4 CloudMessagingService.myBackgroundMessageHandler package:moto_picto/…/firebase/cloud_messaging_service.dart:73 E/flutter (25583): #5 _fcmSetupBackgroundChannel.<anonymous closure> package:firebase_messaging/firebase_messaging.dart:38 E/flutter (25583): #6 MethodChannel._handleAsMethodCall package:flutter/…/services/platform_channel.dart:409 E/flutter (25583): #7 MethodChannel.setMethodCallHandler.<anonymous closure> package:flutter/…/services/platform_channel.dart:377 E/flutter (25583): #8 _DefaultBinaryMessenger.handlePlatformMessage package:flutter/…/services/binding.dart:199 E/flutter (25583): #9 _invoke3.<anonymous closure> (dart:ui/hooks.dart:290:15) E/flutter (25583): #10 _rootRun (dart:async/zone.dart:1184:13) E/flutter (25583): #11 _CustomZone.run (dart:async/zone.dart:1077:19) E/flutter (25583): #12 _CustomZone.runGuarded (dart:async/zone.dart:979:7) E/flutter (25583): #13 _invoke3 (dart:ui/hooks.dart:289:10) E/flutter (25583): #14 _dispatchPlatformMessage (dart:ui/hooks.dart:164:5)
So now it is no longer saying plugin missing but it is saying
PlatformException(error, Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()
Edit 2:
I just noticed that the latest error https://github.com/g123k/flutter_plugin_device_apps/issues/31 might be one of the plugin itself. Going to see if different plugins work now
I hope I provided enough info, please let me know if more info is needed or if the question needs to altered. I can respond within a couple off minutes.