Flutter - onLaunch 中的 Firebase 云消息导航不起作用

Posted

技术标签:

【中文标题】Flutter - onLaunch 中的 Firebase 云消息导航不起作用【英文标题】:Flutter - Firebase Cloud Messaging Navigation in onLaunch doesn't work 【发布时间】:2021-06-04 22:56:35 【问题描述】:

我正在构建一个使用 FCM 接收推送通知的应用。

我想在点击通知时路由到特定屏幕(例如,用户的个人资料)。

android 上,当应用程序刚刚关闭(而不是“终止”)时,它可以正常工作,但当应用程序终止(“终止”)时,它就无法正常工作。 在 ios 上,它根本不起作用。

我正在实现它:

NotificationsHandler

class NotificationsHandler 
  static final NotificationsHandler instance = NotificationsHandler();

  final _fcm = FirebaseMessaging();

  void onBackgroundNotificationRecevied(Function onReceived) 
    _fcm.configure(
      onResume: (message) => onReceived(message),
      onLaunch: (message) => onReceived(message),
    );
  

myMainScreen 的 initState

@override
  void initState() 
    NotificationsHandler.instance.onBackgroundNotificationRecevied(
      onReceived: (message) async 
        final userId = message['data']['userId'];
        final user = this.users.firstWhere((currentUser) => currentUser.id == userId);

        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => UserProfileScreen(
              user,
            ),
          ),
        );
      
    );
    super.initState();
  

发送通知的代码(通过外部 React 管理面板)

const payload = 
    notification: 
        title: `myTitle`,
        body: `My message`,
        sound: "default",
        badge: "1",
        click_action: "FLUTTER_NOTIFICATION_CLICK",
    ,
    data: 
        click_action: 'FLUTTER_NOTIFICATION_CLICK',
        userId: myUserId,
    ,
;
    
const options = 
    priority: 'high',
    timeToLive: 60 * 60 * 24
;

admin.messaging().sendToTopic('myTopic', payload, options);

有谁知道为什么它不起作用?

谢谢!

【问题讨论】:

你能显示NotificationHandler类的代码吗? @Andrej 我已将其添加到我的问题中 能否也显示发送通知的代码? @Andrej 是的,我现在确实将它添加到我的问题中。请注意,通知是通过外部 React 管理面板发送的,而不是通过 Flutter 应用程序 在您的 _fcm.configure() 方法中,您是否错过了“onBackgroundMessage”参数? -> onBackgroundMessage: yourBackgroundMessageHandler ,其中“yourBackgroundMessageHandler”应该是您的***函数?说到 iOS,您是否创建了 APNS 证书并与您的 GoogleServiceInfo.plist 文件正确链接? 【参考方案1】:

您可以尝试使用getInitialMessage 而不是onLaunch。我相信这会做你想要的,因为documentation 指出了以下几行:

这应该用于确定特定通知交互是否应以特定目的打开应用程序(例如打开聊天消息、特定屏幕等)。

@override
void initState() 
  super.initState();
  FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) 
    if (message != null) 
      Navigator.pushNamed(context, '/message', arguments: MessageArguments(message, true));
    
  );

【讨论】:

getInitialMessage 只能在最新版本的 firebase 中访问。不幸的是,我使用的是以前的版本 我明白了。由于我无法检查您的其余代码,我只能推测发现问题。您在注册处理程序之前是否调用了 requestNotificationPermissions?【参考方案2】:

我假设你正在使用firebase_messaging 包。

iOS

如果您在模拟器上对其进行测试,它将无法正常工作。文档中说:

通过 APN 的 FCM 不适用于 iOS 模拟器。要接收消息和通知,需要使用真实设备。

安卓

在 Android 上,如果用户从设备设置中强制退出应用,则必须再次手动重新打开应用才能开始工作。

更多信息here.

【讨论】:

感谢您的回答。我正在通过 TestFlight 使用真实设备测试我的 iOS 应用程序,但它不起作用。关于 Android 版本 - 我尝试实现,当用户单击通知时,它将再次启动,但会显示通知的正确屏幕,而不是应用程序的主屏幕 @F.SO7 你在 iOS 上请求权限吗? 是的,我确实在 Android 和 iOS 上都收到了完全正常的通知。但是当用户点击通知时,它会打开主屏幕而不是我尝试打开的屏幕(例如用户的个人资料) 哦,我明白了。那么问题实际上出在您注册通知处理程序的时间。您正在 MainScreen 中注册它 - 为时已晚,因为此时通知已经处理完毕。您应该尽快注册处理程序,例如在主函数中。 但在主功能中我无法导航到特定屏幕。如何导航到主功能上的相关屏幕【参考方案3】:

根据我的经验,我记得 onLaunch 回调函数会在执行 main 函数之后立即触发,甚至在 initstate 方法之前。

我所做的是在 runApp() 之前的 main 函数中使用服务定位器(例如 get_it)定位服务类,然后 onLaunch 回调设置初始配置,以便您的应用可以使用它的值。

例如

final getIt = GetIt.instance;

Future<void> main() async 
    WidgetsFlutterBinding.ensureInitialized();
    await Firebase.initializeApp();
    getIt.registerSingleton<Configurator>(Configurator());///start configuration service
    FirebaseMessagingService.initialise()///start firebase messaging service
    runApp();


...

class FirebaseMessagingService 
  final FirebaseMessaging _fcm;

  FirebaseMessagingService.initialise() : _fcm = FirebaseMessaging() 
    if (Platform.isIOS) 
      _fcm.requestNotificationPermissions(IosNotificationSettings());
    

    _fcm.configure(
      ...
      onLaunch: _launchMessageHandler,
    );
  


//top-level function or static method
_launchMessageHandler(Map<String, dynamic> message) async 
  //some parsing logic
  ...
  getIt<Configurator>().setInitialConfig(parsed_data);



...

//then

void initState() 
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) 
      final config = getIt<Configurator>().config;
      //do something
    ;

你将不得不实现这些全部设置,但它的流程大致如上。

【讨论】:

有没有办法不使用get_it来实现它?我正在使用提供者 通常提供者使用上下文来访问实例。如果您使用的是 Riverpod,这是可能的。 您能否解释一下使用 Provider 实现它的更多信息? ***.com/questions/12649573/… 这是在 dart 中制作单例实例的方法。如果您在初始化 App 之前创建配置提供程序实例,您可以访问它的实例。但我从来没有这样尝试过。 我无法理解它与问题的关系【参考方案4】:

我认为您的麻烦更多在于单击通知后导航到另一个屏幕。

如果是这种情况,请创建一个路由类。

一个例子如下:

class Navigator
  GlobalKey<NavigatorState> _navigator;

  /// Singleton getter
  static Navigator get instance => _instance ??= Navigator._();

  /// Singleton Holder
  static Navigator _instance;

  /// Private Constructor
  Navigator._() 
    _navigator = GlobalKey<NavigatorState>();
  

  GlobalKey<NavigatorState> get navigatorKey => _navigator;

  Future<dynamic> navigateTo(String routeName, [dynamic arguments]) =>
      navigatorKey.currentState.pushNamed(routeName, arguments: arguments);

现在是屏幕/页面

class CustomRoutes 
  const CustomRoutes._();

  factory CustomRoutes() => CustomRoutes._();

  static const String HomeRoute = 'HomeRoute';
    ...
    ...

  static Route<dynamic> generateRoute(RouteSettings settings) 
    switch (settings.name) 
      case CustomRoutes.HomeRoute:
        return MaterialPageRoute(builder: (_) => HomePage());
      default:
        return MaterialPageRoute(
            builder: (_) => Scaffold(
                body: Center(child: Text('No path for $settings.name'))));
    
  

所以如果你想去主页你可以调用

await Navigator.instance.navigateTo(CustomRoutes.HomeRoute, someArguments)

记得将 globalkey 注册到你的 materialapp

MaterialApp(
...
...
navigatorKey: Navigator.instance.navigatorKey
...);

【讨论】:

以上是关于Flutter - onLaunch 中的 Firebase 云消息导航不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Firebase_messaging onResume 和 onLaunch 回调不会在 Flutter 中调用

Flutter Firebase 消息触发 onLaunch

Flutter 和 FCM(Firebase 云消息传递)onMessage、onResume 和 onLaunch 在单击通知时未触发(包:firebase_messaging 7.0.0)

带有 WebView 的 Flutter 应用中的 Firebase 身份验证

如何使用 Flutter 在 Firestore 中删除集合中的所有文档

Xamarin.Forms.Forms.Init(e) Onlaunched 中的 FileNotFoundExeception