【问题标题】:Flutter - Firebase Cloud Messaging Navigation in onLaunch doesn't workFlutter - onLaunch 中的 Firebase 云消息导航不起作用
【发布时间】: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 文件正确链接?

标签: firebase flutter dart firebase-cloud-messaging


【解决方案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 实现它的更多信息?
  • stackoverflow.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
...);

【讨论】:

    猜你喜欢
    • 2021-04-18
    • 2020-06-21
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 2018-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多