Shaitan
Shaitan

Reputation: 65

Navigate from notification via beamer

I want to navigate to a specific page via beamer from a notification click.

In my main.dart I initialze my app and fcm. The class 'PushNotificationReceiver' should handle the notification logic.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await PushNotificationReceiver.instance.initialize();
  runApp(MultiProvider(providers: [
    // Some of my providers
  ], builder: (context, _) => MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {

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

    PushNotificationReceiver.instance.registerNotifications((route) => {
      context.beamToNamed(route)
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(builder: (context, themeProvider, child) {
      return MaterialApp.router(
        routeInformationParser: BeamerParser(),
        routerDelegate: _beamerDelegate,
        backButtonDispatcher: BeamerBackButtonDispatcher(delegate: _beamerDelegate),
      );
    }
  }
}

I implemented the functions to receive and show local notifications but to simplify it I only paste the code for the click (removed null checks as well).

class PushNotificationReceiver {
  static PushNotificationReceiver _instance;
  void Function(String route) navigateFunction;

  static PushNotificationReceiver get instance {
    if (_instance == null) {
      _instance = new PushNotificationReceiver();
    }

    return _instance;
  }

  Future<void> initialize() async {
    await Firebase.initializeApp();
  }
  
  void registerNotifications(void Function(String route) navigateFunction) {
    this.navigateFunction = navigateFunction;

    // Called the other functions to receive notifications, but excluded them for simplicity.

    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      this.navigateFunction("/MyPage/${message.data["id"]}");
    });
  }
}

When I click on the notification I get the following error:

[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: 'package:beamer/src/beamer.dart': Failed assertion: line 40 pos 14: 'BeamerProvider.of(context) != null': There was no Router nor BeamerProvider in current context. If using MaterialApp.builder, wrap the MaterialApp.router in BeamerProvider to which you pass the same routerDelegate as to MaterialApp.router.

I tried it first without a function that I pass in and a GlobalKey in the main.dart with the same result. Any suggestions?

Upvotes: 0

Views: 807

Answers (1)

Shaitan
Shaitan

Reputation: 65

Found the solution. My first approach of a global key works if I wrap my MaterialApp.router in a Beamerprovider (like the error message suggested).

final GlobalKey myGlobalKey = GlobalKey();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await PushNotificationReceiver.instance.initialize();
  runApp(MultiProvider(providers: [
    // Some of my providers
  ], builder: (context, _) => MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();

    PushNotificationReceiver.instance.registerNotifications();
  }
  
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(builder: (context, themeProvider, child) {
      return BeamerProvider(
        key: myGlobalKey,
        routerDelegate: _beamerDelegate,
        child: MaterialApp.router(
          routeInformationParser: BeamerParser(),
          routerDelegate: _beamerDelegate,
          backButtonDispatcher: BeamerBackButtonDispatcher(
            delegate: _beamerDelegate
          )
        )
      );
    }
  }
}

That leads to my push notification receiver:

class PushNotificationReceiver {
  static PushNotificationReceiver _instance;

  static PushNotificationReceiver get instance {
    if (_instance == null) {
      _instance = new PushNotificationReceiver();
    }

    return _instance;
  }

  Future<void> initialize() async {
    await Firebase.initializeApp();
  }
  
  void registerNotifications(void Function() {
    // Called the other functions to receive notifications, but excluded them for simplicity.

    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      myGlobalKey.currentContext.beamToNamed("/MyPage/${message.data["id"]}");
    });
  }
}

I hope this will help some others too.

Upvotes: 1

Related Questions