flutter firebase onclick redirection when app is open - flutter

in my app firebase push notification is implemented.
on click event works when app is terminated.
but how to achieve notification on click of redirection when app is open.
class _Application extends State<Application> {
// It is assumed that all messages contain a data field with the key 'type'
Future<void> setupInteractedMessage() async {
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage != null) {
_handleMessage(initialMessage);
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _handleMessage(RemoteMessage message) {
if (message.data['type'] == 'chat') {
Navigator.pushNamed(context, '/chat',
arguments: ChatArguments(message),
);
}
}
#override
void initState() {
super.initState();
// Run code required to handle interacted messages in an async function
// as initState() must not be async
setupInteractedMessage();
}

Related

Flutter Firebase messaging: sending a user to a specific screen

Im trying to work with firebase messaging on flutter, and here's the situation. I have push notification implemented simply with the following:
void main() async {
WidgetsFlutterBinding();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// await _configureFirebaseAuth();
// await _configureFirebaseStorage();
// _configureFirebaseFirestore();
runApp(const MyApp());
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print("Handling a background message: ${message.messageId}");
}
This allows the push notifications to appear, but there is no real functionality to it. In my case, i would like to call navigator and push a certain route. Since this requires context, I placed the following method in my home page(the first screen actually built in the app):
#override
void initState() {
// TODO: implement initState
handleMessageOnBackground();
super.initState();
}
void handleMessageOnBackground() {
FirebaseMessaging.instance.getInitialMessage().then(
(remoteMessage) {
if (remoteMessage != null) {
print('Message: ${remoteMessage.data}');
RemoteMessage? message = remoteMessage;
}
},
);
}
The idea is that, in the initstate method, i now have context, so I would be able to Navigate to a different page. While this works(to my understanding) when the app is completely closed, it will not cover the cases when remote notifications are caught by the .onMessage or the .onBackgroundMessage. Is there any way to pass NotificationMessages from the top of my app down into the main page to use for navigation?
Thank you!
If you want to navigate without context use a GlobalKey.
Define a Globalkey //not inside any class
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
and inside your MaterialAppWidget()
MaterialApp(
navigatorKey: navigatorKey,
...
);
From firebase you'll receive some data in _firebaseMessagingBackgroundHandler(){}
based on that data you can navigate to any screen.
//if you are creating a notification using that data then put required data in payload of that notification. so you can receive that payload when you tap on that notification that will help you to navigate to a specific screen.
so navigate without context like this.
navigatorKey.currentState
?.pushNamed(AnotherScreen.routeName);
if you want to pass arguments
navigatorKey.currentState
?.pushNamed(IOSNotificationIntentScreen.routeName, arguments: {
"arg1": "hello arg 1",
"arg2": "hello arg 2",
});

The method 'onSelectNotifications' isn't defined using flutter local notification plugin

in flutter_local_notification 12.0.2
The onSelectNotification parameter is not anymore.
So what is the alternative of this. So that we can handle callback when we click on notification.
you can stream the notification
import 'package:rxdart/rxdart.dart';
...
// use this
class MyNotifManager {
static final onNotifications = BehaviorSubject<String?>();
...
// then add the payload to your local notification
// exampel for the foreground notif
onDidReceiveNotificationResponse: (payload) async {
onNotifications.add(payload.payload); // add payload to the stream
},
then to handle the callback:
Future<void> listenNotification() async =>
MyNotifManager.onNotifications.stream.listen(onClickNotification);
and for your action after click
void onClickNotification(String? payload) {
Navigator.push();
}
call the stream on your initState
#override
void initState() {
super.initState();
MyNotifManager.init();
listenNotification();
}
with this method, you will able to handle calback when click on notification.
It has onDidReceiveNotificationResponse callback when plugin initialize.
_plugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (details) {
// Click Notification Event Here
},
);
If you click notification when app is terminated,
_plugin.getNotificationAppLaunchDetails().then((value) {
// Click Notification Event Here
});

Flutter audio_service media resume

I have custom queuing logic using MediaItem which works properly when the UI is active. I am stopping the audio playback using onTaskRemoved method.
#override
Future<void> onTaskRemoved() async {
//if (!AudioServiceBackground.state.playing) {
logger.v("Task Removed");
await stop();
//}
}
#override
Future<void> stop() async {
await _player.stop();
await playbackState.firstWhere(
(state) => state.processingState == AudioProcessingState.idle);
}
However after swiping the task, notification is still visible and when I click the notification to resume nothing happens and app is stuck in splash screen.

How to handle redirects from initState in Flutter

I am using the plugin flutter_local_notifications to show a user notifications on the app. I have managed to show the notifications on the app and the user can click on the notifications, the user will be redirected to see all pending items from the notification in a notification page. I have set the function to detect the onclick on initstate. The whole function and method to show notification I have implemented it on the homescreen.
#override
void initState() {
super.initState();
initPlatformState();
getNotifications();
NotificationApi.init(initScheduled: true);
init();
_configureSelectNotificationSubject(); //function to redirect to Notifications page
}
which goes to
void _configureSelectNotificationSubject() {
print("clicked is the notification");
NotificationApi.onNotifications.stream.listen((String? payload) async {
await Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => WANotifications(current: current)),
(Route<dynamic> route) =>
true);
});
}
The challenge am facing with this implementation is that when a user clicks to go to the home screen , the user gets redirected automatically to the notifications page from the home screen without his/her consent. The redirect should only occur when they click on the notifications.
How can I set the redirect to only occur when the user clicks the notification only and not when they click to go to home screen
You can achieve this with the help of didNotificationLaunchApp.
bool get didNotificationLaunchApp =>
notificationAppLaunchDetails?.didNotificationLaunchApp ?? false;
// Use here,
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
selectedNotificationPayload = notificationAppLaunchDetails!.payload;
initialRoute = SecondPage.routeName;
}
Pl check full example here : https://pub.dev/packages/flutter_local_notifications/example
For non main file :
#override
void initState() {
super.initState();
localNotification(); // call below localNotification() here.
}
localNotification() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin!.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
// redirect to new screen if true.
}
}

Flutter Riverpod: Refresh Page Offscreen using State Notifier

I'm using StateNotifier and Riverpod.
I have a notification page, which contains a list of notification. When a notification arrives, I trigger a refresh for notification. However, when I navigate to notification page, it still using the old (cached?) list.
How do I refresh a page offscreen?
Foreground Message
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
_localNotification.showLocalNotification(message);
ProviderContainer().read(notificationProvider).getNotification();
});
Background Message
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
final LocalNotification localNotification = LocalNotification();
await localNotification.init();
localNotification.showLocalNotification(message);
ProviderContainer().read(notificationProvider).getNotification();
}
NotificationProvider
Future<void> getNotification() async {
try {
state = const NotificationLoadingState();
_notificationList = await _notificationRepository.getNotification();
state = NotificationLoadedState(_notificationList); // ==> I get a new list here
} catch (e, s) {
state = const NotificationErrorState('error fetching notification');
}
}
UI
final state = watch(notificationProvider.state);
if (state is NotificationLoadingState) {
return _buildLoading();
} else if (state is NotificationLoadedState) {
return _buildLoaded(state.notificationList); // ==> I still get the old list here
} else if (state is NotificationErrorState) {
return _buildError(state.message);
}
Edit:
I managed to solve the foreground message handler by using navigatorKey.currentContext.
However, I still haven't solved background message handler.
I've tried changing my main.dart to use UncontrolledProviderScope with a global ProviderContainer, which then was called from background message handler. It's still not refreshing.
With this line you are creating a new instance for your providers :
ProviderContainer().read(notificationProvider).getNotification();
you need to use a context to get the existing instance of ProviderContainer:
context.read(notificationProvider).getNotification();
or if you are not inside ui make dependencies between your providers