I am struggling to understand how to navigate from a Push Notification class on selecting a notification in flutter. I need access to the BuildContext or somehow figure out a way to tell my app to navigate without this.
My code looks like below:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await PushNotificationService().setupInteractedMessage();
runApp(const MyApp());
}
Future awaitDeepLink() async {
StreamSubscription _sub;
try {
await getInitialLink();
_sub = uriLinkStream.listen((Uri uri) {
runApp(MyApp(uri: uri));
}, one rror: (err) {
});
} on PlatformException {
print("PlatformException");
} on Exception {
print('Exception thrown');
}
}
class MyApp extends StatelessWidget {
final Uri uri;
static final FirebaseAnalytics analytics = FirebaseAnalytics.instance;
const MyApp({Key key, this.uri}) : super(key: key);
@override
Widget build(BuildContext context) {
return OverlaySupport(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus.unfocus();
}
},
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: buildThemeData(),
home: CheckAuth(uri: uri),
),
),
);
}
}
PushNotificationService.dart
class PushNotificationService {
Future<void> setupInteractedMessage() async {
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
String token = await FirebaseMessaging.instance.getToken();
var storage = const FlutterSecureStorage();
storage.write(key: "fcm_token", value: token);
if (initialMessage != null) {
print(initialMessage.data['type']);
}
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("message opened app:" message.toString());
});
await enableIOSNotifications();
await registerNotificationListeners();
}
registerNotificationListeners() async {
AndroidNotificationChannel channel = androidNotificationChannel();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
var androidSettings =
const AndroidInitializationSettings('@mipmap/ic_launcher');
var iOSSettings = const IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
var initSettings = InitializationSettings(
android: androidSettings,
iOS: iOSSettings,
);
flutterLocalNotificationsPlugin.initialize(
initSettings,
onSelectNotification: onSelectNotification,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
icon: android.smallIcon,
playSound: true,
),
),
payload: json.encode(message.data),
);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print("onMessageOpenedApp: $message");
if (message.data != null) {
print(message.data);
}
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}
Future onSelectNotification(String payload) async {
Map data = json.decode(payload);
if (data['type'] == 'message') {
// NEED TO ACCESS CONTEXT HERE
// Navigator.push(
// navigatorKey.currentState.context,
// CupertinoPageRoute(
// builder: (navigatorKey.currentState.context) => MessagesScreen(
// conversationId: data['conversation_id'],
// userId: data['user_id'],
// name: data['name'],
// avatar: data['avatar'],
// projectName: data['project_name'],
// projectId: data['project_id'],
// plus: data['plus'],
// ),
// ),
// );
}
}
Future<void> _firebaseMessagingBackgroundHandler(
RemoteMessage message) async {
print("onBackgroundMessage: $message");
}
enableIOSNotifications() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
androidNotificationChannel() => const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.max,
);
}
As you can see in the onSelectNotification() function I am trying to navigate but do not know how.
I am quite new to dart/flutter so any guidance would be appreciated.
CodePudding user response:
//You can set a global key for your navigation:
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// Pass it to MaterialApp:
new MaterialApp(
title: 'MyApp',
onGenerateRoute: generateRoute,
navigatorKey: navigatorKey,
);
// Push routes:
navigatorKey.currentState.pushNamed('/someRoute');
CodePudding user response:
I need access to the BuildContext
Yes you need context
to navigate. In flutter its best practice to have navigation code in the widgets. and you have your context
From a tweet thread by Andrea Bizzotto
RULE: Navigation code belongs to the widgets
If you try to put your navigation code in the business logic, you'll have a hard time because you need a BuildContext to do so.
Solution:
- emit a new widget state
- listen to the state in the widget and perform the navigation there
CodePudding user response:
create a stream
StreamController<Map<String, dynamic>> streamController = StreamController<Map<String, dynamic>>();
then use it here
Future onSelectNotification(String payload) async {
Map data = json.decode(payload);
_streamController.add(data)
}
}
and then you can listen to the stream on the home page under your MaterialApp widget
@override
void initState() {
streamController.stream.listen((event) {
if (data['type'] == 'message') {
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => MessagesScreen(
conversationId: data['conversation_id'],
userId: data['user_id'],
name: data['name'],
avatar: data['avatar'],
projectName: data['project_name'],
projectId: data['project_id'],
plus: data['plus'],
),
),
);
}
});
super.initState();
}