应用程序终止时未获取有效载荷数据,Flutter FCM和LPN



我通过FCM和LocalPushNotifications设置推送通知,我可以在应用程序的前台和后台设置它。在应用程序的终止状态下,我确实会收到通知,但当我按下它时,不会发生任何操作,即使应用程序的前台和后台状态工作正常,并将用户导航到通知屏幕,但在终止状态中,应用程序只会打开,不会导航到通知屏,只会打开应用程序的主屏幕。由于设备没有连接,我在控制台日志中看不到错误,但当我从模拟器启动应用程序时,这就是我启动时得到的:

I/flutter ( 3829): Got a message whilst in the terminated state!
I/flutter ( 3829): Message data: null

这在FirebaseMessaging.instance.getInitialMessage().then()...pushNotifications()方法内部调用

这是里面有注释的代码:

处理推送通知的逻辑:

Future<void> pushNotifications() async {
await Firebase.initializeApp();
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
_handleMessage(initialMessage);
}
/// THIS IS NOT WORKING, IT OPENS THE APP BUT DOESN'T NAVIGATE TO THE DESIRED SCREEN
///gives you the message on which user taps
///and it opened the app from terminated state
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) {
LocalNotificationService.display(message);
print('Got a message whilst in the terminated state!');
print('Message data: ${message.data}');
if (message != null) {  
print('terminated state');
}
});
///forground work
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
LocalNotificationService.display(message);
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
});

///EVEN THOUGH IT IS SUPPOSED TO WORK LIKE THIS, I ONLY MANAGED TO MAKE IT WORK WITH BACKGROUND HANDLER, THIS METHOD NEVER TRIGGERS
///When the app is in background but opened and user taps
///on the notification
FirebaseMessaging.onMessageOpenedApp.listen((message) {
print('Got a message whilst in the background!');
print('Message data: ${message.data}');
_handleMessage(message);
LocalNotificationService.display(message);
});
}

///THIS HANDLES THE NOTIFICATIONS WHEN THE APP IS IN THE BACKGROUND
Future<void> _handleMessage(RemoteMessage message) async {
await Firebase.initializeApp();
if (message.data != null) {
print('message handler');
LocalNotificationService.display(message);/// ALL OF THESE CALLED FROM THE LocalNotificationService CLASS BELOW
}
}
///MAIN METHOD, WHERE I INITIALIZE FIREBASE AND THE METHODES ABOVE(pushNotifications()), HANDLE THE MESSAGES WITH onBackgroundMessage(_handleMessage),
void main() async {
WidgetsFlutterBinding.ensureInitialized();
pushNotifications();
var initializationSettingsAndroid =
AndroidInitializationSettings("@mipmap/ic_launcher");
var initializationSettingsIOS = IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
await Firebase.initializeApp();
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.onBackgroundMessage(_handleMessage);
runApp(MyApp());
}

我的本地通知服务类别:

class LocalNotificationService {
static final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
static void initialize(BuildContext context) {
final InitializationSettings initializationSettings =
InitializationSettings(
android: AndroidInitializationSettings("@mipmap/ic_launcher"));
_notificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String payloadData) async {

if (payloadData!= null) {

Navigator.pushNamed(context, NotificationsScreen.id);
}
});
}
static void display(RemoteMessage message) async {
try {
final id = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
"push notifications",
"push notifications",
"push notifications",
importance: Importance.max,
priority: Priority.high,
));
await _notificationsPlugin.show(
id,
'push notifications',
'You have received a new push notification!',
notificationDetails,
payload: message.data['default'], // THIS IS NULL WHEN IN TERMINATED STATE OF APP
);
} on Exception catch (e) {
print('exception: ' + e.toString());
}
}
}

因此,正如我所说,前台和后台状态都在工作,并对应于正确的屏幕,但终止的应用程序状态根本不对应,但它确实显示通知,并在点击时打开应用程序。

我是不是错过了什么?我主要是自己遵循文档和一些东西,但它仍然没有按预期工作。

感谢任何形式的帮助,提前感谢!

我还没能完全解决你描述的问题,这非常令人沮丧。

这就是我到目前为止所发现的,我将把它放在这里,因为它可能会帮助你:

有三种类型的消息,datanotificationmixed

如果使用纯数据负载

  • 消息基本上是无声的
  • onMessage在应用程序停飞时确实响应数据通知
  • onMessageOpenedApp在任何情况下都不会触发数据消息
  • onBackgroundMessage用于在处于终止状态或后台状态时使用本地通知显示消息
  • 由您(使用本地通知包)使用onSelectNotification处理他们的点击
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: selectNotification
);
  • 你不能在所有这些场景中使用onSelectNotification(据我所知,***这是我现在的绊脚石

如果使用纯通知或混合有效负载

  • 当应用程序是后台(但不是前台)时,FCM包将为您显示通知

  • 应用程序预测时onMessage确实对数据做出响应

  • 当在后台状态(但不适用于终止状态)点击通知时,onMessageOpenedApp将触发

  • onBackgroundMessage将触发,但与上面不同的是,您不应该使用它来显示通知,因为这将强制双重通知(一个由FCM包处理,另一个由您手动完成)

  • 点击,当应用程序后台时由软件包处理,但当前台时由您处理。***可能也被终止,目前还不确定。

正如我所提到的,到目前为止,我已经列出了一些事实。这非常棘手和令人沮丧。让我慢下来的是,当使用混合有效载荷(我一直在使用)时,在终止时,通知要么根本不来,要么按自己的速度来(在发送数小时后)。

如果你在这个问题上取得进展,请告诉我,我认为我们在同一条船上。。。

@GrandMagus幸运的是,我刚刚开始工作!!(让onMessageOpenedApp触发,所以我做了一些更改,但我不确定是哪一个启动了。

  • 我清除了所有缓存,删除了应用程序并从头开始安装
  • 编辑了AndroidManifest.xml以按照文档的建议进行更改,如果您确实这样做了,它们是:<intent-filter> <action android:name="FLUTTER_NOTIFICATION_CLICK" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>

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

  • 将我的有效载荷更改为混合datanotification。我在有效载荷中包含了FLUTTER_NOTIFICATION_CLICK。我可以进一步解释,如果你不知道那是什么。它的关键是让你的有效载荷至少有notification信息。这将强制包创建通知,然后该通知将响应单击。在这种情况下,不要自己创建本地推送通知,否则您将收到2个通知。如果您得到两个,您会注意到包生成的一个实际上将运行onMessageOpenedApp
  • 我开始在Release mode中测试我的应用程序。我想知道AndroidManifest.xml的更改是否只允许在每个.xml文件中放置提醒通知才能工作。在这种情况下,我正在编辑release文件,但正在调试版本上进行测试

我遇到了一些类似的问题,最终可以用不同的方式使用Navigator.pushNamed()来解决它。尽管我处理通知的方式与您有所不同。以下是我所做的:

  • 创建文件route_generator.dart->这将允许您处理通过应用程序的路由,并将有效载荷传递到另一个屏幕:
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
// my homescreen
case '/':
return MaterialPageRoute(
builder: (context) => const ShoppingItemListScreen());
// my target screen to reach from notifications
case '/add':
return MaterialPageRoute(
builder: (context) => AddShoppingItemScreen(
// my data payload from notifications I'm passing to the screen
shoppingItem: args,
));
default:
return _errorRoute();
}
}
static Route<dynamic> _errorRoute() {
return MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text('ERROR'),
centerTitle: true,
),
body: const Center(
child: Text('Page not found!'),
),
);
});
}
}
  • main.dartStatelessWidget中使用GlobalKey
class MyApp extends StatelessWidget {
const MyApp({super.key});
// this is your GlobalKey
static final GlobalKey<NavigatorState> navigatorKey =
GlobalKey(debugLabel: 'Main Navigator');
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
  • 在处理与通知交互的async方法中使用GlobalKey
void onTapLocalNotification(NotificationResponse notificationResponse) async {
final String? payload = notificationResponse.payload;
debugPrint(payload);
await MyApp.navigatorKey.currentState!.pushNamed(
'/add',
arguments: ShoppingItem(name: payload!),
);
}
  • 调用onTapLocalNotification:
final FlutterLocalNotificationsPlugin notificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> launchNotification() async {
const InitializationSettings initializationSettings =
InitializationSettings(
android: AndroidInitializationSettings("@drawable/ic_launcher"),
iOS: DarwinInitializationSettings(
requestSoundPermission: true,
requestAlertPermission: true,
requestBadgePermission: true,
),
);
// getting information if notification launched the app (from terminated state)
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await notificationsPlugin.getNotificationAppLaunchDetails();
final didNotificationLaunchApp =
notificationAppLaunchDetails?.didNotificationLaunchApp ?? false;
if (didNotificationLaunchApp) {
var payload = notificationAppLaunchDetails!.notificationResponse;
onTapLocalNotification(payload!);
} else {
await notificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: onTapLocalNotification,
onDidReceiveBackgroundNotificationResponse: onTapLocalNotification,
);
}
}

我希望这将对你有所帮助,以防你仍然面临这个问题。

当应用程序处于终止状态时,您可以使用flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails()从通知中获取有效负载。

最新更新