在 Flutter 上单击背景通知时如何导航?

Posted

技术标签:

【中文标题】在 Flutter 上单击背景通知时如何导航?【英文标题】:how to navigate when click background notification on Flutter? 【发布时间】:2020-06-20 16:11:41 【问题描述】:

点击背景 FCM通知时是否可以导航到指定路径?

我创建了一个 Top-Level 函数并将其添加到导航器路径,但它不起作用,当单击背景通知时,它只是打开应用程序

我猜我发现了一个问题

现在,我将fcm 配置从home page 更改为splash screen。 前景没有导航到页面,我认为这是因为启动画面不再可用。当我点击通知消息时,它只是打开了应用程序。

FCM 配置

onBackgroundMessage: backgroundMessageHandler

***函数

Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) 
  if (message.containsKey('data')) 
    getIt<NavigationService>().navigateTo('/$message['data']['screen']');
  

有效载荷

const payload: admin.messaging.MessagingPayload = 
                notification:
                    title: `New Enquiry`,
                    body:`$customerName published to $subName`,
                    badge: '1',
                    sound: 'default'
                ,
                data: 
                    click_action: `FLUTTER_NOTIFICATION_CLICK`,
                    sound: `default`,
                    status: `chat`,
                    screen: `homePage`
                  
            

ma​​in.dart

GetIt getIt = GetIt.instance;

void main() 
  setupLocator();
    runApp(MyApp());

MaterialApp

 return MaterialApp(
      navigatorKey: NavigationService().navigatorKey,
      onGenerateRoute: Router.generateRoute,
    );

NavigationServicesetupLocator

class NavigationService 
  final GlobalKey<NavigatorState> navigatorKey =
      new GlobalKey<NavigatorState>();

  Future<dynamic> navigateTo(String routeName) 
    return navigatorKey.currentState.pushNamed(routeName);
  


void setupLocator() 
  getIt.registerLazySingleton(() => NavigationService());

【问题讨论】:

通知负载是否包含click_action 字段? @HasilT 是的,我将有效负载添加到此处 我也有同样的问题,还没找到解决办法 您找到解决方案了吗?我也面临同样的问题。 【参考方案1】:

您可以使用此功能在应用被终止时导航并在后台接收通知

  FirebaseMessaging.instance
        .getInitialMessage()
        .then((RemoteMessage message) 
      print("FirebaseMessaging.getInitialMessage");
      if (message != null) 

        Navigator.of(context).pushNamed('/call');
      
    );

此函数仅在应用打开并获取最后一条消息时运行一次。

您可以在此文档中阅读更多内容:https://github.com/FirebaseExtended/flutterfire/blob/62e09975f9b3d14141585e62ddab6b98e667b7cf/docs/messaging/notifications.mdx

【讨论】:

我的问题是如何在 BACKGROUND MODE 下导航 getInitialMessage() 将在应用程序通过终止状态的通知打开时触发。它可用于通过在通知中传递数据来导航到某个页面【参考方案2】:

要处理来自后台状态的通知,您可以使用 FirebaseMessaging 库公开的流。

FirebaseMessaging.onMessageOpenedApp.listen((remoteMessage) 
  // Handle navigation or perform any logic here
);

【讨论】:

OP 要求一种在背景模式下处理推送通知的方法,因此答案是正确的。您的答案使用一种方法来处理来自 TERMINATED 状态的推送通知,该方法有效,但这不是 OP 想要的。您应该更仔细地阅读问题和 cmets【参考方案3】:

我希望你已经配置了 firebase_messaging 指定的 here 所需的本机端声明

根据您提供的有效负载:

有效载荷

const payload: admin.messaging.MessagingPayload = 
                notification:
                    title: `New Enquiry`,
                    body:`$customerName published to $subName`,
                    badge: '1',
                    sound: 'default'
                ,
                data: 
                    click_action: `FLUTTER_NOTIFICATION_CLICK`,
                    sound: `default`,
                    status: `chat`,
                    screen: `homePage`
                  
            

让你的 onResume 像这样,onLaunch 也一样

onResume

onResume: (Map<String, dynamic> message) 
  if(SharedClassID.toString().contains(message['data']['classID']))
  
   
    Navigator.push(context, MaterialPageRoute(builder: (context)=>BroadcastNotification()));
    print("found");
  
  else if(SharedClassID.toString().contains(message['data']['classID']))
  
 
    Navigator.push(context, MaterialPageRoute(builder: (context)=>StudentHomework()));
    print("found");
  

  else
    
      print("not found");
    


  //print(message['data']['classID']+" onResume");
  print('onResume: $message');
  return;

我可以找出它不起作用的原因,因为在有效负载中,键是 screen:'homePage' 并且我可以注意到您没有传递 classID所以发生的事情是它无法评估您添加的 if else 条件。

你更新 if/else 条件如下:

if(message['data']['screen'] == 'homePage')
  
    //TODO: route
  
  else if(message['data']['screen'] == 'homeWorkPage')
    //TODO: route
  

如果您想基于 SharedClassId 进行路由,则在有效负载和路由中传递 classId。 例如sn-p:

if(message['data']['classId'] == SharedClassId)
  
    //TODO: route
  
  else if(message['data']['classId'] == SharedClassId)
    //TODO: route
  

【讨论】:

【参考方案4】:

在该示例中,我使用共享首选项数据(如类 ID)来检查通知数据是否包含此类 ID,然后它可以导航到特定屏幕

void registerNotification() 
_firebaseMessaging.requestNotificationPermissions(
  const iosNotificationSettings(sound: true, badge: true, alert: true),
);

_firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) 
  print('onMessage: $message');
 // print(message['data']['classID']+" onMessage");
  if(SharedClassID.toString().contains(message['data']['classID']))
  
   
    Navigator.push(context, MaterialPageRoute(builder: 
 (context)=>BroadcastNotification()));
    print("found");
  
  
  else if(SharedClassID.toString().contains(message['data']['classID']) )
  
   
    Navigator.push(context, MaterialPageRoute(builder: (context)=>MuseGalaryNew()));
    print("found");
  
  else
  
    print("not found");
  

  return;
, onResume: (Map<String, dynamic> message) 
  if(SharedClassID.toString().contains(message['data']['classID']))
  
   
    Navigator.push(context, MaterialPageRoute(builder: (context)=>BroadcastNotification()));
    print("found");
  
  else if(SharedClassID.toString().contains(message['data']['classID']))
  
 
    Navigator.push(context, MaterialPageRoute(builder: (context)=>StudentHomework()));
    print("found");
  

  else
    
      print("not found");
    


  //print(message['data']['classID']+" onResume");
  print('onResume: $message');
  return;
, onLaunch: (Map<String, dynamic> message) 
  if(SharedClassID.toString().contains(message['data']['classID'])  )
  
            Navigator.push(context, MaterialPageRoute(builder: (context)=>BroadcastNotification()));
    print("found");
  
  else if(SharedClassID.toString().contains(message['data']['classID']))
  
          Navigator.push(context, MaterialPageRoute(builder: (context)=>StudentHomework()));
    print("found");
  

  else
  
    print("not found");
  
  return;
);


【讨论】:

不管你要打开哪个屏幕,只要知道应用程序完全关闭时如何通过导航器打开屏幕,谢谢 您需要使用 _firebaseMessaging.subscribeToTopic("Your topic name") 订阅事件..在应用关闭时收到通知后,当您单击通知时它将重定向到该特定页面跨度> 【参考方案5】:

截至目前 2021 年 8 月的最新代码。 首先,您的项目 dart 版本和 firebase 插件版本是集成 firebase 通知的重要内容。如果您使用的是较低版本,那么您可能会遇到一些问题。对于我的颤振项目,我使用的是最新的 null 安全 Firebase 消息插件。如果您使用 Flutter 消息传递 10.0.4 或更高版本,则无需在 android manifest 文件中添加任何元数据。你可以看到complete code here。

  firebase_messaging: ^10.0.4
  firebase_core: ^1.4.0
  flutter_local_notifications: ^8.1.1

如果 Flutter 应用程序关闭,则将调用以下代码。它只会被调用一次,您应该在 firebase 控制台云消息传递窗口中提供 click_action 作为“FLUTTER_NOTIFICATION_CLICK”作为自定义数据。

  // when app is closed and it will be called only once
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) 
 print("fireabse closed app msg");

  if (message != null) 
    print( " firebase msg received closed add "+message.data.toString());
    Navigator.push(context, MaterialPageRoute(builder: (context) return product(prodid: message.data["prodid"]);));

    /*  Navigator.pushNamed(context, '/message',
        arguments: MessageArguments(message, true));
  */

  
);

要在状态栏上显示通知图标,请使用以下代码。

FirebaseMessaging.onMessage.listen((RemoteMessage message) 
      RemoteNotification? notification = message.notification;
      AndroidNotification? android = message.notification?.android;
      print(" firebase msg - "+message.data.length.toString());
      if (notification != null && android != null) 
        print("firebase msg body "+ notification.body.toString());
        flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            NotificationDetails(
              android: AndroidNotificationDetails(
                channel.id,
                channel.name,
                channel.description,
                // TODO add a proper drawable resource to android, for now using
                //      one that already exists in example app.
                icon: 'noti_icon',
                color: Colors.red

              ),
            ));


      
    );

【讨论】:

以上是关于在 Flutter 上单击背景通知时如何导航?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Flutter 中的通知导航到应用程序中的特定 MaterialPageRoute

Flutter单击后退按钮时如何执行

Flutter MaterialPageRoute 导航到黑色背景的屏幕时如何解决?

Flutter - 从 FCM 收到通知时自动运行应用程序(无需单击它)

Flutter:当应用程序处于后台但未在 iOS 中终止时,无法在通知单击时重定向到特定屏幕

单击通知行为仅在应用程序在后台运行时才有效?