FCM iOS push notification capture custom data when app is terminated?

Viewed 8

i am working on e-commerce mobile app, of course i need to send push notifications with a specific order number or product , so once user click on the push notification it shall handle the custom data sent with push notification to open the product or order page.

so my issue is , when the application is fully terminated i am not able to capture the custom data i've sent from server, the push notification is received successfully but none of firebase delegates are triggered when app is terminated . unlike the foreground , when app is in foreground and user clicks on the push notification i am able to handle the custom data and able to open the product / order page .

any idea why i am not able to capture push notification when app is terminated and user clicked on the push to open the app ?

PHP Code (Backend) :

$msg = array
(
    'body'      => $push['text'],
    'title'     => $push['title'],
    'sound'     => 'default',
    'vibrate'   => 1,
    'largeIcon' => 'large_icon',
    'smallIcon' => 'small_icon'
);

$push['params'] = @json_decode($push['params']) ? json_decode($push['params']) : array();


$fields = array
(
    'registration_ids'  => array_values($push['tokens']),
    'notification'      => $msg,
    'data'       => $push['params'] 
);


$data_string = json_encode($fields);
                                    
$headers = array ( 'Authorization:key =' . $api, 'Content-Type: application/json' );
$ch = curl_init(); curl_setopt( $ch,CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send' );
curl_setopt( $ch,CURLOPT_POST, true );
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch,CURLOPT_POSTFIELDS, $data_string);
$result = curl_exec($ch);


curl_close ($ch);

Swift Code (App delegate extension which handle everything for push ) :

import Foundation
import FirebaseCore
import FirebaseMessaging

extension APP_delegate {
    
    public func registerForPushNotification(){
        
        // [START set_messaging_delegate]
        Messaging.messaging().delegate = self
        // [END set_messaging_delegate]
        // Register for remote notifications. This shows a permission dialog on first run, to
        // show the dialog at a more appropriate time move this registration accordingly.
        // [START register_for_notifications]
        if #available(iOS 10.0, *) {
          // For iOS 10 display notification (sent via APNS)
          UNUserNotificationCenter.current().delegate = self

          let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
          UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { (granted, error) in
                if granted {
                    // Register after we get the permissions.
                    UNUserNotificationCenter.current().delegate = self
                }
            }
          )
        } else {
          let settings: UIUserNotificationSettings =
            UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
           
            LW_APP.shared.appDelegate.application.registerUserNotificationSettings(settings)
        }

        LW_APP.shared.appDelegate.application.registerForRemoteNotifications()
    }
    
    
    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
      print("Unable to register for remote notifications: \(error.localizedDescription)")
    }


    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      print("APNs token retrieved: \(deviceToken)")
       Messaging.messaging().apnsToken = deviceToken
    }
    
}

// [START ios_10_message_handling]
@available(iOS 10, *)
extension APP_delegate: UNUserNotificationCenterDelegate {
    
    // [START receive_message]
     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
       // If you are receiving a notification message while your app is in the background,
       // this callback will not be fired till the user taps on the notification launching the application.
       // TODO: Handle data of notification
       // With swizzling disabled you must let Messaging know about the message, for Analytics
       Messaging.messaging().appDidReceiveMessage(userInfo)
       print("[FCM][1] \(userInfo)")
         
         UserDefaults.standard.set("asd", forKey: "pushData")
         UserDefaults.standard.synchronize()
         NotificationCenter.default.post(name: .pushAction, object: nil)
     }

     func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                      fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        Messaging.messaging().appDidReceiveMessage(userInfo)
       // Print full message.
        print("[FCM][2] \(userInfo)")
         
         UserDefaults.standard.set("asd", forKey: "pushData")
         UserDefaults.standard.synchronize()
         NotificationCenter.default.post(name: .pushAction, object: nil)

       completionHandler(UIBackgroundFetchResult.newData)
     }
    
    
      // Receive displayed notifications for iOS 10 devices.
      func userNotificationCenter(_ center: UNUserNotificationCenter,
                                  willPresent notification: UNNotification,
                                  withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions)
                                    -> Void) {
          
            let userInfo = notification.request.content.userInfo

            // With swizzling disabled you must let Messaging know about the message, for Analytics
             Messaging.messaging().appDidReceiveMessage(userInfo)
            // [START_EXCLUDE]
            // Print message ID.
            if let messageID = userInfo["gcm.message_id"] {
              print("Message ID (1) : \(messageID)")
            }
          
          UserDefaults.standard.set("asd", forKey: "pushData")
          UserDefaults.standard.synchronize()
          NotificationCenter.default.post(name: .pushAction, object: nil)
      
          completionHandler([[.badge, .sound]])
      }

      func userNotificationCenter(_ center: UNUserNotificationCenter,
                                  didReceive response: UNNotificationResponse,
                                  withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo

        // [START_EXCLUDE]
        // Print message ID.
    //    if let messageID = userInfo["gcm.message_id"] {
    //      print("Message ID (2) : \(messageID)")
    //    }
          

    //      if let aps:[String:Any] = userInfo["aps"] as? [String:Any] {
    //          //The message
    //          print("Alert Data =>  \(aps)")
    //      }
          
          UserDefaults.standard.set("asd", forKey: "pushData")
          UserDefaults.standard.synchronize()
          NotificationCenter.default.post(name: .pushAction, object: nil)
          
          if let custom_data:String = userInfo["gcm.notification.data"] as? String {
             // The custom Data comes as json string need to decode it
             // Env.pushData =  Tools.fromJson(custom_data)
              NotificationCenter.default.post(name: .pushAction, object: nil)
          }
      
        // [END_EXCLUDE]
        // With swizzling disabled you must let Messaging know about the message, for Analytics
         Messaging.messaging().appDidReceiveMessage(userInfo)
      
         completionHandler()
      }
    
    }

    // [END ios_10_message_handling]
    extension APP_delegate: MessagingDelegate {
      // [START refresh_token]
      func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("Firebase registration token: \(String(describing: fcmToken))")
          
          if  Env.sharedInstance.pushToken != fcmToken {
              Env.sharedInstance.pushToken = fcmToken ?? ""
              LW_APP.api.register_push_token(nil) { _ in }
          }
      
          print("Firebase registration token: \( Env.sharedInstance.pushToken )")
          NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: ["token": fcmToken ?? ""])

      }

}

PS : When app is not terminated i am able to get the custom data inside the push notification when user clicks on the push notification using this method . unlike the background issue when app fully terminated.

  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              didReceive response: UNNotificationResponse,
                              withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo

      UserDefaults.standard.set("asd", forKey: "pushData")
      UserDefaults.standard.synchronize()
      NotificationCenter.default.post(name: .pushAction, object: nil)
      
      if let custom_data:String = userInfo["gcm.notification.data"] as? String {
         // The custom Data comes as json string need to decode it
         // Env.pushData =  Tools.fromJson(custom_data)
          NotificationCenter.default.post(name: .pushAction, object: nil)
      }
  
    // [END_EXCLUDE]
    // With swizzling disabled you must let Messaging know about the message, for Analytics
     Messaging.messaging().appDidReceiveMessage(userInfo)
  
     completionHandler()
  }

i am stuck in this case for weeks , any advice much appreciated.

0 Answers
Related