Firebase:从后台消息更新模型

Firebase: Update model from background message

当我的应用程序在后台从我们的服务器接收到带有数据对象的消息时,我将如何实现我的模型的新状态? FirebaseMessaging.onBackgroundMessage() 正在运行,我可以看到从服务器发送的数据,但我不知道如何使用这些新数据更新模型。将它分配给一个变量是有效的,但稍后读取这个变量 returns null。我也在使用 GetIt,但当应用程序处于后台时无法调用它。 所有教程只展示了如何接收数据(并将其打印到控制台),但 none 展示了当应用程序在后台时如何实际使用它。

编辑:我检查了多个描述云消息传递的来源,例如 https://firebase.flutter.dev/docs/messaging/usage/。他们中的大多数只是描述如何接收消息。示例:

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print("Handling a background message: ${message.messageId}");
}

我已经讲到这里了。我来自服务器的消息包含一个数据对象,它具有所需的模型值(例如:"newBalance" : 100.00)。但是,如何在我的应用程序中使用这些新数据在后台更新我的模型?我似乎无法访问它(如上文所述,稍后分配的变量returns null)。

您的选择有限,正如 documentation 所说:

Since the handler runs in its own isolate outside your applications context, it is not possible to update application state or execute any UI impacting logic. You can, however, perform logic such as HTTP requests, perform IO operations (e.g. updating local storage), communicate with other plugins etc.

例如,您可以使用 Shared preferences plugin 来保存从后台消息处理程序接收到的数据,例如:

import 'package:shared_preferences/shared_preferences.dart';

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
    final sharedPrefs = await SharedPreferences.getInstance();
    sharedPrefs.setString('data', <YOUR DATA FROM MESSAGE>);
}

由于此时你的应用处于后台,需要在恢复后取这个值。查看完整示例 here,但基本上您的主小部件中需要这样的东西:

@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
  if (state == AppLifecycleState.resumed) {
    final sharedPrefs = await SharedPreferences.getInstance();
    final data = sharedPrefs.getString('data');
    print('Found in SharedPrefs: $data');
  }
}

在此之后,您可以找到一种方法来更新您需要的任何内容,这些内容已经在您的应用程序上下文中。

经过将近一周的尝试,我想我找到了解决问题的方法。使用 hive 包,应用程序将新数据写入本地数据库。但是,当应用程序处于后台时,调用 Hive.initFlutter() 无效。所以我在 main() 方法中将目录 (await getApplicationDocumentsDirectory()).path 的路径写入 SharedPreferences 。然后,当应用程序在后台收到一条消息时,我调用

if (Platform.isAndroid) {
  SharedPreferencesAndroid.registerWith();
} else if (Platform.isIOS) {
  SharedPreferencesIOS.registerWith();
}

(来自包 shared_preferences_androidshared_preferences_ios),之后我可以检索 Hive 的路径 var dir = (await SharedPreferences.getInstance()).getString("keyForDir");。使用 Hive.init(dir) 我可以打开盒子并在那里写入我的数据(box.close() 之后)。最后,当应用程序再次位于前台时,我可以从 Hive 读取数据(之后不要忘记 box.close())。

呸,多么糟糕的解决方案,但这是唯一对我有用的解决方案。互联网上的其他一些人似乎也有同样的问题 (https://github.com/flutter/flutter/issues/98473),其他一些解决方案对他们有效,但对我无效。