Flutter:不能在 onBackgroundMessage 中使用任何插件

Flutter: Can't use any plugin in onBackgroundMessage

我正在使用 Firebase 推送通知,我想在触发 onBackgroundMessage 时执行我的一些代码。它实际上被触发是因为我在控制台中打印,但我尝试使用多个插件但没有成功。每次我都会收到类似(未处理的异常:MissingPluginException(未在频道 flutter_ringtone_player 上播放方法 flutter_ringtone_player)找到实现)的错误。我相信这是因为在应用程序的后台状态中没有应用程序上下文,但是这个功能有什么用,我实际上可以在其中做什么?

我想在触发 onBackgroundMessage 时播放声音。

    super.initState();

    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onBackgroundMessage: myBackgroundMessageHandler,
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
    );

static Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {        
  FlutterRingtonePlayer.play(
    android: AndroidSounds.notification,
    ios: IosSounds.glass,
    looping: true, // Android only - API >= 28
    volume: 0.8, // Android only - API >= 28
    asAlarm: true, // Android only - all APIs
  );

    print("background message executed");

  return null;
}

尝试在 Android 的应用程序 class 中注册您需要在 myBackgroundMessageHandler 中使用的插件。这是我的 Application.kt:

的示例
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
    super.onCreate()
    FlutterFirebaseMessagingService.setPluginRegistrant(this)
}

override fun registerWith(registry: PluginRegistry?) {
    PathProviderPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"))
    FlutterLocalNotificationsPlugin.registerWith(registry?.registrarFor("com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin"))
    FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
}
}

这是一个工作代码。当设备收到推送通知 (Firebase) 时,执行 onBackgroundMessage 并播放自定义声音,即使应用已关闭。

main.dart

static Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {        
    final assetsAudioPlayer = AssetsAudioPlayer();

    assetsAudioPlayer.open(
        Audio("assets/audio/alarm.mp3"),
    );

    print("sound played");

    return null;
  }

  void initState() {
    super.initState();

    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
      },
      onBackgroundMessage: myBackgroundMessageHandler
    );
  }

Application.kt

import com.github.florent37.assetsaudioplayer.AssetsAudioPlayerPlugin

class Application : FlutterApplication(), PluginRegistrantCallback {
    override fun onCreate() {
        super.onCreate()
        FlutterFirebaseMessagingService.setPluginRegistrant(this)
    }   

    override fun registerWith(registry: PluginRegistry) {
        AssetsAudioPlayerPlugin.registerWith(registry?.registrarFor("com.github.florent37.assetsaudioplayer"))

        FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
    }
}

为了避免此类问题,我建议在 flutter 上使用最新版本的 firebase_messaging(flutter 版本 >= 1.12)。如the official doc所述:

If you are using Flutter Android Embedding V2 (Flutter Version >= 1.12) then no additional integration steps are required for Android.

要在这种情况下继续使用 firebase,请执行以下步骤:

  1. 在您的 pubspec.yaml 文件中,添加以下两个依赖项:

    firebase_core: ^0.7.0
    firebase_messaging: ^8.0.0-dev.15  
    
  2. 运行 flutter pub get

代码示例:

在使用任何 firebase 服务之前,您需要按照 here

所述使用 await Firebase.initializeApp();

当应用程序在前台时接收 Firebase 推送的代码示例:

FirebaseMessaging _messaging;
await Firebase.initializeApp();
  _messaging = FirebaseMessaging.instance;
   //App is in the foreground

  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print('Got a message, app is in the foreground!');
    print('Message data: ${message.data}');

    if (message.notification != null) {
      print('Message also contained a notification: ${message.notification}');
    }
  });

代码示例应用程序在后台运行/已终止:

您需要定义一个顶级函数(class 之外的函数)。后者将在消息出现且应用程序处于后台时被调用: 根据the doc,应该是这样的:

Future<void> _firebaseMessagingBackgroundHandler(
RemoteMessage message,
) async {
   await Firebase.initializeApp();
   print('onBackgroundMessage received: $message');
  
 }

那么,这里就用到上面提到的:

 FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);