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.