Handling Push Notifications When App Is Terminated

Handle tap on local notification when app is terminated - iOS - Swift

When you tap on Push Notification on Notification Center.
OS launches your app (terminated before) then STILL delivers the action to this (Function 1)

func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
)

You can get the notification object from response like what you did.
But you may need to save temporary this data from the selected push notification, then handle it later when app is completely active with user.

Remember to call completionHandler() when you finish your logic. And, you must set UNUserNotificationCenter.current().delegate = self, before you return true in

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool`.

self here is your AppDelegate, which means you set UserNotification's delegate to a live object or initialized object.
It will be able to handle the above delegate function call (Function 1) to get your selected push notification's data.

How to handle push notification when app is not running/app is terminated

If the app is not running (killed state) , you can't execute any methods or code , only if the user clicks the push notification you can receive object of it in didFinishLaunchingWithOptions launchingOptions and handle it ....

How to call API when app is terminated in push notifcation iOS Swift?


As per Apple guidelines, you can get push notification for the background as well as on foreground state but when it comes to
Terminate state apple don't allow you to automatically open the app or
do any kind of operation unless you launch the app through notification.

Though you can handle notification during the Terminated state using Launch Options at the time of app launch.

Coding Example:

In your AppDelegate.swift import firebase library

import Firebase
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications

Whenever app launch register for push notification service, add the following lines of code into your didFinishLaunchingWithOptions

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
registerForPushNotifications(application: application)
handleNotificationWhenAppIsKilled(launchOptions)
return true
}

func handleNotificationWhenAppIsKilled(_ launchOptions: [UIApplicationLaunchOptionsKey: Any]?) {
// Check if launched from the remote notification and application is close
if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
// Handle your app navigation accordingly and update the webservice as per information on the app.
}
}

Add extension methods of appDelegate to register for remote notification and to get device token from APNS

//MARK: - Notifications related...
extension AppDelegate {
func registerForPushNotifications(application: UIApplication) {
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: {_, _ in })
// For iOS 10 data message (sent via FCM
Messaging.messaging().delegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}

application.registerForRemoteNotifications()
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
let savedAPNSToken = UserDefaults.standard.object(forKey: "savedAPNSToken") as? String
if savedAPNSToken != token {
UserDefaults.standard.set(token, forKey: "savedAPNSToken")
UserDefaults.standard.synchronize()
Messaging.messaging().apnsToken = deviceToken
}
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error.localizedDescription)
}

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

}

Use the following methods of notificationCenter to handle notification in the foreground and background states :

// MARK: - UNUserNotificationCenterDelegate
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

// 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
completionHandler([.alert])
}


/// Handle tap on the notification banner
///
/// - Parameters:
/// - center: Notification Center
/// - response: Notification response
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {

let userInfo = response.notification.request.content.userInfo
completionHandler()
}

Firebase token renewel:

extension AppDelegate : MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
// Note: This callback is fired at each app startup and whenever a new token is generated.
let savedFCMToken = UserDefaults.standard.object(forKey: "savedFCMToken") as? String
if savedFCMToken != fcmToken {
UserDefaults.standard.set(fcmToken, forKey: "savedFCMToken")
UserDefaults.standard.synchronize()
// Update FCMToken to server by doing API call...
}
}
}

Handling Push Notifications when App is Terminated

As per your question, there is no way to hold all the notification when you open the app, better you call an api to get all notification as per time stamp from your back end/server that's how Facebook does.

Handle Notifications when app is terminated(iOS)

Have you tried using getDeliveredNotifications(completionHandler:)? You can call the following code in e.g. the viewDidLoad method of the controller in which you display the received notifications.

Note that if the user clears the received notifications in the notification center this won't work. You'll have to do as mentioned in the accepted answer of the question you linked in your comment.

UNUserNotificationCenter.current().getDeliveredNotifications { notifications in

// notifications: An array of UNNotification objects representing the local
// and remote notifications of your app that have been delivered and are still
// visible in Notification Center. If none of your app’s notifications are
// visible in Notification Center, the array is empty.

// As said in the documentation, this closure may be executed in a background
// thread, so if you want to update your UI you'll need to do the following:
DispatchQueue.main.sync { /* or .async {} */
// update UI
}
}

Firebase push notifications callback doesn't work when app is terminated

I resolved this by using the .getInitialMessage() function (This is the callback if the app is terminated.
My notifications worked when the app was on background but not terminated.

To resolve this I just added this to my code:

FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
if (message != null) {
Navigator.pushNamed(context, message.data['view']);
}
});

I've made a working demo here



Related Topics



Leave a reply



Submit