MaikuB / flutter_local_notifications

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

Flutter local notification didnt work on background #2428

Open BIBS23 opened 1 month ago

BIBS23 commented 1 month ago
Flutter local notification didnt work on background in debug it is working fine. I have used this package for showing notifcation in foreground it works perfectly but on background it doesnt the firebase default notificatin is showing. Is there is a way to show local notificatin with action in background  im attaching my code below

@pragma('vm:entry-point')
void onSelectNotification(NotificationResponse notificationResponse) async {
  final payload = notificationResponse.payload;

  if (payload != null && payload.isNotEmpty) {
    Map<String, dynamic> data = Map<String, dynamic>.from(jsonDecode(payload));

    log("Notification payload: ${data.toString()}");

    String messageType = data['type'];

    if (notificationResponse.actionId == 'accept_call') {
      // Stop the audio first
      await audioPlayer.stop();
      audioPlayer.dispose();

      // Cancel the notification
      if (notificationId != null) {
        flutterLocalNotificationsPlugin.cancel(notificationId!);
      }

      // Navigate to the call view
      navigatorKey.currentState?.push(
        MaterialPageRoute(
          builder: (_) => CallView(
            channelId: data['channelId'],
            agoraToken: data['agora_token'],
            contactName: data['caller_name'],
          ),
        ),
      );

      return; // Early return to prevent further execution
    } else if (notificationResponse.actionId == 'reject_call') {
      // Stop the audio first
      await audioPlayer.stop();
      audioPlayer.dispose();

      // Cancel the notification
      if (notificationId != null) {
        flutterLocalNotificationsPlugin.cancel(notificationId!);
      }

      // Since this is a reject action, do not navigate to any page
      log('Call Rejected');

      return; // Early return to prevent further navigation
    }

    // Handle other message types based on 'messageType'
    if (messageType == 'missed_call') {
      BottomNavProvider().setPage(3);
    } else if (messageType == 'chat') {
      navigatorKey.currentState?.push(
        MaterialPageRoute(
          builder: (_) => IncomingCallView(
            channelId: data['channelId'],
            agoraToken: data['agora_token'],
            contactName: data['channelId'],
          ),
        ),
      );
    } else if (messageType == 'new_interest') {
      navigatorKey.currentState?.push(
        MaterialPageRoute(
          builder: (_) => IncomingCallView(
            channelId: data['channelId'],
            agoraToken: data['agora_token'],
            contactName: data['caller_name'],
          ),
        ),
      );
    } else if (messageType == 'notification') {
      navigatorKey.currentState?.push(
        MaterialPageRoute(
          builder: (_) =>
              NotificationView(), // Navigate to the notification screen
        ),
      );
    }
  } else {
    log("Notification payload is null or empty.");
  }
}

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
AudioPlayer audioPlayer = AudioPlayer();
int? notificationId;

class PushNoti {
  String? _fcmToken;
  final FirebaseMessaging _fcm = FirebaseMessaging.instance;

  Future<void> requestNotificationPermission() async {
    await _fcm.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );
    _fcmToken = await _fcm.getToken();
    log('device FCM token is $_fcmToken');

    LocalStorage.setString({'fcmToken': _fcmToken.toString()});
    _fcmToken = await _fcm.getToken();
  }

  Future<void> initPushNotification() async {
    _fcmToken = await _fcm.getToken();
    log('device FCM token is $_fcmToken');

    LocalStorage.setString({'fcmToken': _fcmToken.toString()});

    // Handle incoming messages when the app is in the foreground
    FirebaseMessaging.onMessage.listen((RemoteMessage? message) async {
      // showNotification(message!);
      // If it's a call type message, show the incoming call screen
      if (message!.data.isNotEmpty && message!.data['type'] == 'call') {
        audioPlayer.play();
        navigatorKey.currentState
            ?.push(
          MaterialPageRoute(
            builder: (_) => IncomingCallView(
              channelId: message!.data['channelId'],
              agoraToken: message.data['agora_token'],
              contactName: message.data['caller_name'],
            ),
          ),
        )
            .then((_) {
          if (notificationId != null) {
            audioPlayer.stop();
            flutterLocalNotificationsPlugin.cancel(notificationId!);
          }
        });
      } else {
        showNotification(message);
      }
    });

    // Handle notification taps when the app is in the background or terminated
    FirebaseMessaging.onMessageOpenedApp
        .listen((RemoteMessage? message) async {});

    // Check if the app was opened from a terminated state due to a notification tap
    _fcm.getInitialMessage().then((RemoteMessage? message) {});
  }
}

void showNotification(RemoteMessage message) async {
  RemoteNotification? notification = message.notification;
  AndroidNotification? android = message.notification?.android;
  String? title = message.data['title'];
  String? body = message.data['body'];
  String? type = message.data['type'];

  if (message.data['type'] == 'call') {
    await audioPlayer.setAsset(
        'assets/ringtone/ringtone.mp3'); // Load the ringtone from assets
    audioPlayer.play();

    log('hello world tttt ${message.data.toString()}');
  }
  var platformChannelSpecifics = NotificationDetails(
    android: message.data['type'] == 'call'
        ? AndroidNotificationDetails(
            'call_channel', // For call notifications
            'Incoming Call',

            importance: Importance.max,
            priority: Priority.max,
            // sound: RawResourceAndroidNotificationSound('isa_63861'), // Custom sound for calls (optional)
            playSound: true,
            color: UiColor.primary,
            actions: <AndroidNotificationAction>[
              AndroidNotificationAction(
                'accept_call',
                'Accept',
                // icon: DrawableResourceAndroidBitmap("ic_accept"),
                showsUserInterface: true,
              ),
              AndroidNotificationAction(
                'reject_call',
                'Reject',
                // icon: DrawableResourceAndroidBitmap("ic_reject"),
                showsUserInterface: true,
              ),
            ],
          )
        : AndroidNotificationDetails(
            'important_notifications', // For other notifications
            'Important Notifications',
            importance: Importance.high,
            color: UiColor.primary,
            // sound: RawResourceAndroidNotificationSound("notification_sound"), // Optional custom sound
            actions: [], // No actions for other notifications (can be added dynamically)
          ),
    iOS: DarwinNotificationDetails(
      sound: 'default',
      presentAlert: true,
      presentBadge: true,
      presentSound: true,
    ),
  );

  if (notification != null && android != null) {
    notificationId = notification.hashCode;

    flutterLocalNotificationsPlugin.show(notification.hashCode,
       notification.title, notification.body, platformChannelSpecifics,
        payload: jsonEncode(message.data));
  }

}

Future<void> initLocalNotifications() async {
  const AndroidInitializationSettings initializationSettingsAndroid =
      AndroidInitializationSettings('mipmap/ic_launcher');

  const InitializationSettings initializationSettings = InitializationSettings(
    android: initializationSettingsAndroid,
    iOS: DarwinInitializationSettings(),
  );

  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
  onDidReceiveBackgroundNotificationResponse: (NotificationResponse notificationResponse) async {
      // Handle background notification response here
      log('Background notification received from local notoifction: ${notificationResponse.payload}');
    },
      onDidReceiveNotificationResponse: onSelectNotification);
}

Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  // Show the notification first
  showNotification(message);

  // Check if the message type is 'call'
  if (message.data['type'] == 'call') {
    // Wait for 25 seconds
    await Future.delayed(Duration(seconds: 25));

    // Remove the notification after 25 seconds
    flutterLocalNotificationsPlugin.cancel(message.notification.hashCode);
    log('Notification removed after 25 seconds for call type.');
  }
}

Future<void> firebaseMessagingForegroundHandler(RemoteMessage message) async {
  if (message.data['type'] == 'call') {
    await audioPlayer.setAsset(
        'assets/ringtone/ringtone.mp3'); // Load the ringtone from assets
    audioPlayer.play();
  } else {
    showNotification(message);
  }
}
iamongit commented 1 month ago

Could you please format the issue for better readability? It's all over the place right now.

smithFlutter commented 1 month ago

same problem without solution.

BIBS23 commented 1 month ago

Could you please format the issue for better readability? It's all over the place right now.

i have formatted can you please tell me why it doesnt show in background when notification triggers. Currently it shows the defautl firebase notification only and flutter local notifications only working in foreground

BIBS23 commented 1 month ago

same problem without solution.

if you get any solution please mention I have tried many things