MaikuB / flutter_local_notifications

A Flutter plugin for displaying local notifications on Android, iOS, macOS and Linux
2.45k stars 1.39k forks source link

onDidReceiveBackgroundNotificationResponse callback is not getting navigate or not triggered function when tapped on notification #2011

Closed itsdani121 closed 1 year ago

itsdani121 commented 1 year ago

Describe the bug

Here i implement flutter local notification with firebase messaging but the issue is when i receive notificaiton on foreground app then it navigate where i want to navigate it. but when my app is on background or terminated state then it will not working backgroundNotificationResponse function till now. here is my code..

Expected behavior

The expected behavior of this function is when app is background or terminated state then this function triggered and inside where i am using navigation then it navigate it without any problem

Sample code to reproduce the problem

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,
  enableLights: true,
  ledColor: Colors.purpleAccent,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
FirebaseMessaging messaging = FirebaseMessaging.instance;
AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('ic_launcher');
final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid);

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
var mIdNotify;
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  RemoteNotification? notification = message.notification;
  AndroidNotification? androidz = message.notification?.android;
  if (message.notification != null && androidz != null) {
    flutterLocalNotificationsPlugin.show(
      notification.hashCode,
      notification?.title,
      notification?.body,
      NotificationDetails(
        android: AndroidNotificationDetails(
          'your channel id',
          'your channel name',
          channelDescription: 'your channel description',
          priority: Priority.high,
          importance: Importance.max,
          // Assigning vibration pattern to notification
          // Assigning custom sound to notification
          icon: '@mipmap/ic_launcher',
          // Assigning large icon to notification
          largeIcon: DrawableResourceAndroidBitmap('@mipmap/ic_launcher'),
        ),
      ),
    );
    mIdNotify = message.data['meeting_id'];
    print('meeting background id $mIdNotify  - ${box.read('nMeetingId')}');
  }
  // popUpMessage(message.notification!.android!.tag!);
  // }
  navigatorKey.currentState?.push(MaterialPageRoute(
    builder: (context) => MeetingViewPage(meetingId: box.read('nMeeting') != null ? int.parse(box.read('nMeetingId')) : int.parse(mIdNotify)),
  ));

  print('backgrond  mssss   ${message.notification?.toMap()}');
}

//main method.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  await Firebase.initializeApp();
  await GetStorage.init();
  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

    messaging.getToken().then((value) {
      box.write('fcm_token', value!);
    });
    FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);

  await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);
    await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
      alert: true, // Required to display a heads up notification
      badge: true,
      sound: true,
    );

    _fcmForegroundHandler();
    runApp(SplashPage());

}

  Future<void> _fcmForegroundHandler() async {
    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      RemoteNotification? notification = message.notification;
      AndroidNotification? androidx = message.notification?.android;
      if (notification != null && androidx != null) {
        flutterLocalNotificationsPlugin.show(
          notification.hashCode,
          notification.title,
          notification.body,
          NotificationDetails(
            android: AndroidNotificationDetails(
              'your channel id',
              'your channel name',
              channelDescription: 'your channel description',
              priority: Priority.high,
              importance: Importance.max,
              // Assigning icon to notification
              icon: '@mipmap/ic_launcher',
              // Assigning large icon to notification
              largeIcon: DrawableResourceAndroidBitmap('@mipmap/ic_launcher'),
            ),
          ),
        );
        mIdNotify = message.data['meeting_id'];
      }
      popUpMessage(message.data['meeting_id']);
    });

    print('fmc token  ${box.read('fcm_token')}');
  }

  popUpMessage(mId) async {
    box.write('nMeetingId', mId!);

    await flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onDidReceiveNotificationResponse: notificationTapBackground, onDidReceiveBackgroundNotificationResponse: notificationTapBackground);
  }

  @pragma('vm:entry-point')
  void notificationTapBackground(NotificationResponse details) {
    // handle action

    Future(() async {

      await Navigator.push(
          context,
          MaterialPageRoute(
              builder: (context) => MeetingViewPage(
                    meetingId: 600,
                  )));
    });

  }
MaikuB commented 1 year ago

This isn't a bug as the expectations you've listed aren't based on how the plugin works. Please refer through the docs and example app

itsdani121 commented 1 year ago

issue

here is in documentation in which it mention to use how to use these plugin function

issue

but it didnot work that's why i create issue. so kindly look into this matter or explain what i missed... @MaikuB

itsdani121 commented 1 year ago

i also comments on other issues which are closed but didnot get response that's why i create this issue

MaikuB commented 1 year ago

The section of the documentation you are looking into is for notification actions, which you don't use at all. That's an explicit section in the readme for what you talked about even https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications#handling-notifications-whilst-the-app-is-in-the-foreground. As mentioned earlier please take a careful look at docs and what you're using. I recommend you also run the example app to understand the behaviour

itsdani121 commented 1 year ago

app run in the foreground properly, when I receive notification it navigates me to a specific screen but the issue came in the background or terminated state, also there is no clearly explanation about android device. all steps clearly mention above code, and follow as per guidelines.

itsdani121 commented 1 year ago

all android guidellines are followed here

MaikuB commented 1 year ago

All the info is there in the docs and example app. What you spoke about then is covered by https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications#getting-details-on-if-the-app-was-launched-via-a-notification-created-by-this-plugin and https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications#initialisation. I had mentioned looking at the example app as well a number of times but seems like you haven't tried to do so either so please take a look at it

sanjaycdev commented 1 year ago

@itsdani121 have you found any solution , am also stuck in the same situation , No matter wot i do onDidReceiveBackgroundNotificationResponse is not triggering .

itsdani121 commented 1 year ago

I uae awesome notification now

sanjaycdev commented 1 year ago

After a while i would like to share my findings , the onDidReceiveBackgroundNotificationResponse is getting executed only while clicking on notification Actions or attachments , Tried in my app and also in shared example app , it works the same [Android]. image and to get payload data on selecting notification i am using getNotificationAppLaunchDetails() I hope it helps some one in future :) let me know if am wrong

MaikuB commented 1 year ago

@sanjaycdev that is correct. This is why I mentioned @itsdani121 expectations weren't correct as they were looking at the documentation that was for notification actions and none of their code used notification actions

sanjaycdev commented 1 year ago

Is there any function which gets executed selecting on notification while app is in terminated state ? @itsdani121 i tried with FirebaseMessaging.instance.getInitialMessage() , this doesn't carry payload data its "null" Each time i select the notification it triggers the but its returning null. final RemoteMessage? _message = await FirebaseMessaging.instance.getInitialMessage();

`"notification" : { "body" : "test", "content_available" : true, "priority" : "max", "title" : "test", "image":"https://fastly.picsum.photos/id/612/536/354.jpg?hmac=Q46mJFmXBiIMHIwDHpyVW2eC7hVZB11ag3JpXAglHEk" },

"data" : { "body" : "test notif", "contentavailable" : "true", "priority" : "high", "title" : "test data" }`

if i send notification with "notification":{} then its returning the payload , but without "notification":{} it returns null

itsdani121 commented 1 year ago

@sanjaycdev i think @MaikuB is only person who give answer about this question bcz still i dont get the solution about it , when app is terminate condition how i get notification and navigate it.

sanjaycdev commented 1 year ago

hi @itsdani121 I am happy share my solution here :), So the package provides getNotificationAppLaunchDetails() which helps to achieve what we are expecting . code below

 final NotificationAppLaunchDetails notificationAppLaunchDetails =
      await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();

  if (notificationAppLaunchDetails.didNotificationLaunchApp) {
     print('Notification payload: ${notificationAppLaunchDetails.payload}');
}

a lot of effort to finally find this single line of code with a lot of satisfaction at the end :). @MaikuB correct me if am wrong

MaikuB commented 1 year ago

That is correct. Reminder this plugin is only for local notifications so trying to use this plugin to deal with when a user interacted with a push notification e.g. from FCM won't work. This means if you use FCM, it's plugin is what you should use to deal with notifications from FCM

TinhHuynh commented 10 months ago

Should we rename onDidReceiveBackgroundNotificationResponse into a more meaningful one since this will be called when we tap on an action of a notification?

santhoshkumar4035 commented 6 months ago

@sanjaycdev where to use this code final NotificationAppLaunchDetails notificationAppLaunchDetails = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();

if (notificationAppLaunchDetails.didNotificationLaunchApp) { print('Notification payload: ${notificationAppLaunchDetails.payload}'); }

sunil-singh-chaudhary commented 4 months ago

did you find any solution

@sanjaycdev where to use this code final NotificationAppLaunchDetails notificationAppLaunchDetails = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();

if (notificationAppLaunchDetails.didNotificationLaunchApp) { print('Notification payload: ${notificationAppLaunchDetails.payload}'); }

TinhHuynh commented 4 months ago

@sunil-singh-chaudhary You can put the code on the first screen of your app.

sunil-singh-chaudhary commented 4 months ago

ok thanks for replying the exact problem is i am using { "message": { "token": "fprLORLLQGGc_luE7YpUjg:APA91bET--hCU5f68JCp",

"data": { "channel_id": "channel_id_18", "sound": "app_sound", "title": "My First Notification", "body": "{\"description\": \"Hey you received a chat request from User\", \"notificationType\": 2}"

},

} } for custom sound ok so the problem with firebase is first time when app is in foreground it will running properly as it is intialized but if first time app is in background then it is playing defualt tone so i changed my api to send in data tag all sound and channel id "data": { "channel_id": "channel_id_18", "sound": "app_sound", "title": "My First Notification", "body": "{\"description\": \"Hey you received a chat request from User\", \"notificationType\": 2}"

}, instead of using notification so it is now working fine everywhere except when tap on notification now before it is handle by firebase FirebaseMessaging.onMessageOpenedApp.listen())

but now not so i want this data payload from notification but while app in foreground again then onDidReceiveNotificationResponse is called but giving wrong formate data like is

"{sound: app_sound, body: {\"description\": \"Hey you received a chat request from User\", \"notificationType\": 2}, title: My First Notification, channel_id: channel_id_18}" [log] payload body "\"{sound: app_sound, body: {\\"description\\": \\"Hey you received a chat request from User\\", \\"notificationType\\": 2}, title: My First Notification, channel_id: channel_id_18}\""

well this is not converting to json first, second now if again app in background then onDidReceiveNotificationResponse is never called don't know what is happening here should i change lib to awssom notification any idea

code is

Future foregroundNotificatioCustomAuddio(RemoteMessage payload) async { _setNotificationDisplayed(true); final localNotificationshandler = FlutterLocalNotificationsPlugin();

var messageData = json.decode((payload.data['body']));

final initializationSettingsDarwin = DarwinInitializationSettings(
  defaultPresentBadge: true,
  requestSoundPermission: true,
  requestBadgePermission: true,
  defaultPresentSound: false,
  onDidReceiveLocalNotification: (id, title, body, payload) async {
    return;
  },
);
final android = const AndroidInitializationSettings('@mipmap/ic_launcher');
final initialSetting = InitializationSettings(

    android: android, iOS: initializationSettingsDarwin);
localNotificationshandler.initialize(
  initialSetting,
  onDidReceiveNotificationResponse: ondidreceiveBackgroundResponseHandler,
  onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
final customSound = 'app_sound.wav';
AndroidNotificationDetails androidDetails =
    const AndroidNotificationDetails(
  'channel_id_18',
  'channel.name',
  importance: Importance.max,
  icon: "@mipmap/ic_launcher",
  playSound: true,
  enableVibration: true,
  sound: RawResourceAndroidNotificationSound('app_sound'),
);

final iOSDetails = DarwinNotificationDetails(
  sound: customSound,
);
final platformChannelSpecifics =
    NotificationDetails(android: androidDetails, iOS: iOSDetails);
global.sp = await SharedPreferences.getInstance();

if (global.sp!.getString("currentUser") != null) {
  await localNotifications.show(
    10,
    ' payload.notification!.title',
    'payload.notification!.body',
    platformChannelSpecifics,
    payload: json.encode(payload.data.toString()),
  );
}

} and

@pragma('vm:entry-point') static void ondidreceiveBackgroundResponseHandler( NotificationResponse details) { log('respons ondidreceiveBackgroundResponseHandler clicked ${details.payload}'); String payloadString = details.payload!; Map<String, dynamic> payloadData = convert.jsonDecode(payloadString); log('payloadData clicked $payloadData'); }

@pragma('vm:entry-point') static void notificationTapBackground( NotificationResponse notificationResponse) { log('respons background notification clicked ${notificationResponse.payload}'); global.showToast(message: 'notification clicked in background'); // handle action } outside top level method one more thing notificationTapBackground method never initiate or called whether app is in foreground or background

thiagolioy commented 3 weeks ago

This is not working.. The callback when the user taps a local notification is not being called. Everything is properly configured. I can send the notifications and tap them. Remote notifications are working fine also. The callbacks for the Flutter local notifications package are not being trigged. What am I doing wrong?

Future<void> initNotification() async {
    const AndroidInitializationSettings androidInitializationSettings =
        AndroidInitializationSettings("app_icon");

    final DarwinInitializationSettings iOSInitializationSettings =
        DarwinInitializationSettings(
      requestAlertPermission: true,
      requestBadgePermission: true,
      requestSoundPermission: true,
      onDidReceiveLocalNotification: (id, title, body, payload) async {
        debugPrint(
            "onDidReceiveLocalNotification: id: $id, title: $title, body: $body, payload: $payload");
      },
    );

    final InitializationSettings initializationSettings =
        InitializationSettings(
      android: androidInitializationSettings,
      iOS: iOSInitializationSettings,
    );
    await notificationPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse: ondDidReceiveLocalNotification,
      onDidReceiveBackgroundNotificationResponse:
          ondDidReceiveLocalNotification,
    );

    await notificationPlugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.requestNotificationsPermission();

    final appNotification =
        await notificationPlugin.getNotificationAppLaunchDetails();
    if (appNotification != null && appNotification.didNotificationLaunchApp) {
      AnalyticsCenter.getInstance()
          .trackEvent('APP_LAUNCHED_BY_LOCAL_NOTIFICATION');

    }
  }

  @pragma('vm:entry-point')
  static Future<void> ondDidReceiveLocalNotification(
      NotificationResponse notificationResponse) async {
    debugPrint("ondDidReceiveLocalNotification: $notificationResponse");
  }

  notificationDetails() {
    return NotificationDetails(
        android: AndroidNotificationDetails(
            androidChannelID, androidChannelTitle,
            importance: Importance.max, priority: Priority.high),
        iOS: const DarwinNotificationDetails());
  }

  Future showNotification(
      {int id = 0, String? title, String? body, String? payload}) async {
    return notificationPlugin.show(
        id, title, body, payload: payload, await notificationDetails());
  }