[Firebase Messaging]:后台应用程序未调用时,后台消息处理程序方法未调用?

时间:2019-12-12 06:27:30

标签: flutter flutter-dependencies flutter-test

我正在开发一个使用FCM推送通知的应用程序,当该应用程序在后台或终止并接收新通知时,我需要将该通知的数据保存在(SQLITE)中,而无需单击通知或重新打开再次单击该应用程序,除非单击该通知,否则不会在应用程序中读取该通知。有什么建议吗?

这是我的NotificationHandler.dart

import 'dart:async';
import 'dart:io';
import 'package:eshaar/model/message.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:intl/intl.dart';
import 'package:eshaar/model/database_helper.dart';


FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
new FlutterLocalNotificationsPlugin();

Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
  print("onBackgroundMessage: $message");
  //_showBigPictureNotification(message);
  return Future<void>.value();
}


Future onSelectNotification(String payload) async {

}

class NotificationHandler {
  FirebaseMessaging _fcm = FirebaseMessaging();
  StreamSubscription iosSubscription;
  DatabaseHelper db = new DatabaseHelper();
  static final NotificationHandler _singleton =
  new NotificationHandler._internal();

  factory NotificationHandler() {
    return _singleton;
  }
  NotificationHandler._internal();

  initializeFcmNotification() async {
    var initializationSettingsAndroid =
    new AndroidInitializationSettings('mipmap/ic_launcher');
    var initializationSettingsIOS = new IOSInitializationSettings(
        onDidReceiveLocalNotification: onDidReceiveLocalNotification);
    var initializationSettings = new InitializationSettings(
        initializationSettingsAndroid, initializationSettingsIOS);
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);

    if (Platform.isIOS) {
      iosSubscription = _fcm.onIosSettingsRegistered.listen((data) {
        // save the token  OR subscribe to a topic here
      });

      _fcm.requestNotificationPermissions(IosNotificationSettings());
    } else {
      _saveDeviceToken();
    }

    _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("---------------------On Message--------------------");
        displayNotification(message['data']['title'],message['data']['body']);
        _saveNotificationToLocal(message);
      },
      onBackgroundMessage: Platform.isIOS ? null : myBackgroundMessageHandler ,
      onLaunch: (Map<String, dynamic> message) async {
        print("---------------------On Lunch--------------------");
        _saveNotificationToLocal(message);
      },
      onResume: (Map<String, dynamic> message) async {
        print("---------------------On Resume--------------------");
        _saveNotificationToLocal(message);
      },
    );
  }

  _saveNotificationToLocal(Map<String, dynamic> message){
    String sender_id = message['data']['sender_id'];
    String message_id = message['data']['message_id'];
    String title = message['data']['title'];
    String body = message['data']['body'];
    String del_time  = getCurrentDateTime();
    Messages msg = new Messages(sender_id,message_id,title,body,del_time);
    db.saveMessages(msg);

  }

 String getCurrentDateTime(){
   var now = new DateTime.now();
   var formatter = new DateFormat('MMM d yy h:mm a');
   String formatted = formatter.format(now);
   return formatted;
  }

  /// Get the token, save it to the database for current user
  _saveDeviceToken() async {
    String fcmToken = await _fcm.getToken();
  }


  Future<void> onDidReceiveLocalNotification(
      int id, String title, String body, String payload) async {
    // display a dialog with the notification details, tap ok to go to another page
  }

  void displayNotification(String title,String body) async{
    var androidPlatformChannelSpecifics = AndroidNotificationDetails(
        'your channel id', 'your channel name', 'your channel description',
        importance: Importance.Max, priority: Priority.High, ticker: 'ticker');
    var iOSPlatformChannelSpecifics = IOSNotificationDetails();
    var platformChannelSpecifics = NotificationDetails(
        androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
    await flutterLocalNotificationsPlugin.show(
        0, '$title', '$body', platformChannelSpecifics,
        payload: 'item x');
  }
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ot.eshaar.eshaar">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE" />



    <!-- 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="eshaar"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- This keeps the window background of the activity showing
                 until Flutter renders its first frame. It can be removed if
                 there is no splash screen (such as the default splash screen
                 defined in @style/LaunchTheme). -->
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />


            <meta-data
                    android:name="com.google.firebase.messaging.android.channel_id"
                    android:value="mmne" />

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


            <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>
        <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>
        <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />


    </application>
</manifest>

扑打医生-v

[✓] Flutter (Channel stable, v1.9.1+hotfix.6, on Mac OS X 10.14.4 18E226, locale
    en-US)
    • Flutter version 1.9.1+hotfix.6 at /Users/mahmoudabdelaziz/Desktop/flutter
    • Framework revision 68587a0916 (3 months ago), 2019-09-13 19:46:58 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/mahmoudabdelaziz/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-1343-b01)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.0, Build version 11A420a
    • CocoaPods version 1.8.4

[!] Android Studio (version 3.4)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build
      1.8.0_152-release-1343-b01)

[✓] IntelliJ IDEA Community Edition (version 2018.3.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 31.3.4
    • Dart plugin version 183.5153.38

[✓] Connected device (1 available)
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 9 (API
      28) (emulator)

4 个答案:

答案 0 :(得分:7)

已经很晚了,但我仍然会回应其他人的帮助。

这里的问题与处理无关,而与您从Firebase控制台发送的消息类型有关。 onBackgroundMessage仅当消息是数据消息或带有数据有效负载的通知消息时,才调用callBack。

并确保您的邮件中也添加了click_action: 'FLUTTER_NOTIFICATION_CLICK'

从Firebase控制台生成消息也存在一些问题,因此请尝试直接从服务器生成消息。 有关更多详细信息,请查看此thread


答案 1 :(得分:3)

在我的情况下,仅在有效负载上没有通知时才触发FCM onBackgroundMessage。如果有效负载上有通知,它将发送通知,并在系统托盘上显示通知。

但是,如果要对发送的数据进行一些编译,请删除有效负载上的通知,然后仅发送数据

{
  "to" : "Place the token of the test device here",
  "click_action": "FLUTTER_NOTIFICATION_CLICK",
  "priority": "high",
  "data" : {
     "type" : "anything",
     "title": "Title of Your Notification in Title",
     "key_1" : "Value for key_2"
  }

}

答案 2 :(得分:0)

在myBackgroundMessageHandler中,您需要调用该函数以将通知保存到本地存储中。

例如

Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
  print("onBackgroundMessage: $message");
  //_showBigPictureNotification(message);
    NotificationHandler()._saveNotificationToLocal(message);
  return Future<void>.value();
}

希望有帮助。

答案 3 :(得分:0)

请确保您在发送通知时添加了click_action属性。 确保其值与您在android intent中提供的值匹配。

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