在 Flutter 中初始化通知的正确位置

Tho*_*mas 6 push-notification google-cloud-messaging flutter

我目前正在努力让通知按照我希望的方式在 Flutter 上运行。我目前的解决方案是有一个动态的 LandingPage,它 - 取决于 FirebaseAuth - 重定向到登录或主屏幕。

MaterialApp(
   theme: ThemeData(
   ...
   home: Scaffold(body: Builder(builder: (context) => LandingPage()))
),
Run Code Online (Sandbox Code Playgroud)

在 LandingPage 中,我将在我的 Singleton 中调用一个函数来为我设置通知。如您所见,我在这里传递上下文。这是因为我想从通知的onMessage回调中显示 Snackbar 。

class LandingPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    FirebaseUser user = Provider.of<FirebaseUser>(context);
    if (user != null) {
      Singleton().setupMessaging(user.uid, context); //This is the line
      return MainPage(userId: user.uid);
    } else {
      while(Navigator.canPop(context)){
        Navigator.pop(context);
      }
      return LoginPage();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在努力实现,一旦用户登录,就让消息传递系统运行。如果当前令牌未定义,我只设置回调。

我现在遇到的问题是,所说的上下文不是应用程序范围的,这意味着,一旦我导航到具有自己的上下文的新 Widget,就无法再显示 Snackbar。现在我不确定这是否是初始化消息传递的正确位置,因为没有应用程序范围的上下文。

setupMessaging(String uid) async{
   if((await SharedPreferences.getInstance()).getBool('bNotifications') ?? true){
     print("bNotifications disabled");
     return;
   }

   _firebaseMessaging.getToken().then((token) {
     if (_lastToken != token) {
       if (_lastToken == null) {
         if (Platform.isIOS) iOSPermission();
         _firebaseMessaging.configure(
           onMessage: (Map<String, dynamic> message) async {
             print('onMessage $message');
             Scaffold.of(context).showSnackBar(...); //Here I need the context
           },
           onResume: (Map<String, dynamic> message) async {
             print('onResume $message');
           },
           onLaunch: (Map<String, dynamic> message) async {
             print('onLaunch $message');
           },
         );
       }
       _lastToken = token;
     }
   });
}
Run Code Online (Sandbox Code Playgroud)

我还考虑在 onMessage-callback 中显示本地通知,但本地通知和 firebase-messaging 在 iOS 上不能一起工作。

我听说的最后一个选项是使用 GlobalKey,我需要通过我的所有页面。我听说这种方法也很慢。

Ovi*_*diu 2

不存在应用程序范围的东西Context,但您可以为Scaffold您的Snackbars.

初始化一个GlobalKey可以静态访问的。必须在构建任何路线之前对其进行初始化,例如。在您的应用程序的main()函数中,或者在返回以下内容的小部件的状态中MaterialApp

static final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
Run Code Online (Sandbox Code Playgroud)

添加一个构建器,用MaterialApp以下内容包装每个页面Scaffold

builder: (BuildContext context, Widget child) {
  return Scaffold(
    key: scaffoldKey,
    body: child,
  );
}
Run Code Online (Sandbox Code Playgroud)

现在您不再需要特定于页面的内容,Context因为您可以使用顶级Scaffold来显示Snackbars

MyAppState.scaffoldKey.currentState.showSnackBar(...)
Run Code Online (Sandbox Code Playgroud)