When i tap on notificatio and app is in foreground state, then “onDidReceiveNotificationResponse” does not trigger. why ? I have added print statement inside the method and it’s not working. I am getting notifications both in terminated and foreground state. Only issue is that I can not detect the notification tap in the case of foreground.
<code>import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sos_cameroon/app/common/shared_preference_manager.dart';
import 'package:sos_cameroon/src/features/notifications/data/repositories/local_notification_service.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import '../../models/schedule_notification_model.dart';
@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
// ignore: avoid_print
print('notification(${notificationResponse.id}) action tapped: '
'${notificationResponse.actionId} with'
' payload: ${notificationResponse.payload}');
if (notificationResponse.input?.isNotEmpty ?? false) {
// ignore: avoid_print
print(
'notification action tapped with input: ${notificationResponse.input}');
}
}
class FlutterLocalNotification implements LocalNotificationService {
final SharedPreferences _sharedPreferences =
SharedPreferencesManager.instance;
final StreamController<String?> _selectNotificationStream =
StreamController<String?>.broadcast();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidNotificationDetails _channel = const AndroidNotificationDetails(
'default_notification_channel_id', // id
'High Importance Notifications', // title
// description
importance: Importance.high,
enableLights: true,
actions: <AndroidNotificationAction>[
AndroidNotificationAction('1', '', showsUserInterface: true),
],
playSound: true);
@override
Future<void> initialize() async {
await _configureLocalTimeZone();
await _configureNotifications();
}
Future<bool> _isAlreadyScheduled() async {
return _sharedPreferences.getBool("local_notification_schedule") ?? false;
}
Future<bool> _localNotificationScheduled() async {
return _sharedPreferences.setBool("local_notification_schedule", true);
}
Future<void> _configureNotifications() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {},
);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {
debugPrint("NOTIFICATION TAPPED ++++");
switch (notificationResponse.notificationResponseType) {
case NotificationResponseType.selectedNotification:
debugPrint("NOTIFICATION TAPPED: ${notificationResponse.payload}");
break;
case NotificationResponseType.selectedNotificationAction:
if (notificationResponse.actionId == "1") {
debugPrint(
"NOTIFICATION TAPPED ++ SELECTED NOTIFICATION TAPPED: ${notificationResponse.payload}");
}
break;
}
},
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
}
// on tap on any notification
static void onNotificationTap(NotificationResponse notificationResponse) {
// _selectNotificationStream.add(notificationResponse.payload!);
debugPrint("NOTIFICATION IS TAPPED +++++++++++");
}
@override
Future<String?> notificationPayloadFromWhichAppOpened() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
!kIsWeb && Platform.isLinux
? null
: await flutterLocalNotificationsPlugin
.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
String? selectedNotificationPayload =
notificationAppLaunchDetails!.notificationResponse?.payload;
return selectedNotificationPayload;
}
return null;
}
@override
Future<void> requestPermissions() async {
await _requestPermissions();
}
@override
Future<void> scheduleNotification(
{required int id,
required String title,
required String description,
String? payload,
required Duration durationFromCurrentTime}) async {
debugPrint(
"NOTIFICATION SCHEDULED AT+++++++ $durationFromCurrentTime ++++ ${tz.TZDateTime.now(tz.local).add(durationFromCurrentTime)}");
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
description,
payload: payload,
tz.TZDateTime.now(tz.local).add(durationFromCurrentTime),
NotificationDetails(android: _channel),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
}
Future<void> _configureLocalTimeZone() async {
if (kIsWeb || Platform.isLinux) {
return;
}
tz.initializeTimeZones();
final String timeZoneName = await FlutterTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
Future<void> _requestPermissions() async {
if (Platform.isIOS || Platform.isMacOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
MacOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
} else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final bool? grantedNotificationPermission =
await androidImplementation?.requestNotificationsPermission();
// If the app requires scheduling notifications with exact timings
await AndroidFlutterLocalNotificationsPlugin()
.requestExactAlarmsPermission();
}
}
@override
Future<void> scheduleAllNotificationsFromJson() async {
// 1. FIRST CHECK IF NOTIFICATION ALREADY SCHEDULES OR NOT
// if(await _isAlreadyScheduled()){
// debugPrint("NOTIFICATIONS ARE ALREADY SCHEDULED ++++++");
// return;
// }
List<ScheduleNotificationModel> scheduleNotifications =
await _loadNotifications();
for (int index = 0; index < scheduleNotifications.length; index++) {
ScheduleNotificationModel notification = scheduleNotifications[index];
LocaleData localeData = notification.locales!['en']!;
scheduleNotification(
id: index,
title: localeData.title ?? "N/A",
description: localeData.description ?? "N/A",
payload: json.encode(notification.toJson()),
durationFromCurrentTime: Duration(
days: ((notification.day ?? 1) - 1),
hours: notification.hour ?? 0,
minutes: notification.minute ?? 0,
seconds: notification.second ?? 0,
),
);
}
_localNotificationScheduled();
}
/// Read json according to current locale
Future<List<ScheduleNotificationModel>> _loadNotifications() async {
// final currentLocale = Localizations.localeOf(context);
// debugPrint("CURRENT LOCALE : ${currentLocale.languageCode}");
final jsonString =
await rootBundle.loadString('assets/local_notifications/mock.json');
final jsonData = json.decode(jsonString) as List<dynamic>;
return jsonData
.map((json) => ScheduleNotificationModel.fromJson(json))
.toList();
}
@override
Stream<String?> selectNotificationStream() {
return _selectNotificationStream.stream;
}
}
</code>
<code>import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sos_cameroon/app/common/shared_preference_manager.dart';
import 'package:sos_cameroon/src/features/notifications/data/repositories/local_notification_service.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import '../../models/schedule_notification_model.dart';
@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
// ignore: avoid_print
print('notification(${notificationResponse.id}) action tapped: '
'${notificationResponse.actionId} with'
' payload: ${notificationResponse.payload}');
if (notificationResponse.input?.isNotEmpty ?? false) {
// ignore: avoid_print
print(
'notification action tapped with input: ${notificationResponse.input}');
}
}
class FlutterLocalNotification implements LocalNotificationService {
final SharedPreferences _sharedPreferences =
SharedPreferencesManager.instance;
final StreamController<String?> _selectNotificationStream =
StreamController<String?>.broadcast();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidNotificationDetails _channel = const AndroidNotificationDetails(
'default_notification_channel_id', // id
'High Importance Notifications', // title
// description
importance: Importance.high,
enableLights: true,
actions: <AndroidNotificationAction>[
AndroidNotificationAction('1', '', showsUserInterface: true),
],
playSound: true);
@override
Future<void> initialize() async {
await _configureLocalTimeZone();
await _configureNotifications();
}
Future<bool> _isAlreadyScheduled() async {
return _sharedPreferences.getBool("local_notification_schedule") ?? false;
}
Future<bool> _localNotificationScheduled() async {
return _sharedPreferences.setBool("local_notification_schedule", true);
}
Future<void> _configureNotifications() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {},
);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {
debugPrint("NOTIFICATION TAPPED ++++");
switch (notificationResponse.notificationResponseType) {
case NotificationResponseType.selectedNotification:
debugPrint("NOTIFICATION TAPPED: ${notificationResponse.payload}");
break;
case NotificationResponseType.selectedNotificationAction:
if (notificationResponse.actionId == "1") {
debugPrint(
"NOTIFICATION TAPPED ++ SELECTED NOTIFICATION TAPPED: ${notificationResponse.payload}");
}
break;
}
},
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
}
// on tap on any notification
static void onNotificationTap(NotificationResponse notificationResponse) {
// _selectNotificationStream.add(notificationResponse.payload!);
debugPrint("NOTIFICATION IS TAPPED +++++++++++");
}
@override
Future<String?> notificationPayloadFromWhichAppOpened() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
!kIsWeb && Platform.isLinux
? null
: await flutterLocalNotificationsPlugin
.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
String? selectedNotificationPayload =
notificationAppLaunchDetails!.notificationResponse?.payload;
return selectedNotificationPayload;
}
return null;
}
@override
Future<void> requestPermissions() async {
await _requestPermissions();
}
@override
Future<void> scheduleNotification(
{required int id,
required String title,
required String description,
String? payload,
required Duration durationFromCurrentTime}) async {
debugPrint(
"NOTIFICATION SCHEDULED AT+++++++ $durationFromCurrentTime ++++ ${tz.TZDateTime.now(tz.local).add(durationFromCurrentTime)}");
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
description,
payload: payload,
tz.TZDateTime.now(tz.local).add(durationFromCurrentTime),
NotificationDetails(android: _channel),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
}
Future<void> _configureLocalTimeZone() async {
if (kIsWeb || Platform.isLinux) {
return;
}
tz.initializeTimeZones();
final String timeZoneName = await FlutterTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
Future<void> _requestPermissions() async {
if (Platform.isIOS || Platform.isMacOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
MacOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
} else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final bool? grantedNotificationPermission =
await androidImplementation?.requestNotificationsPermission();
// If the app requires scheduling notifications with exact timings
await AndroidFlutterLocalNotificationsPlugin()
.requestExactAlarmsPermission();
}
}
@override
Future<void> scheduleAllNotificationsFromJson() async {
// 1. FIRST CHECK IF NOTIFICATION ALREADY SCHEDULES OR NOT
// if(await _isAlreadyScheduled()){
// debugPrint("NOTIFICATIONS ARE ALREADY SCHEDULED ++++++");
// return;
// }
List<ScheduleNotificationModel> scheduleNotifications =
await _loadNotifications();
for (int index = 0; index < scheduleNotifications.length; index++) {
ScheduleNotificationModel notification = scheduleNotifications[index];
LocaleData localeData = notification.locales!['en']!;
scheduleNotification(
id: index,
title: localeData.title ?? "N/A",
description: localeData.description ?? "N/A",
payload: json.encode(notification.toJson()),
durationFromCurrentTime: Duration(
days: ((notification.day ?? 1) - 1),
hours: notification.hour ?? 0,
minutes: notification.minute ?? 0,
seconds: notification.second ?? 0,
),
);
}
_localNotificationScheduled();
}
/// Read json according to current locale
Future<List<ScheduleNotificationModel>> _loadNotifications() async {
// final currentLocale = Localizations.localeOf(context);
// debugPrint("CURRENT LOCALE : ${currentLocale.languageCode}");
final jsonString =
await rootBundle.loadString('assets/local_notifications/mock.json');
final jsonData = json.decode(jsonString) as List<dynamic>;
return jsonData
.map((json) => ScheduleNotificationModel.fromJson(json))
.toList();
}
@override
Stream<String?> selectNotificationStream() {
return _selectNotificationStream.stream;
}
}
</code>
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sos_cameroon/app/common/shared_preference_manager.dart';
import 'package:sos_cameroon/src/features/notifications/data/repositories/local_notification_service.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import '../../models/schedule_notification_model.dart';
@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
// ignore: avoid_print
print('notification(${notificationResponse.id}) action tapped: '
'${notificationResponse.actionId} with'
' payload: ${notificationResponse.payload}');
if (notificationResponse.input?.isNotEmpty ?? false) {
// ignore: avoid_print
print(
'notification action tapped with input: ${notificationResponse.input}');
}
}
class FlutterLocalNotification implements LocalNotificationService {
final SharedPreferences _sharedPreferences =
SharedPreferencesManager.instance;
final StreamController<String?> _selectNotificationStream =
StreamController<String?>.broadcast();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidNotificationDetails _channel = const AndroidNotificationDetails(
'default_notification_channel_id', // id
'High Importance Notifications', // title
// description
importance: Importance.high,
enableLights: true,
actions: <AndroidNotificationAction>[
AndroidNotificationAction('1', '', showsUserInterface: true),
],
playSound: true);
@override
Future<void> initialize() async {
await _configureLocalTimeZone();
await _configureNotifications();
}
Future<bool> _isAlreadyScheduled() async {
return _sharedPreferences.getBool("local_notification_schedule") ?? false;
}
Future<bool> _localNotificationScheduled() async {
return _sharedPreferences.setBool("local_notification_schedule", true);
}
Future<void> _configureNotifications() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {},
);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {
debugPrint("NOTIFICATION TAPPED ++++");
switch (notificationResponse.notificationResponseType) {
case NotificationResponseType.selectedNotification:
debugPrint("NOTIFICATION TAPPED: ${notificationResponse.payload}");
break;
case NotificationResponseType.selectedNotificationAction:
if (notificationResponse.actionId == "1") {
debugPrint(
"NOTIFICATION TAPPED ++ SELECTED NOTIFICATION TAPPED: ${notificationResponse.payload}");
}
break;
}
},
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
}
// on tap on any notification
static void onNotificationTap(NotificationResponse notificationResponse) {
// _selectNotificationStream.add(notificationResponse.payload!);
debugPrint("NOTIFICATION IS TAPPED +++++++++++");
}
@override
Future<String?> notificationPayloadFromWhichAppOpened() async {
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
!kIsWeb && Platform.isLinux
? null
: await flutterLocalNotificationsPlugin
.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
String? selectedNotificationPayload =
notificationAppLaunchDetails!.notificationResponse?.payload;
return selectedNotificationPayload;
}
return null;
}
@override
Future<void> requestPermissions() async {
await _requestPermissions();
}
@override
Future<void> scheduleNotification(
{required int id,
required String title,
required String description,
String? payload,
required Duration durationFromCurrentTime}) async {
debugPrint(
"NOTIFICATION SCHEDULED AT+++++++ $durationFromCurrentTime ++++ ${tz.TZDateTime.now(tz.local).add(durationFromCurrentTime)}");
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
description,
payload: payload,
tz.TZDateTime.now(tz.local).add(durationFromCurrentTime),
NotificationDetails(android: _channel),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
}
Future<void> _configureLocalTimeZone() async {
if (kIsWeb || Platform.isLinux) {
return;
}
tz.initializeTimeZones();
final String timeZoneName = await FlutterTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
Future<void> _requestPermissions() async {
if (Platform.isIOS || Platform.isMacOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
MacOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
} else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final bool? grantedNotificationPermission =
await androidImplementation?.requestNotificationsPermission();
// If the app requires scheduling notifications with exact timings
await AndroidFlutterLocalNotificationsPlugin()
.requestExactAlarmsPermission();
}
}
@override
Future<void> scheduleAllNotificationsFromJson() async {
// 1. FIRST CHECK IF NOTIFICATION ALREADY SCHEDULES OR NOT
// if(await _isAlreadyScheduled()){
// debugPrint("NOTIFICATIONS ARE ALREADY SCHEDULED ++++++");
// return;
// }
List<ScheduleNotificationModel> scheduleNotifications =
await _loadNotifications();
for (int index = 0; index < scheduleNotifications.length; index++) {
ScheduleNotificationModel notification = scheduleNotifications[index];
LocaleData localeData = notification.locales!['en']!;
scheduleNotification(
id: index,
title: localeData.title ?? "N/A",
description: localeData.description ?? "N/A",
payload: json.encode(notification.toJson()),
durationFromCurrentTime: Duration(
days: ((notification.day ?? 1) - 1),
hours: notification.hour ?? 0,
minutes: notification.minute ?? 0,
seconds: notification.second ?? 0,
),
);
}
_localNotificationScheduled();
}
/// Read json according to current locale
Future<List<ScheduleNotificationModel>> _loadNotifications() async {
// final currentLocale = Localizations.localeOf(context);
// debugPrint("CURRENT LOCALE : ${currentLocale.languageCode}");
final jsonString =
await rootBundle.loadString('assets/local_notifications/mock.json');
final jsonData = json.decode(jsonString) as List<dynamic>;
return jsonData
.map((json) => ScheduleNotificationModel.fromJson(json))
.toList();
}
@override
Stream<String?> selectNotificationStream() {
return _selectNotificationStream.stream;
}
}