How to handle localNotifications when app is closed - ios

I've searched in all questions here but no solution worked.
I scheduled localNotifications with a userInfo option.
When app is in foreground, the notification arrived and a can handle perfectly with this function that system calls by itself.
For local notifications
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
if application.applicationState == .active {
return
}
//My implementation
}
For remote notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
if application.applicationState == .active {
return
}
//My implementation
}
But the problem is, when app is closed, this functions are not called and I can't handle the data that I need.
I've tried get userInfo in that function in appDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let localUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.localNotification] as? [AnyHashable: Any] {
// My implementation
} else if let remoteUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
// My implementation
}
return true
}
But.. Didn't work...
Someone could help me please?
Thanks in advance.

Have you registered for notifications?
In didFinishLaunchingWithOptions():
// Register Notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("User notifications are allowed")
} else {
print("User notifications are NOT allowed")
}
})
application.registerForRemoteNotification()
UNUserNotificationCenter.current().delegate = self
Then you should catch local notifications in UNUserNotificationCenterDelegate method:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
}

You will get the notification in didFinishLaunchingWithOptions if the user clicks it whether it's local or remote , otherwise you won't know except if store them in server and pull them every time you open the app

Related

Please implement -messaging:didReceiveRegistrationToken: to be provided with an FCM token

I am trying to put iOS push notifications onto my app. But keep getting the error
The object <FancyDeliveryManager.ViewController: 0x101910170> does not respond to -messaging:didReceiveRegistrationToken:. Please implement -messaging:didReceiveRegistrationToken: to be provided with an FCM token.
My app delegate looks like:
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window : UIWindow?
//private let pushNotificationHandler: PushNotificationHandler = PushNotificationHandler()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
//notification delegates
Messaging.messaging().delegate = self //enables recievieving of tokens
UNUserNotificationCenter.current().delegate = self
///
//set up nav controller
let root: UIViewController = ViewController()
let navigationController = UINavigationController(rootViewController: root)
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
return true
}
//MARK: Push Handling
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
guard granted else { return }
self?.getNotificationSettings()
}
}
//check the notification settings
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
// This method will be called when app received push notifications in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .badge, .sound])
}
//called when user interacts with push notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Launched from push notification")
completionHandler()
}
// This callback is fired at each app startup and whenever a new token is created.
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
saveFcmToken(token: fcmToken)
}
//save token in database
func saveFcmToken(token: String){
var ref: DatabaseReference!
ref = Database.database().reference()
guard let userID = Auth.currentUser else { return }
ref.child("WarehouseManagers/\(userID)/fcmToken").setValue(token)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
//default to delegate method below
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.newData)
}
// [END receive_message]
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)")
// With swizzling disabled you must set the APNs token here.
// Messaging.messaging().apnsToken = deviceToken
}
func applicationDidBecomeActive(_ application: UIApplication) {
UIApplication.shared.applicationIconBadgeNumber = 0
}
Is there something in the main ViewController that needs to be added here?
Any help would be greatly appreciated.

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

We are working on push notification. We need to call the web service when we get a notification in active, background, foreground and terminated. But when we terminated the app we get a notification but can’t able to call the web service. The reason for calling the web service is to identify the message was received for a mobile app.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if ( application.applicationState == .inactive || application.applicationState == .background ) {
**// Need to call API**
}
}
Is any other way to identify the message was delivered in mobile app in the server side?
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...
}
}
}
We have a option called silent notification check below link
https://medium.com/#m.imadali10/ios-silent-push-notifications-84009d57794c
Check the link below this is what you require.
https://samwize.com/2015/08/07/how-to-handle-remote-notification-with-background-mode-enabled/
You need to activate background mode for push notification. The full process is been explained in the above article.

Why I did not receive any notification on my iPhone?

Running this on Xcode8.3 with swift 3.1
Below is my code in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("OK!")
}
else {
print("No!")
}
})
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("==== didReceiveRemoteNotification ====")
print(userInfo)
}
I use node-apns to push notification to my app and I can have message from my Debug area in Xcode.
==== didReceiveRemoteNotification ====
[AnyHashable("id"): 123, AnyHashable("aps"): {
alert = "Hello World \U270c";
badge = 3;
}]
But, I did not receive any notification on my iPhone.
Did I missing something?
With iOS 10, you can do the following to see push notifications when the App is in Foreground. You have to implement the below function in AppDelegate. It's a delegate method of UNUserNotificationCenterDelegate.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
Follow the below steps:
Import UserNotifications and extend UNUserNotificationCenterDelegate in AppDelegate.
Set up the UNUserNotificationCenter delegate in didFinishLaunchingWithOptions.
let center = UNUserNotificationCenter.current()center.delegate = self
Implement the will present method in AppDelegate and call the completion handler with the options.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert,.badge,.sound])
}
Now if you get a push, you can see the notification alert even if your app is in foreground. More Info in Apple Doc.
if you want to handle notifications, when your app is active, you should do something like this, because the push view won't appear
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if application.applicationState == .active {
//create custom view or something
} else {
//it was background/off
}
}
you might be also interested in creating new build schema, so your app will wait until it would be launched, so you can debug your app behaviour when receiving push.

Notification iOs Push delivered?

I recently set up notifications on my application, I can send via php and no worries, everything works fine.
Since last week, I am trying to find out if a push notification is received by the phone or not..
I can know when someone clicks on it but if the person does not click on it and prefer to open the application, it does not work..
Is there not a simple function that can tell me if a notification has just been received by the application ?
In my AppDelegate.swift :
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Check if launched from notification
if let notification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [String: AnyObject] {
//print(notification)
window?.rootViewController?.present(ViewController(), animated: true, completion: nil)
}
else{
//print("ici ?")
registerForRemoteNotification()
}
return true
}
...
//Called when a notification is delivered to a foreground app.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
//Called to let your app know which action was selected by the user for a given notification.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
...
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
**print("here ?")**
switch((application.applicationState)){
case UIApplicationState.inactive:
print("Inactive")
//Show the view with the content of the push
completionHandler(.newData)
case UIApplicationState.background:
print("Background")
//Refresh the local model
completionHandler(.newData)
default:
print("Active")
//Show an in-app banner
completionHandler(.newData)
break
}
}
}
Problem : I never pass in didReceiveRemoteNotification :/
The "print here" is never displayed.
I have a mistake on this line :
Instance method
'application(application:didReceiveRemoteNotification:fetchCompletionHandler:)'
nearly matches optional requirement
'application(_:didReceiveRemoteNotification:fetchCompletionHandler:)'
of protocol 'UIApplicationDelegate'
But I do not understand :/
Do you have an idea ?
Thx for your help ^^
It's rather common mistake since the conversion to Swift 3 - you're using Swift 2 method.
The right signature of this method in Swift 3 is:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("here?")
}

Get data from payload when remote push notification arrive while my app is in background or closed

I need to capture data from payload when recive a remote push notification, on IOS 9 i did this using the func:
didReceiveRemoteNotification
On IOS 10 using swift 3.0 i've implemented this 2 functions.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
print("\(notification.request.content.userInfo)")
completionHandler([.alert, .badge, .sound])
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
print("User Info = ",response.notification.request.content.userInfo)
completionHandler()
}
the second fuction only executes when the user touch the push
i need capture data when a push notification arrives while my app is in background or even closed.
Regards.
greetings
When a push notification is received and your app isn't running, you need to implement your notification logic in didFinishLaunchingWithOptions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Called when a notification is tapped and the app wasn't running, not in foreground neither in background.
if let userInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [String: AnyObject]{
// your logic here!
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Capture payload here something like:
let appState = userInfo["appState"] as? String
print(appState!)
// Do something for every state
if (application.applicationState == UIApplicationState.active){
print("Active")
}else if (application.applicationState == UIApplicationState.background){
print("Background")
}else if (application.applicationState == UIApplicationState.inactive){
print("Inactive")
}
completionHandler(.noData)
}
try with the didReceiveRemoteNotification function in iOS10:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print(userInfo)
}

Resources