【问题标题】:Flutter: local notification plugin, navigate to specific screen when the user tap the notificationFlutter:本地通知插件,当用户点击通知时导航到特定屏幕
【发布时间】:2019-01-10 21:50:52
【问题描述】:

我正在使用本地通知插件,一切正常,除了当我点击通知时。我想在用户点击通知时导航到特定屏幕

Future onSelectNotification(String payload) async {
    //convert payload json to notification model object
    try{
    Map notificationModelMap = jsonDecode(payload);
    NotificationModel model = NotificationModel.fromJson(notificationModelMap);

    await Navigator.push(
        context,// it`s null!
        new MaterialPageRoute(
            builder: (context) => CommitmentPage(model)));}
            catch(e){print(e.toString());}
  }

但上下文始终为空并给我一个例外 NoSuchMethodError: The method 'ancestorStateOfType' was called on null.

编辑

我尝试按照@Günter Zöchbauer 的建议使用 navigatorKey 并将其传递给材料应用程序,但它给了我另一个例外

Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget

ma​​in.dart

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

static final navigatorKey = new GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      navigatorKey:navigatorKey ,
      title: 'notification',
      theme: ThemeData(
        primarySwatch: Colors.purple,
      ),
      home: new RootPage(auth: new Auth(),),
    );
  }

}

提醒页面

   class ReminderPage extends StatefulWidget {

    @override
      _ReminderPageState createState() => _ReminderPageState();

    }

class _ReminderPageState extends State<ReminderPage> {
  final flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
....

 @override
  void initState() {
    super.initState();

    _initLocalNotification();
....

  }


// this method is called when u tap on the notification
 Future onSelectNotification(String payload) async {

    //convert payload json to notification model object
    Map notificationModelMap = jsonDecode(payload);
    NotificationModel model = NotificationModel.fromJson(notificationModelMap);

    try{
   await Navigator.push(
        MyApp.navigatorKey.currentState.context,
        new MaterialPageRoute(
            builder: (context) => CommitmentPage(model)));}
            catch(e){print(e.toString());}


  }

}

编辑 2 而不是使用

 await Navigator.push(
            MyApp.navigatorKey.currentState.context,
            new MaterialPageRoute(
                builder: (context) => CommitmentPage(model)));}
                catch(e){print(e.toString());}

我用过

await  MyApp.navigatorKey.currentState.push(MaterialPageRoute(builder: (context) => CommitmentPage(model)));

它运行良好,但是当我在终止应用程序后点击通知时,它会将我带到主页而不是所需的主页! 我认为 navigatorKey 还没有初始化!

【问题讨论】:

  • 你能再分享一些代码吗?你怎么称呼你的通知?

标签: dart flutter flutter-layout


【解决方案1】:

1. FMC 有效载荷

{
  "notification": {
    "body": "Hey, someone book your product", 
    "title": "production booking"
  }, 
  "priority" : "high",
  "data": {
    "action" : "BOOKING" //to identify the action
  },
  "to": "deviceFCMId"
}

2。在localnotification.show方法中设置payload数据

showNotification(RemoteMessage message) {
  RemoteNotification notification = message.notification;
  AndroidNotification android = message.notification?.android;
  String action = message.data['action']; // get the value set in action key from FCM Json in Step1
  // local notification to show to users using the created channel.
  if (notification != null && android != null) {
    flutterLocalNotificationsPlugin.show(
        notification.hashCode,
        notification.title,
        notification.body,
        NotificationDetails(
            android: androidNotificationDetails, iOS: iOSNotificationDetails),
        payload: action // set the value of payload
    );
  }
}

3.在 MyApp 类中创建一个 navigatorKey

class _MyAppState extends State<MyApp> {
  final GlobalKey<NavigatorState> navigatorKey =
      GlobalKey(debugLabel: "Main Navigator"); //
}

4.在您的 MaterialApp 上设置 navigatorkey

@override
  Widget build(BuildContext context) {
    //this change the status bar color to white
    return MaterialApp(
          navigatorKey: navigatorKey,
    ....

5.在 initState 上,初始化 localnotificationPlugin 并声明 onSelectNotification 方法

@override
  void initState() {
    super.initState();
    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);
  }

  Future<dynamic> onSelectNotification(payload) async {
  // implement the navigation logic
  }

6.导航逻辑示例

Future<dynamic> onSelectNotification(payload) async {
// navigate to booking screen if the payload equal BOOKING
if(payload == "BOOKING"){
 this.navigatorKey.currentState.pushAndRemoveUntil(
  MaterialPageRoute(builder: (context) => BookingScreen()),
   (Route<dynamic> route) => false,
   );
 }
}

【讨论】:

  • 在5)中,你打算如何使用没有它的上下文?在 initState() 中没有可供 onSelectNotification() 使用的上下文。
【解决方案2】:

navigatorKey 传递给MaterialApp 并使用此密钥获取上下文。此上下文包含一个Navigator,您可以使用它来切换到您想要的任何页面。

https://docs.flutter.io/flutter/material/MaterialApp/navigatorKey.html

【讨论】:

  • 我创建了最终的 navigatorKey = new GlobalKey();并将其传递给材料应用程序,但是当我从另一个 staefull 小部件访问它时,它始终为空。这是访问它的正确方法吗 GlobalKey().currentState.context;
  • 您需要将对键的引用存储在“全局”或静态变量中,以确保您可以在任何地方访问相同的实例。如果它不起作用,请将更新后的代码添加到您的问题中,以便对其进行调查。
  • 尝试await Future.delayed(const Duration(milliseconds: 200), () =&gt; MyApp.navigatorKey.currentState.push(MaterialPageRoute(builder: (context) =&gt; CommitmentPage(model)))); 给应用一些时间来初始化。您可以尝试减少延迟,它甚至可以使用Duration.zero 而不是const Duration(milliseconds: 200)
  • 你在 5 小时后救了我 :)
【解决方案3】:

随着您所做的最新更改,您被带到主页,这更多地与您在应用程序中进一步实例化和初始化插件几个页面的事实有关。考虑到应用程序被杀死,插件也会被杀死。您应该考虑在您的应用程序启动时更接近初始化插件,例如在创建应用程序或创建第一页时左右,具体取决于您想要的行为。在这个问题https://github.com/MaikuB/flutter_local_notifications/issues/99 中,另一个开发人员已经能够更改应用程序被终止时显示的第一页,但这可能与您想要发生的不同。

【讨论】:

  • 是的,这解决了我的问题。你是最棒的(:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
相关资源
最近更新 更多