In Flutter, how do we use Firebase Messaging onBackgroundMessage to create a notification, using flutter_local_notifications?

huangapple go评论75阅读模式
英文:

In Flutter, how do we use Firebase Messaging onBackgroundMessage to create a notification, using flutter_local_notifications?

问题

我们正在开发一个加密聊天应用程序,我们在其中使用Firebase Messaging来进行数据通知。在显示实际通知给用户之前,需要在接收到数据通知后执行一些客户端逻辑,例如将电话号码翻译成本地联系人名称。这个翻译是通过与全局已经可用的映射进行查找来完成的。

数据通知正常接收,并且onBackgroundMessage回调也会被调用。然而,在onBackgroundMessage函数中似乎无法访问任何类型的状态。例如,打印已登录用户的电话号码返回null。
onMessage回调中打印相同的全局变量完全正常。

onMessage中运行flutter_local_notifications正常工作,但是从onBackgroundMessage中完全不起作用,因为找不到方法.show()的实现。目前,它声称flutterLocalNotificationsPlugin为空,但实际上并不是这样。

在我们看来,一旦应用程序进入后台,onBackgroundMessage无法访问应用程序提供的任何内容。必须采取一些措施,以使某些范围/上下文在后台进程中可用。目前,这主要是flutter_local_notifications插件的全部内容,以及本地联系人列表,以将电话号码翻译成名称。

有人有任何想法如何做到这一点吗?

以下是一些代码示例:

FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
final _chatRepository = ChatRepository();

Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) async {
  if (message.containsKey('data')) {
    await _showNotification(message);
    return Future<void>.value();
  }
}

Future _showNotification(message) async {
  List<String> numbers = [];
  numbers.add(message['data']['sender']);
  var name = await _chatRepository.translatePhoneNumbersToChatName(numbers);
  var androidPlatformChannelSpecifics = AndroidNotificationDetails(
      'channel id', 'channel name', 'channel description',
      importance: Importance.Max, priority: Priority.High);
  var iOSPlatformChannelSpecifics = IOSNotificationDetails();
  var platformChannelSpecifics = NotificationDetails(
      androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
  await flutterLocalNotificationsPlugin.show(
    0,
    name,
    message['data']['body'],
    platformChannelSpecifics,
    payload: message['data']['body'],
  );
}

class NotificationHandler {
  final FirebaseMessaging fcm = FirebaseMessaging();
  StreamSubscription iosSubscription;
  String deviceToken = "";

  Future<void> initialize() async {
    flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
    var initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');
    var initializationSettingsIOS =
        IOSInitializationSettings(onDidReceiveLocalNotification: onDidReceiveLocalNotification);
    var initializationSettings = InitializationSettings(initializationSettingsAndroid, initializationSettingsIOS);
    flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: onClickNotification);

    fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        if (message.containsKey('data')) {
          print(message);
          _showNotification(message);
        }
      },
      onBackgroundMessage: Platform.isIOS
          ? null
          : backgroundMessageHandler,
      onLaunch: (Map<String, dynamic> message) async {
        if (message.containsKey('data')) {
          print(message);
          _showNotification(message);
        }
      },
      onResume: (Map<String, dynamic> message) async {
        if (message.containsKey('data')) {
          print(message);
          _showNotification(message);
        }
      },
    );
    _updateDeviceToken();
  }
}

当然,上面的initialize在应用程序生命周期的早期调用。

英文:

We are working on an encrypted chat application where we use Firebase Messaging for data notifications. Some client-side logic needs to be done upon receiving a data notification, before showing an actual notification to the user. For example, a phone number will have to be translated to a local contact name. This translation is done by lookup with a map that is already available globally.

The data notifications are received just fine and the onBackgroundMessage callback is called as well. However, it seems impossible to access any kind of state from the onBackgroundMessage function. For example, printing the phone number of the logged in user returns null.
Printing this same global variable from the onMessage callback works just fine.

Running flutter_local_notifications from onMessage works fine, but again, does not work at all from onBackgroundMessage as 'no implementation could be found for the method .show()'. At the moment, it claims that flutterLocalNotificationsPlugin is null, which it isn't really.

It seems to us that onBackgroundMessage has no access to anything the app provides, as soon as the app is backgrounded. Something has to be done to make some of the scope/context available to the background process. For now, that would mainly be the flutter_local_notifications plugin in its entirety, as well as the local contacts list to translate phone number to name.

Has anyone got any idea how to do this?

Here is some of the code:

FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
final _chatRepository = ChatRepository();
Future&lt;dynamic&gt; backgroundMessageHandler(Map&lt;String, dynamic&gt; message) async {
if(message.containsKey(&#39;data&#39;)) {
await _showNotification(message);
return Future&lt;void&gt;.value();
}
}
Future _showNotification(message) async {
List&lt;String&gt; numbers = [];
numbers.add(message[&#39;data&#39;][&#39;sender&#39;]);
var name = await _chatRepository.translatePhoneNumbersToChatName(numbers);
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
&#39;channel id&#39;, &#39;channel name&#39;, &#39;channel description&#39;,
importance: Importance.Max, priority: Priority.High);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
name,
message[&#39;data&#39;][&#39;body&#39;],
platformChannelSpecifics,
payload: message[&#39;data&#39;][&#39;body&#39;],
);
}
class NotificationHandler {
final FirebaseMessaging fcm = FirebaseMessaging();
StreamSubscription iosSubscription;
String deviceToken = &quot;&quot;;
Future&lt;void&gt; initialize() async {
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid =
new AndroidInitializationSettings(&#39;@mipmap/ic_launcher&#39;);
var initializationSettingsIOS = new IOSInitializationSettings(onDidReceiveLocalNotification: onDidReceiveLocalNotification);
var initializationSettings = new InitializationSettings(initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: onClickNotification);
fcm.configure(
onMessage: (Map&lt;String, dynamic&gt; message) async {
if(message.containsKey(&#39;data&#39;)) {
print(message);
_showNotification(message);
}
},
onBackgroundMessage: Platform.isIOS
? null
: backgroundMessageHandler,
onLaunch: (Map&lt;String, dynamic&gt; message) async {
if(message.containsKey(&#39;data&#39;)) {
print(message);
_showNotification(message);
}
},
onResume: (Map&lt;String, dynamic&gt; message) async {
if(message.containsKey(&#39;data&#39;)) {
print(message);
_showNotification(message);
}
},
);
_updateDeviceToken();
}
.
.
.

Of course, the initialize above is called early on in the application lifecycle.

答案1

得分: 0

class NotificationHandler {
static final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // 将其设为类的静态字段
// ...
}

Future _showNotification(message) async {
// ...
await NotificationHandler.flutterLocalNotificationsPlugin.show( // 访问它
// ...
);
}

希望这对您有所帮助。

英文:
class NotificationHandler {
static final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); // make it a static field of the class
// ...
}
Future _showNotification(message) async {
// ...
await NotificationHandler.flutterLocalNotificationsPlugin.show( // access it
// ...
);
}

Hope this works for you.

答案2

得分: 0

这个插件比我能更好地解释了一切,但恰巧背景是一个完全不同的隔离/上下文,因此如果它们使用旧的(在Flutter 12之前的)API,它将无法访问任何插件。
https://pub.dev/packages/android_alarm_manager#flutter-android-embedding-v1

Embedding v1要求你注册想要从后台访问的任何插件。这样做可以使flutter_local_notifications正常工作。

不幸的是,FCM文档非常不足。

英文:

This plugin explains it all better than I could, but it just so happens that the background is a completely different isolate/context and thus it has no access to any plugins if they use an old (pre Flutter 12) API.
https://pub.dev/packages/android_alarm_manager#flutter-android-embedding-v1

Embedding v1 requires you to register any plugins that you want to access from the background. Doing this makes it flutter_local_notifications work properly.

Unfortunately, FCM docs are heavily lacking.

huangapple
  • 本文由 发表于 2020年1月6日 19:24:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611258.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定