Firebase Messaging onResume和onLaunch不起作用。

40

我在应用程序在前台时可以收到通知,但在后台时却不能。此外,我已经在Google和StackOverflow上搜索了2个小时或更长时间,但仍无法解决这个问题。

我的配置如下:

  firebase_auth: ^0.10.0
  firebase_messaging: ^5.0.0

清单文件是这样的:

Manifest

代码如下:

final notifications = new FirebaseMessaging();

class AppNotifications {
  static String fcmToken = '';

  static Future<Null> init() async {
    appLogs("AppNotifications init");

    notifications.requestNotificationPermissions(const IosNotificationSettings(sound: true, badge: true, alert: true));

    await configure();

    fcmToken = await notifications.getToken();
    appLogs("FCM TOKEN : " + fcmToken);

    notifications.onTokenRefresh.listen((newToken) {
      fcmToken = newToken;
      appLogs("FCM TOKEN onTokenRefresh: " + fcmToken);
    });

    await updateFCMToken();
  }

  static Future<Null> configure() async {
    appLogs("AppNotifications Configure");

    notifications.configure(onMessage: (msg) {
      appLogs('FCM onMessage: ' + msg.toString());
    }, onLaunch: (lun) {
      appLogs('FCM onLaunch: ' + lun.toString());
    }, onResume: (res) {
      appLogs('FCM onResume: ' + res.toString());
    });
  }

  static Future<Null> updateFCMToken() async {
    auth.currentUser.fcmToken = fcmToken;
    await updateUserInSharedPreference();
  }
}

我是这样调用函数的:

class HomeScreenState extends State<HomeScreen> {


  @override
  void initState() {
    super.initState();

    Future.delayed(Duration(milliseconds: 100), () async {
      await AppNotifications.init();
    });
  }

..... ....

我正在使用Postman发送通知:

Postman

我的日志:

**(App is Foreground)**  I/flutter (31888): APPLOGS : FCM onMessage: {notification: {title: Test notification title, body: Test notification body}, data: {status: done, id: 1, foo: bar, click_action: FLUTTER_NOTIFICATION_CLICK}}
  **(App is Background)**  W/FirebaseMessaging(31888): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.

Flutter医生:

[✓] Flutter (Channel stable, v1.2.1, on Mac OS X 10.14.4 18E226, locale en-GB)
    • Flutter version 1.2.1 at /Users/Ajay/SDK/flutter
    • Framework revision 8661d8aecd (3 months ago), 2019-02-14 19:19:53 -0800
    • Engine revision 3757390fa4
    • Dart version 2.1.2 (build 2.1.2-dev.0.0 0a7dcf17eb)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/Ajay/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
    • All Android licenses accepted.

[✓] iOS toolchain - develop for iOS devices (Xcode 10.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.2.1, Build version 10E1001
    • ios-deploy 1.9.4
    • CocoaPods version 1.6.0

[✓] Android Studio (version 3.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 34.0.1
    • Dart plugin version 182.5215
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)

[!] VS Code (version 1.33.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    ✗ Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (1 available)
    • ONEPLUS A5000 • b47e8396 • android-arm64 • Android 9 (API 28)

我也在Android上遇到了通知支持的问题。除此之外,当应用程序在前台时,我无法收到通知。但即使是在“后台到达”通知的情况下,在应用程序启动时数据有效负载也会丢失。然而,iOS却完美地运行。 - George Zvonov
我最终通过在 runApp(MyApp()) 内部初始化 Firebase 来解决我的 Firebase Messaging 问题。由于您似乎已经这样做了,因此您的代码流程和我的唯一区别在于您使用版本 5.0.0。您尝试过降级吗?例如,我使用的是 4.0.0+4 版本。 - George Zvonov
1
@George 当从API接收到推送通知时,click_action参数是否必须存在?onLaunch和onResume方法是否不会被调用? - Shangari C
@AjayKumar,你解决了这个问题吗? - Shangari C
2
如果您的目标是 Android 设备,建议使用 click_action。否则,当用户在托盘中单击通知时,onLaunch / onResume 将不会被调用。有关更多信息,请查看文档中的 _发送消息_。 - George Zvonov
@George 好的,谢谢。但是在iOS中,如果我的应用程序在后台运行,通知横幅不会出现。只有在打开应用程序前景通知时,对话框才能从API正常工作。如果我从控制台触发,所有内容都正常工作。对此有什么建议吗? - Shangari C
10个回答

66

我花了两天时间来解决这个问题,这可能对你有所帮助。 notification标签只用于显示通知。您只能在onResume/onLaunch上访问数据内容。

如果您想在onResume/onLaunch内处理通知消息,请将这些消息添加到data标签中,然后可以随意操作。

请参考此链接获取更多详细信息。

发送此通知消息

{
       "notification": {
          "body": "body",
          "title": "title"
       },
       "priority": "high",
       "data": {
        "body": "body",
          "title": "title"
          "click_action": "FLUTTER_NOTIFICATION_CLICK",
          "id": "1",
          "status": "done",
          "image": "https://ibin.co/2t1lLdpfS06F.png",
       },
       "to": <your token>
    }

您将在onResume或onLaunch收到以下信息,此时您的通知标签将为空。

{notification: {}, data: {image: https://ibin.co/2t1lLdpfS06F.png, google.original_priority: high, google.sent_time: 1560858283888, google.delivered_priority: high, body: body , title: title, click_action: FLUTTER_NOTIFICATION_CLICK, google.message_id: 0:1560858283908500%eefdc741eefdc741, collapse_key: <package>, google.ttl: 2419200, from: <from>, id: 1, status: done}}

您可以使用添加在数据标签中的标题和正文。


21
这就是正确的答案!“click_action”键需要放在“data”对象内部。Firebase的文档极其不完善。 - Sandeep Chayapathi
1
在一些教程中,他们提到了“clickAction”,这引起了这个问题。 - moslem
1
@MDavid 你能告诉我在哪个路由里放置firebase init代码吗? 我已经添加了,但仍然无法运行。 通知在后台显示,但onResume没有工作。 - Naeem
谢谢@MDavid,你能给我一个例子吗?我尝试了但是没找到。 - Naeem
@MDavid 好的,我已经收到数据了,现在我想在空上下文中启动我的铃声屏幕,因为应用程序在后台运行。 请查看:https://stackoverflow.com/questions/61700435/how-to-start-specific-screen-when-notification-appear-in-flutter - Naeem
显示剩余7条评论

31

在我的情况下,onResumeonLoad没有触发,因为我缺少click_action: 'FLUTTER_NOTIFICATION_CLICK'notification属性下,而不是在data属性下

一旦我将我的负载更改为以下格式,onResumeonLoad开始正常工作。

{
    notification: {
        title: 'Title',
        body: 'Body',
        click_action: 'FLUTTER_NOTIFICATION_CLICK'
    }
}

我在这里找到了相关文档。

如果您在TypeScript(或其他语言)中进行设置,您需要通过消息的android.notification.clickAction属性来设置。否则,您可能会收到有关该属性无效的错误。以下是使用MulticastMessage的示例。请注意,它并没有从头开始显示消息构造;只足以展示设置clickAction的上下文。

// Initialize the notification
const notification: admin.messaging.Notification = {
    title: 'Hello',
    // Though the "clickAction" property is available here, it throws an error about
    // having an invalid property when actually trying to send the notification.
    // Instead, the "clickAction" property is set further downstream under the
    // MulticastMessage.android.notification object.
    // clickAction: 'FLUTTER_NOTIFICATION_CLICK'
};

// Do other things to build your notification

const message: admin.messaging.MulticastMessage = {
    tokens: [],
    notification: notification
};

// Do other things to build your message

// If a notification is being sent then set the click_action
if (message.notification) {
    // Combine with the existing message.android object, if one exists
    message.android = message.android || {};
    message.android.notification = Object.assign(message.android.notification || {}, {
        clickAction: 'FLUTTER_NOTIFICATION_CLICK'
    });
}

1
如果将其放置在数据标签中,它会启动我的活动,但 onResume 和 onLoad 不起作用。 - Anand saga
1
如果我将其添加到“notification”负载中,则会出现以下错误:接收到无效的JSON负载。在\'message.notification\'处未知名称“click_action”:找不到字段。 - Shajeel Afzal
我更新了我的答案,展示了我们如何在代码中设置它的示例。 - cokeman19
这必须放置在android.notification对象中,而不是常规notification对象中!!!!!! - giorgio79

4
在firebase_messaging包的文档中的此处
插件文档链接上,他们说您需要在服务器端的POST请求中作为“自定义数据”键值对包括click_action: FLUTTER_NOTIFICATION_CLICK,以便调用onResumeOnlaunch方法。

例如,这里使用php firebase admin sdk发送通知到FCM,以下是发送通知的代码示例:

        $factory = (new Factory)->withServiceAccount('path to firebase keys json file');
                $messaging = $factory->createMessaging();

                $deviceToken = $user->deviceToken;
    $message = CloudMessage::withTarget('token', $deviceToken)
                        ->withNotification(Messaging\Notification::create('title', 'body'))
                        ->withData(['custom-data-key1' => 'custom-data-value1', 'custom-data-key2' => 'custom-data-value2', 'click_action'=>'FLUTTER_NOTIFICATION_CLICK']);
$messaging->send($message);

2
你可能在AndroidManifest中缺少一些元数据(正如日志所告诉你的那样)。 你需要将以下内容添加到你的清单文件中:

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/default_notification_channel_id"/>

看起来这是一个重复的问题


2
在处理 FCM 故障排除时,另一件需要注意的事情是在你的 onMessage 处理中。首先,在 onMessage 中打印输出以查看设备是否接收到消息。通知可能会在此之后失败并且不显示,因此了解它是否得到了是很好的。如果是这样,那么您就知道已经正确配置了 FCM,而您的问题在于 UI 处理。接下来,检查 onMessage 打印语句并确保在其后处理数据的方式是正确的。我注意到 Android 数据与 iOS 类型的结构模式不同,因此这可能导致您错误地解析数据,这可能不会显示通知,并且也不会引发错误。以下是我的一个例子:
    _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        String sender;
        String parsedMessage;

        if (Platform.isAndroid) {
          sender = message['notification']['title'];
          parsedMessage = message['notification']['body'];
        }
        if (Platform.isIOS) {
          sender = message['aps']['alert']['title'];
          parsedMessage = message['aps']['alert']['body'];
        }
      },
    );

你可以看到,我根据平台的不同以不同的方式解析相同的数据。如果不这样做,通知将永远不会出现,也不会指示任何失败。
再次强调,在拆开.ts/.js云函数之前,请先尝试此方法。

2

安德·萨加发布的答案是正确的。

您需要在数据部分中添加标题和正文。通知负载将在 onResume 和 onLaunch 中为空,尽管它是从后端 Node.js API 发送的。

以下是 Flutter 正在解决的示例负载:

on resume {notification: {}, data: {image: https://ibin.co/2t1lLdpfS06F.png, google.original_priority: normal, google.sent_time: 1577389234347, google.delivered_priority: normal, body: "Custom Body", type: OrderDetail, title: "Custom title", click_action: FLUTTER_NOTIFICATION_CLICK, google.message_id: 0:1577389234352165%dfef845edfef845e, collapse_key: <<App NAme>>, google.ttl: 2419200, from: 790713779055, id: "5e050c04c308f6abb5a60b2e"}}

典型的Dart配置应该是这样的。
firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print('on message ${json.encode(message['data']['title'])}');
        redirectScreenOnLoad(message);
      },

      onResume: (Map<String, dynamic> message) async {
        firebaseMessaging.onTokenRefresh;
        print('on resume $message');
        redirectScreenOnLoad(message);

      },

      onLaunch: (Map<String, dynamic> message) async {
        firebaseMessaging.onTokenRefresh;
//        await API.updateUserApiToGetFCMKey();
        print('on launch $message');
        redirectScreenOnLoad(message);
      },
    );

在redirectScreenOnLoad(String message)函数中,我会检查输入负载并将其重定向到不同的屏幕。

1
这是关于Android的问题,但在iOS中json里不存在[data],你是否也已经解决了iOS上的这个问题?我已经困扰了整整一个星期,在onResume中可以运行,但在onLaunch时会失败。 - Argel Bejarano
我没有在iOS上测试过。你能否发布一下从Firebase消息中获取的回应? - downlz
只需要让它工作,需要从initiState调用才能运行。 - Argel Bejarano
redirectScreenOnLoad() 函数在哪里? - Hitesh sapra
这只是一些配置问题,您需要完全按照文档中的步骤进行操作,它就能正常工作。 - Argel Bejarano
您能展示一下redirectScreenOnLoad函数吗? - Roxx

1

完整指南:处理Firebase消息:

handleMessaging() {
  _firebaseMessaging.configure(
    onMessage: (Map<String, dynamic> message) async {
      // showNotification(
      //     message['notification']['title'], message['notification']['body']);
      print("onMessage: $message");

      print('Data is: '+ message['data']['screen'].toString());

    },
    onLaunch: (Map<String, dynamic> msg) {
      print("Called onLaunch");
      print(msg);
      print('Data is: '+ msg['data']['screen'].toString());

      if(msg['data']['screen'].toString() == 'Chat Screen') {
        return //Navigate to chatApp();
      }
      return null;
    },
    onResume: (Map<String, dynamic> msg) {
      //(App in background)
      // From Notification bar when user click notification we get this event.
      // on this event navigate to a particular page.
      print(msg);

      // // Assuming you will create classes to handle JSON data. :)
      // Notification ns = Notification(title: msg['title'], body: msg['body']);
      //        
      return null;
    },
    // onMessage: (Map<String, dynamic> msg) {
    // // (App in foreground)
    // // on this event add new message in notification collection and hightlight the count on bell icon.
    // // Add notificaion add in local storage and show in a list.
  );
}

0
onLaunch: (Map<String, dynamic> msg) {
    print("Called onLaunch");
    print(msg);
    if(msg['data']['screen'].toString() == 'chat') {
        //Navigate to chat screen
    }
    return null;
},

0
如果你的安卓应用使用 Kotlin 开发,你应该将这个作为你的应用程序活动添加进去。
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService

class Application : FlutterApplication(), PluginRegistrantCallback {

    override fun onCreate() {
        super.onCreate()
        FlutterFirebaseMessagingService.setPluginRegistrant(this);
    }

    override fun registerWith(registry: PluginRegistry?) {
        io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
    }
}

不要忘记在Manifest文件中添加以下内容:android:name=".Application"


0

重要提示:FirebaseMessaging的新版本是一个重大变化,如果您发现了这个线程,那么以上所有内容都将无法使用。

Configure已经消失了,与Flutter 2的其他更新一样,事情都是通过.listen方法完成的。 关于此事有一个线程: 如何在Flutter中使用最新版本配置Firebase Messaging?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接