I have an application, I want to send notifications only to authorized users,
authorization occurs by token if the token is empty, then the user is not authorized, for authorization and storing the token I use the shared_pref package. How can I disable notifications if the user is not logged in?
Token validation is only done in MyAppState notifications I need to disable in the same place
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await Permission.notification.request();
if(Constants.USER_TOKEN.isEmpty) {
FirebaseMessaging.instance.setAutoInitEnabled(false);
}
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
if (navKey.currentState != null) {
if(Constants.USER_TOKEN.isNotEmpty) {
navKey.currentState!.push(MaterialPageRoute(
builder: (context) => NotificationScreen()));
}
print('Message');
}
}
await _messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
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,
channelDescription: channel.description,
icon: '#mipmap/ic_launcher',
),
),
);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) {
print("On message opened app: ${message?.data}}");
if (navKey.currentState != null) {
if(Constants.USER_TOKEN.isNotEmpty) {
navKey.currentState!.push(MaterialPageRoute(
builder: (context) => const NotificationScreen()));
}
}
});
var initializationSettingsAndroid =
const AndroidInitializationSettings('#drawable/ic_notification');
var initializationSettingsIOS = const DarwinInitializationSettings();
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
await _messaging.requestPermission();
String? token = await _messaging.getToken();
if (token != null) {
print("FIREBASE TOKEN $token");
} else {
print("CANNOT TAKE FIREBASE TOKEN");
}
if (Platform.isIOS) {
var APNS = await _messaging.getAPNSToken();
print('APNS: $APNS');
}
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
getToken() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
Constants.USER_TOKEN = pref.getString('login') ?? "";
});
}
#override
void didChangeDependencies() async {
super.didChangeDependencies();
await getToken();
}
Use deleteToken which invalidates the current token and getToken again to get a new one when enabling.
getToken() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
Constants.USER_TOKEN = pref.getString('login') ?? "";
});
if(Constants.USER_TOKEN.isEmpty()){
// delete firebase token
}else{
// get firebase token
}
}
Related
i have implemented firebase push notification in my project with payload json,
I have done all the configurations and now when i click on the notification, it works sometimes perfectly but sometimes the redirection just doesn't work, let's say if i click the notification 10 times, it redirects to the desired page for 4 times and rest 6 times, its taking me to home screen. I am sharing my code below.
Main File
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
await Firebase.initializeApp();
await SharedPref.initialize();
initilizeCamera();
initializeDb();
FlutterError.onError = (error) {
FirebaseCrashlytics.instance.recordFlutterFatalError(error);
};
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(
const ProviderScope(child: MyApp()),
);
});
await pushNotificationToken();
/// Get initial message
await FirebaseMessaging.instance.getInitialMessage();
notificationActions(
action: (RemoteMessage? message) {
if (kDebugMode) {
if (message?.notification != null) {
}
}
if (message != null) {
notificationAction(message: message);
}
},
localNotification: true,
localNotificationAction: (payload) {
if (kDebugMode) {
}
notificationAction(payload: payload);
});
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white,
statusBarColor: Colors.white,
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return KeyboardDismissOnTap(
child: GetMaterialApp(
theme: appThemeData,
debugShowCheckedModeBanner: false,
title: 'XYZ',
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
initialBinding:XYZBindings(),
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => const XYZScreen(),
}),
);
}
}
Firebase Notification Code
/// Firebase messaging instance
FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
/// Get firebase notification instance
FirebaseMessaging get firebaseMessagingInstance => _firebaseMessaging;
/// Firebase push notification token
Future<String?> pushNotificationToken() async =>
_firebaseMessaging.getToken().then((value) {
Log.w('FCM TOKEN :: $value');
return value;
});
/// When user clicks on the notification
void notificationActions({
#required Function(RemoteMessage?)? action,
bool localNotification = false,
Function(Map<String, dynamic>)? localNotificationAction,
}) {
/// Make sure localNotification is Not Null
if (localNotification) {
assert(localNotificationAction != null);
}
if (Platform.isIOS) {
_requestPermissions();
}
if (localNotification) {
FlutterLocalNotificationHelper().initializeSettings(
actionCallback: localNotificationAction,
);
}
/// Get initial message
_firebaseMessaging.getInitialMessage().then((RemoteMessage? message) {
action!(message);
});
/// On Message
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
if (localNotification) {
await FlutterLocalNotificationHelper().showNotificationWithDefaultSound(
title: message.notification?.title,
body: message.notification?.body,
payload: jsonEncode(message.data),
);
}
});
/// On Message open app
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
action!(message);
});
}
/// Request permission for iOS
void _requestPermissions() {
_firebaseMessaging.requestPermission(
provisional: true,
);
}
Local Notification Page
/// Helper class for local notifications
class FlutterLocalNotificationHelper {
/// Constructor
factory FlutterLocalNotificationHelper() => _instance;
FlutterLocalNotificationHelper._();
/// Flutter LocalNotification Helper instance
static final FlutterLocalNotificationHelper _instance =
FlutterLocalNotificationHelper._();
/// Flutter LocalNotification for iOS Category
static const String darwinNotificationCategory = 'plainCategory';
/// Notification plugin
late FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin;
/// Flutter LocalNotifications Plugin
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
/// Request local notification
Future<void> requestLocalNotification() async {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestPermission();
}
/// local notification plugin callback
late Function(Map<String, dynamic>) _localNotificationCallback;
/// Initialize local notifications
Future<void> initializeSettings({
#required Function(Map<String, dynamic>)? actionCallback,
}) async {
if (actionCallback != null) {
_localNotificationCallback = actionCallback;
}
/// initialize settings for => Android
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('#mipmap/ic_launcher');
/// initialize settings for => iOS
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
/// Initialize settings for both => Android / iOS
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
/// Flutter local notification plugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Local notification plugin initialize
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (NotificationResponse response) {
if (response.payload != null) {
_localNotificationCallback(json.decode(response.payload!));
}
},
);
/// On notification click
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await _flutterLocalNotificationsPlugin
.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
await onSelectNotification(
notificationAppLaunchDetails?.notificationResponse.toString(),
);
}
}
/// WHEN USER CLICKS TO NOTIFICATION
Future<void> onSelectNotification(String? payload) async {
if (payload != null) {
final Map<String, dynamic> payloadJson =
jsonDecode(payload) as Map<String, dynamic>;
_localNotificationCallback(payloadJson);
}
}
/// SHOW LOCAL NOTIFICATION
/// 'your channel id', 'your channel name', IS NOT NEEDED
Future<void> showNotificationWithDefaultSound({
#required String? title,
#required String? body,
#required String? payload,
}) async {
/// Android notification details
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your channel id',
'your channel name',
importance: Importance.max,
priority: Priority.high,
color: AppColors.red,
icon: '#mipmap/ic_launcher',
);
/// iOS Notification details
const DarwinNotificationDetails iOSPlatformChannelSpecifics =
DarwinNotificationDetails(
categoryIdentifier: darwinNotificationCategory,
presentSound: true,
presentAlert: true,
badgeNumber: 0,
);
/// Notification platforms details
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
/// Show notification
await _flutterLocalNotificationsPlugin.show(
0,
title,
body,
platformChannelSpecifics,
payload: payload,
);
}
}
Notifications Action page
void notificationAction(
{RemoteMessage? message, Map<String, dynamic>? payload}) {
The redirection is written here.
}
please let me know that why sometimes the redirection works and sometimes not.
I am trying to navigate my notifications while terminated, opened. I can navigate when app is open but not on screen. In my home page's initstate method, I created onMessageOpenedApp method to catch notification then call the api. Here is firebase messaging configuration.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
AppleNotification? apple = message.notification?.apple;
if (notification != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: const IOSNotificationDetails()),
);
}
}
Future<void> iniciliazarFlutterLocalNotifications() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails = !kIsWeb &&
Platform.isLinux
? null
: await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
var androidSettings =
const AndroidInitializationSettings('mipmap/launcher_icon');
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title/ description
importance: Importance.high,
ledColor: Colors.blue);
var iOSSettings = const IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
var initSetttings =
InitializationSettings(android: androidSettings, iOS: iOSSettings);
flutterLocalNotificationsPlugin.initialize(initSetttings);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
AppleNotification? apple = message.notification?.apple;
if (notification != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: const IOSNotificationDetails()),
);
}
});
}
}
And here is my HomeScreen initState variables that only I can navigate my notification then call Api provider.
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
void initState() {
super.initState();
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (message.data.containsKey('idReferance')) {
Provider.of<CustomerProvider>(context, listen: false)
.getTrackingInformationList(TrackingInformationFilterRequestModel(
searchBox: message.data['idReferance']));
}
});
}
#override
Widget build(BuildContext context) {
return Container();
}
}
There is a function called getInitialMessage which returns the remote notifiction if the app is opened from notification when it is terminated.
if the app is opened from other places it will return null. You can handle the navigation according to this remote notification object. Here is a sample function you can use
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);
}
you can call this method from initstate from your app splash screen or some where you find it relevant. You can see example in this link for more detail
https://firebase.flutter.dev/docs/messaging/notifications/#handling-interaction
I am integrating notifications into my applications. Initially, I used firebase I got image notifications in 3 states i.e., on foreground(Local Notifications) background, and terminated state. But when I trigger a notification from postman I am getting a notification for the foreground. But in the background and terminated state, I am getting plain notifications with no image. I am getting the image URL in the data.
import 'dart:convert';
import 'package:authentication/utils/shared_utils.dart';
import 'package:authentication/utils/utils.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import '../presentation/authentication/login/login_view.dart';
import 'package:authentication/utils/routes/routes.dart';
class NotificationHelper {
FirebaseMessaging messaging = FirebaseMessaging.instance;
String notificationText;
AndroidBitmap androidBitmap;
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.max,
playSound: true);
Future initializeFCM(String userId) async {
_initSettings(userId);
///handle messages when app is in foreground
_handleAndroidForegroundNotification();
_handleIosForegroundNotification();
///handle messages when app opened either from background or terminated state.
_onMessageOpened();
_onTerminated();
}
_initSettings(String userId) {
String uId = userId + "userSpecific";
messaging.subscribeToTopic("public");
messaging.subscribeToTopic(uId);
messaging.getToken().then((value) {
print("fcm token >>> " + value);
});
final AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('app_icon');
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(
requestBadgePermission: false,
requestAlertPermission: false,
onDidReceiveLocalNotification: _onDidReceiveLocalNotification,
);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: null);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: _onSelectNotification);
}
Future<dynamic> _onSelectNotification(data) async {
debugPrint("OnSelect Message Log>>>>>>>.");
String userId = SharedUtils.getString('UserId');
if (userId.isEmpty && userId == "") {
SharedUtils.setString('route', data);
Navigator.push(Utils.navigatorKey.currentContext,
MaterialPageRoute(builder: (context) => LoginView()));
} else {
Navigator.of(Utils.navigatorKey.currentContext)
.push(Routes.generateRoute(data));
}
}
Future _onDidReceiveLocalNotification(
int id, String title, String body, String payload) async {
debugPrint("Did receive Message Log>>>>>>>.");
}
///handle foreground state for Android
Future _handleAndroidForegroundNotification() async {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
_showAndroidNotification(message);
});
}
///handle foreground state for iOS
Future _handleIosForegroundNotification() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
///handle background state
Future _onMessageOpened() async {
FirebaseMessaging.onMessageOpenedApp.listen((message) {
debugPrint('onMessageOpenedApp clicked!>>>>>>>>>.');
final routeFromMessage = message.data["route"];
debugPrint('Route called for background***************');
String userId = SharedUtils.getString('UserId');
if (userId.isEmpty && userId == "") {
SharedUtils.setString('route', routeFromMessage);
Navigator.push(Utils.navigatorKey.currentContext,
MaterialPageRoute(builder: (context) => LoginView()));
} else {
Navigator.of(Utils.navigatorKey.currentContext, rootNavigator: true)
.push(Routes.generateRoute(routeFromMessage));
}
});
}
///handle terminated state
static _onTerminated() {
FirebaseMessaging.instance.getInitialMessage().then((message) {
if (message != null) {
final routeFromMessage = message.data["route"];
debugPrint('Route called for terminated state***************');
String userId = SharedUtils.getString('UserId');
if (userId.isEmpty && userId == "") {
SharedUtils.setString('route', routeFromMessage);
Navigator.push(Utils.navigatorKey.currentContext,
MaterialPageRoute(builder: (context) => LoginView()));
} else {
Navigator.of(Utils.navigatorKey.currentContext)
.push(Routes.generateRoute(routeFromMessage));
}
}
});
}
/// set data to the notification UI
Future _showAndroidNotification(RemoteMessage message) async {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
androidBitmap = null;
if (message.data['image'] != null && message.data['image'] != '') {
var imagesBytes = await Utils.getImageBytes(message.data['image']);
androidBitmap =
ByteArrayAndroidBitmap.fromBase64String(base64.encode(imagesBytes));
} else if (message.notification.android.imageUrl != null) {
var imagesBytes =
await Utils.getImageBytes(message.notification.android.imageUrl);
androidBitmap =
ByteArrayAndroidBitmap.fromBase64String(base64.encode(imagesBytes));
}
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
color: Colors.blue,
styleInformation: androidBitmap != null
? BigPictureStyleInformation(androidBitmap)
: null,
playSound: true,
icon: '#mipmap/ic_launcher',
),
),
payload: message.data["route"]);
}
}
}
I'm trying to display the background and foreground notification in flutter using flutter_local_notifications package. here is my firebase class code
class FirebaseMessagingService {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
IOSInitializationSettings? _initializationSettingsIOS;
AndroidInitializationSettings? _initializationSettingsAndroid;
AndroidNotificationDetails? _androidLocalNotificationDetails;
AndroidNotificationChannel? androidNotificationchannel;
static FirebaseMessagingService? _messagingService;
NotificationDetails? _androidNotificationDetails;
InitializationSettings? _initializationSettings;
//NotificationNavigationClass _notificationNavigationClass = NotificationNavigationClass();
NotificationAppLaunchDetails? _notificationAppLaunchDetails;
bool? _didNotificationLaunchApp;
static FirebaseMessaging? _firebaseMessaging;
FirebaseMessagingService._createInstance();
factory FirebaseMessagingService() {
// factory with constructor, return some value
if (_messagingService == null) {
_messagingService = FirebaseMessagingService
._createInstance(); // This is executed only once, singleton object
_firebaseMessaging = _getMessagingService();
}
return _messagingService!;
}
static FirebaseMessaging _getMessagingService() {
return _firebaseMessaging ??= FirebaseMessaging.instance;
}
Future<String?> getToken() {
return _firebaseMessaging!.getToken();
}
Future initializeNotificationSettings() async
{
NotificationSettings? settings = await _firebaseMessaging
?.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings?.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else
if (settings?.authorizationStatus == AuthorizationStatus.provisional) {
print('User granted provisional permission');
} else {
print('User declined or has not accepted permission');
}
androidNotificationchannel = const AndroidNotificationChannel(
NOTIFICATION_ID, // id
NOTIFICATION_TITLE, // title
description: NOTIFICATION_DESCRIPTION,
// description
importance: Importance.max,
);
//
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(androidNotificationchannel!);
if (Platform.isIOS) {
//configure local notification for ios
await _initializeIosLocalNotificationSettings();
}
else {
//configure local notification for android
await _initializeAndroidLocalNotificationSettings();
}
}
Future<void> _initializeIosLocalNotificationSettings() async
{
_initializationSettingsIOS = const IOSInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false
);
_initializationSettings = InitializationSettings(
iOS: _initializationSettingsIOS
);
}
Future<void> _initializeAndroidLocalNotificationSettings() async
{
_initializationSettingsAndroid =
const AndroidInitializationSettings('mipmap/ic_launcher');
_initializationSettings = InitializationSettings(
android: _initializationSettingsAndroid,
);
_androidLocalNotificationDetails =
const AndroidNotificationDetails(
LOCAL_NOTIFICATION_ID,
LOCAL_NOTIFICATION_TITLE,
channelDescription: LOCAL_NOTIFICATION_DESCRIPTION,
importance: Importance.max,
priority: Priority.high);
_androidNotificationDetails =
NotificationDetails(android: _androidLocalNotificationDetails);
//This will execute when the app is open and in foreground
void foregroundNotification() {
try {
_showLocalNotification(localNotificationId: DateTime
.now()
.hour + DateTime
.now()
.minute + DateTime
.now()
.second,
notificationData: message?.data,
messageTitle:message?.notification?.title ,
messageBody: message?.notification?.body,
);
} catch (error) {
log("error");
}
});
}
void _showLocalNotification(
{int? localNotificationId, Map<String, dynamic>? notificationData,String? messageTitle,String? messageBody}) async
{
if (notificationData != null) {
log("Notification Data:${notificationData}");
await _flutterLocalNotificationsPlugin.show(
localNotificationId ?? 0, notificationData["title"]??messageTitle,
notificationData["body"]??messageBody,
_androidNotificationDetails,
payload: jsonEncode(notificationData));
}
}
//This will excute when the app is in background but not killed and tap on that notification
void backgroundTapNotification() {
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) async {
try {
RemoteMessage? terminatedMessage = await _firebaseMessaging
?.getInitialMessage();
} catch (error) {
log("error");
}
});
}
}
and calling it in splash screen
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
heartbeatAnimation =
Tween<double>(begin: 100.0, end: 250.0).animate(controller);
controller.forward().whenComplete(() {
controller.reverse();
});
void _setNotifications() async {
FirebaseMessagingService().foregroundNotification();
FirebaseMessagingService().backgroundTapNotification();
}
await FirebaseMessagingService().initializeNotificationSettings();
_setNotifications();
}
When i close the app and hit the API notification is displaying on background, but when i open the app and hit the API notification is not displaying, nor foreground and not on background.
please help me to get out from this problem.
I use Firebase messaging in my Flutter app , I want to navigate to another screen when I click on the notification even my app is in foreground or background , I used many functions and it doesn't trigger the click event and I can't find anything can solve my problem .
When I click on the notification when app is in foreground or background , nothing happened because it navigate to the same page .
And when I click on the notification when app is terminated , it opens on Splash screen and go to the home not the screen that I want .
I added this intent-filter in my Manifest
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
And I added this to the Json object
"click_action": "FLUTTER_NOTIFICATION_CLICK",
And here is how can I get background FCM in the main.dart
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance', // id
'High Importance Notifications', // title
importance: Importance.high,
playSound: true);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
SessionManager sessionManager = SessionManager();
await Firebase.initializeApp();
//final sound = 'sound.mp3';
print('A bg message just showed up : ${message.messageId}');
final android = AndroidInitializationSettings('#mipmap/ic_launcher');
final ios = IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,);
final settings = InitializationSettings(android: android,iOS: ios);
flutterLocalNotificationsPlugin.initialize(settings,);
if(message.data['title'].toString().toLowerCase()=="new request") {
sessionManager.getBadge().then((badge) {
if (badge != null) {
int x = badge + 1;
sessionManager.saveBadge(x);
print("notification number is " + x.toString());
}
else {
sessionManager.saveBadge(1);
}
});
}
flutterLocalNotificationsPlugin.show(
message.data.hashCode,
message.data['title'],
message.data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
importance: Importance.high,
priority: Priority.high,
// sound: RawResourceAndroidNotificationSound(sound.split('.').first),
playSound: true,
icon: '#mipmap/ic_launcher',
),
));
/*NotificationApi.showNotification(
title: message.data['title'],
body: message.data['body'],
payload: "",
id: int.parse(channel.id));*/
}
Future<void> main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
runApp(MyApps());
// configLoading();
}
class MyApps extends StatefulWidget {
const MyApps({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return MyApp();
}
}
class MyApp extends State<MyApps> {
static ValueNotifier<int> strikeNotifier = ValueNotifier(0);
Color _primaryColor = Color(0xff0d8b75);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
builder: () => MaterialApp(
debugShowCheckedModeBanner: false,
home: SplashScreen(),
),
designSize: const Size(1080, 2280),
);
}
void showNotification(String title, String body) async {
await _demoNotification(title, body);
}
Future<void> _demoNotification(String title, String body) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'channel_I', 'channel name',
showProgress: true,
priority: Priority.high,
playSound: true,
ticker: 'test ticker');
var iOSChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: iOSChannelSpecifics);
await flutterLocalNotificationsPlugin
.show(0, title, body, platformChannelSpecifics, payload: 'test');
}
#override
void initState() {
super.initState();
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));
}
});
getToken().then((value) {
if(value!=null) {
AppConstants.firebaseToken = value;
}
});
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
new FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid = AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettingsIOS = IOSInitializationSettings();
var initializationSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
var data = message.data;
// AndroidNotification? android = message.notification?.android;/
if (data != null ) {
if(data['title'].toString().toLowerCase()=="new request") {
SessionManager sessionManager = SessionManager(context);
sessionManager.getBadge().then((badge) {
if (badge != null) {
setState(() {
int x = badge + 1;
strikeNotifier.value = x;
sessionManager.saveBadge(x);
});
}
else {
strikeNotifier.value = 1;
sessionManager.saveBadge(1);
}
});
}
print("entered");
flutterLocalNotificationsPlugin.show(
data.hashCode,
data['title'],
data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
playSound: true,
icon: '#mipmap/ic_launcher',
),
));
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));
});
}
Future<String?> getToken() async{
String? token = await FirebaseMessaging.instance.getToken();
print("token is "+token!);
return token;
}
}
In yaml
firebase_core: ^1.12.0
firebase_messaging: ^11.2.6
dependency_overrides:
firebase_messaging_platform_interface: 3.1.6
Edit : from multiple solutions , I tried the most common solution that I used onMessageOpenedApp in initState but it doesn't enter in it
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
Navigator.push(context, MaterialPageRoute(builder: (context)=>DoneAndPaiedPagess(0)));
});
In your code, you are using the flutter_local_notifications plugin and you are creating local notification when you get a push notification from firebase messaging.
Since the notification is not created by firebase messaging so, you are not getting on tap callback in getInitialMessage and onMessageOpenedApp.
In order to get on tap callback on local notifications, you can pass a callback function while initializing flutter_local_notifications
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
void selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
// Here you can check notification payload and redirect user to the respective screen
await Navigator.push(
context,
MaterialPageRoute<void>(builder: (context) => SecondScreen(payload)),
);
}
}
For more, you can check flutter_local_notifications documentation
On your home widget within initState, check the getInitialMessage value :
// get the remote message when your app opened from push notification while in background state
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
// check if it is exists
if (initialMessage != null) {
// check the data property within RemoteMessage and do navigate based on it
}
Check the firebase flutter documentation here https://firebase.flutter.dev/docs/messaging/notifications/#handling-interaction.
Use onMessageOpenedApp stream to listen when a notification is opened in the foreground or background. When the application is terminated, use getInitialMessage to get a pending notification.