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