I'm using FCM server for remote notifications, it worked perfectly with sending and receiving notifications.
My problem is when the device is in the background, this function func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) doesn't called.
Solutions that I've tried:
This function:
userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
is called when user tapped on the notification. Otherwise, it's not triggered.
Adding "content-available": true, "priority": "high" to the payload. Also, I tried this value "content-available": 1.
This is my function code:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("userInfo: \(userInfo)")
completionHandler(.newData);
}
Just adding on accepted answer: in my case the problem was the same, but as I'm sending the Notification through an http "POST" NSMUtableRequest the way to apply the accepted answer was to actually add it in the notification parameters together with sound, badge, tiles etc etc..
let postParams: [String : Any] = [
"to": receiverToken,
"notification": [
"badge" : 1,
"body": body,
"title": title,
"subtitle": subtitle,
"sound" : true, // or specify audio name to play
"content_available": true, // this will call didReceiveRemoteNotification in receiving app, else won't work
"priority": "high"
],
"data" : [
"data": "ciao",
]
]
Hope this will also help others, as I spent a long time trying to figure out how to apply this solution.
Many thanks.
If you are testing with Postman then try changing "content-available": true to "content_available" : true. content-available will send notification but it doesn't call didReceiveRemoteNotification.
All you need to see remote notification in background and foreground and show as alert when app run are this appDelegate.swift that i used in my code:
import Firebase
import UserNotifications
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm_message_id"
var deviceID : String!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// [START set_messaging_delegate]
Messaging.messaging().delegate = self
// [END set_messaging_delegate]
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 })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
Fabric.sharedSDK().debug = true
return true
}
func showNotificationAlert(Title : String , Message : String, ButtonTitle : String ,window : UIWindow){
let alert = UIAlertController(title: Title, message: Message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: ButtonTitle, style: .cancel, handler: nil))
window.rootViewController?.present(alert, animated: true, completion: nil)
}
// [START receive_message] remote notification
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
// This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
// the FCM registration token.
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
}
}
// [START ios_10_message_handling]
#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
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
if let aps = userInfo["aps"] as? NSDictionary {
if let alert = aps["alert"] as? NSDictionary {
if let title = alert["title"] as? NSString {
let body = alert["body"] as? NSString
showNotificationAlert(Title: title as String, Message: body! as String, ButtonTitle: "Ok", window: window!)
}
} else if let alert = aps["alert"] as? NSString {
print("mohsen 6 =\(alert)")
}
}
// Print full message.
print(userInfo)
completionHandler()
}
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
// [START refresh_token]
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
deviceID = fcmToken
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
// [END ios_10_data_message]
}
The first thing you need to check is the Background Mode > Remote Notification is on. If not, it will not be invoked in the background mode.
Step 1 – Add framework
import UserNotifications
Step 2 – Inherit AppDelegate with UNUserNotificationCenterDelegate
final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {}
Step 3 – Make appropriate changes for registerPushNotifications and call it didFinishLaunchingWithOptions
private func registerPushNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.currentNotificationCenter().delegate = self
UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions([.Badge, .Sound, .Alert], completionHandler: { granted, error in
if granted {
UIApplication.sharedApplication().registerForRemoteNotifications()
} else {
// Unsuccessful...
}
})
} else {
let userNotificationTypes: UIUserNotificationType = [.Alert, .Badge, .Sound]
let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
}
Step 4 – Implement new handlers
// leave this for older versions
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
}
// For iOS10 use these methods and pay attention how we can get userInfo
// Foreground push notifications handler
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
if let userInfo = notification.request.content.userInfo as? [String : AnyObject] {
// Getting user info
}
completionHandler(.Badge)
}
// Background and closed push notifications handler
#available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
if let userInfo = response.notification.request.content.userInfo as? [String : AnyObject] {
// Getting user info
}
completionHandler()
}
As you tried i believe every thing , background permission is enable , content-available is the part of payload, you are also receiving notification in active state, last thing will be Power save mode, you need to check is power saving is off; as if you Phone is in power saving mode, then background refresh and other process is gone in limited state, so app will not call didReceivedNotifcation in background.
Related
So I'm trying to implement Cloud Messaging with Firebase Functions for a message center in my app. My firebase function says it is already working and I do receive the message in my console log, however, the notification is not being deployed in my phone on background mode.
I've implemented the permission to receive notifications once my user is logged in in Home View. This is my code:
func askNotificationPermission() {
//Firebase Push Notifications
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in
print("HOLA TE DIERON PERMISO")
})
Messaging.messaging().shouldEstablishDirectChannel = true
UIApplication.shared.registerForRemoteNotifications()
Messaging.messaging().delegate = self
}
I've implemented the necessary Firebase functions in didFinishLaunchingApplication:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//MARK: Firebase
FirebaseApp.configure()
//Firebase Cloud Messaging
Messaging.messaging().delegate = self
//MARK: Others
//KeyboardManager
IQKeyboardManager.shared.enable = true
//navbar
let navControl = UINavigationBar.appearance()
let myColor : UIColor = UIColor(red: 0, green: 0.1333, blue: 0.3176, alpha: 1)
navControl.tintColor = myColor
return true
}
And this is my extension for the Notifications within App Delegate:
extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate {
func applicationDidEnterBackground(_ application: UIApplication) {
Messaging.messaging().shouldEstablishDirectChannel = true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
let dataDict: [String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
//TODO: If necessary send token to application server
//Note: This callback is fired at each app startup and whenever a new token is generated
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
Messaging.messaging().appDidReceiveMessage(userInfo)
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print("USER INFO: ",userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
print("USER INFO IN DID RECEIVE REMOTE NOTIFICAITON:", userInfo, UIBackgroundFetchResult.newData)
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo as! [String:Any]
completionHandler([.alert, .badge, .sound])
print("HOLI")
}
}
I don't know what might be the problem and why I am receiving the information in the console but it is not being pushed to the app. I've searched through several stackoverflow questions but none have worked.
This is what my console logs:
2020-08-06 11:06:06.804344-0500 FleaMarket_UserSide[13985:4429211] [] nw_read_request_report [C2] Receive failed with error "Software caused connection abort"
[AnyHashable("title"): Jay Shetty Meditations, AnyHashable("aps"): {
"content-available" = 1;
}, AnyHashable("gcm.message_id"): 1596729966264394, AnyHashable("message"): did you get it?, AnyHashable("google.c.sender.id"): 520471783461]
USER INFO IN DID RECEIVE REMOTE NOTIFICAITON: [AnyHashable("title"): Jay Shetty Meditations, AnyHashable("aps"): {
"content-available" = 1;
}, AnyHashable("gcm.message_id"): 1596729966264394, AnyHashable("message"): did you get it?, AnyHashable("google.c.sender.id"): 520471783461] UIBackgroundFetchResult
2020-08-06 11:06:06.835793-0500 FleaMarket_UserSide[13985:4429216] 6.27.0 - [Firebase/Firestore][I-FST000001] WatchStream (282c75618) Stream error: 'Unavailable: Socket is not connected'
I found my error. It was in my firebase function. I had written my payload incorrectly. I had written:
var newmessage = {
data: {
title: groupName,
body: message
},
topic: offerTopic,
};
The correct payload according to Firebase documentation is NOTIFICATION:
var newmessage = {
notification: {
title: groupName,
body: message
},
topic: offerTopic,
};
Make sure to stick to the firebase cloud message documentation found here, or it won't take it as a notification and won't push it.
https://firebase.google.com/docs/cloud-messaging/ios/topic-messaging
Push is being received while app is in the background killed by the user, when the user hits the push notification it opens the app and it doesn't crash but it is closed immediately.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// 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.
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
print("The userInfo is: \(userInfo)")
completionHandler(UIBackgroundFetchResult.newData)
}
The previous method is not even called, or may be it is but I don't know how to debug it, since the application is not running.
Here's the notification object that I send via the server:
apns: {
payload: {
aps: {
alert: {
title: messageObject.authorName,
body: messageObject.content,
},
sound: "notification.wav",
category: "ChatViewController"
}
}
}
That is what is send via the server. The notifications work when the application is in background and not killed, or when the application is in foreground.
I think so when user click on the notification while your application is killed or in background or foreground, below method would be executed. And you have to test it one by one.
First of all check that whether yo are able to see the popup as soon as the application runs when you click on notification. Just copy, paste this code in your AppDelegate Class and comment your didReceiveRemoteNotification method and then check whether your application crash or not.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
guard let object = response.notification.request.content.userInfo as? [String : AnyObject] else {
return
}
self.normalPopup()
}
/// Alert Popup, if user not exist in our database.
func normalPopup() {
let alert = UIAlertController(title: "Test", message: "Show pop up window.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
}))
self.window?.rootViewController?.present(alert, animated: true)
}
If popup window shows, then comment the normalPopup function and replace that function with below code. Then check whether your application crash or not while application killed.
Messaging.messaging().appDidReceiveMessage(userInfo)
Please Lemme know if you are still facing the same issue.
If you use firebase for that first you should define it on application(_ application:, didFinishLaunchingWithOptions:) like underneath:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
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 })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
FirebaseApp.configure()
return true
}
Also you can Handle notifications when app is ran, with this func:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if let messageID = userInfo["gcm.message_id"] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
and
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if let messageID = userInfo["gcm.message_id"] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
and you should set new token to Messaging with this method:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
let token = deviceToken.map { String(format: "%02.2hhx", $0)}.joined()
print(token)
}
at the end you can handle notifications with below extension
// [START ios_10_message_handling]
#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
if let messageID = userInfo["gcm.message_id"] {
print("Message ID: \(messageID)")
}
//*************************
// Handle push notification message automatically when app is running
//*************************
print(userInfo)
// Change this to your preferred presentation option
completionHandler([[.alert, .sound]])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo["gcm.message_id"] {
print("Message ID: \(messageID)")
}
//*************************
// Handle push notification message after click on it
//*************************
print(userInfo)
completionHandler()
}
}
I have implemented push notification by firebase. Not able to get notifications from background. Having following code in my App delegate,
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
sleep(3)
IQKeyboardManager.shared.enable = true
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 })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
Messaging.messaging().delegate = self
Messaging.messaging().shouldEstablishDirectChannel = true
UIApplication.shared.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
Messaging.messaging().shouldEstablishDirectChannel = true
}
func applicationWillEnterForeground(_ application: UIApplication) {
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Message Data", remoteMessage.appData)
}
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 message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// 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 message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
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)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
And getting print for Message Data at did receive remote Notification
Message Data [AnyHashable("from"): 459345502087, AnyHashable("collapse_key"): www.rwdev.com.TravelSheriff2.1, AnyHashable("notification"): {
body = "Notifications ";
e = 1;
tag = "campaign_collapse_key_4509884114250587926";
title = "Travel Sheriff ";
}]
But I am not able to get push notifications while background and foreground. Even not getting "Message Data" print while app in background.
(Note:Please don't come up with previous stack overflow links and answers have already tried most of them..didnt work out..)
Hey #Aleesha use the request identifier.
I give you example down below follow the code, i hope its worked.
//MARK:- USER NOTIFICATION DELEGATE
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
print(notification.request.content.userInfo)
if notification.request.identifier == "rig"{
completionHandler( [.alert,.sound,.badge])
}else{
completionHandler([.alert, .badge, .sound])
}
}
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
//Handle the notification
completionHandler(
[UNNotificationPresentationOptions.alert,
UNNotificationPresentationOptions.sound,
UNNotificationPresentationOptions.badge])
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print(userInfo)
switch application.applicationState {
case .active:
let content = UNMutableNotificationContent()
if let title = userInfo["title"]
{
content.title = title as! String
}
if let title = userInfo["text"]
{
content.body = title as! String
}
content.userInfo = userInfo
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 0.5, repeats: false)
let request = UNNotificationRequest(identifier:"rig", content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(request) { (error) in
if let getError = error {
print(getError.localizedDescription)
}
}
case .inactive:
break
case .background:
break
}
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let token = Messaging.messaging().fcmToken
print("FCM token: \(token ?? "")")
}
In FCM notifications when a user clicks on notification it is redirecting to home page but I want to redirect to a specific page other than home page and the app is in foreground. When it was redirected to specific page the app should read the data in the notification and display the data on the page.
Here is the code that represent the above idea but it redirects to home page and nothing is happening(like display data).
My APPDelegate.class
import UIKit
import Firebase
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
Messaging.messaging().delegate = self as! MessagingDelegate
//Register for notification
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
return true
}
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 message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// 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 message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
// [END receive_message]
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
// This function is added here only for debugging purposes and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs token can be paired with
// the FCM registration token.
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
}
}
// [START ios_10_message_handling]
#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
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
// [START refresh_token]
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
// [END ios_10_data_message]
}
add this code inside didReceive Response method like that:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
let storyBoard: UIStoryboard = UIStoryboard(name: "yourStoryboardName", bundle: nil)
let presentViewController = storyBoard.instantiateViewController(withIdentifier: "yourViewControllerStoryboardID") as! YourViewController
presentViewController.yourDict = userInfo //pass userInfo data to viewController
self.window?.rootViewController = presentViewController
presentViewController.present(presentViewController, animated: true, completion: nil)
completionHandler()
}
Application not running
When app is in closed state you should check for launch option in didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
var viewController = UIViewController()
if (launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary) != nil {
viewController = storyBoard.instantiateViewController(withIdentifier: "storyboardIdentifier") // user tap notification
}else{
viewController = storyBoard.instantiateViewController(withIdentifier: "storyboardIdentifier") // User not tap notificaiton
}
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
Application in Foreground state Here you can redirect on specific viewcontroller
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print full message.
print(userInfo)
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let presentViewController = storyBoard.instantiateViewController(withIdentifier: "storyboardIdentifier") as! YourViewController
presentViewController.yourDict = userInfo //pass userInfo data to viewController
self.present(presentViewController, animated: true, completion: nil)
completionHandler()
}
}
You have to implement two methods for handling the notification, one for when the app is in the background, and the other for when the app has been shut down and is not running.
Inside your AppDelegate, implement the application(_:didFinishLaunchingWithOptions:) -> Bool method. This is for when the app is not running:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
if let notificationData = launchOptions?[.remoteNotification] {
// Use this data to present a view controller based
// on the type of notification received
}
return true
}
When your app is in the background, you need to implement the userNotificationCenter(_:didReceive:withCompletionHandler:) method:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let notificationData = response.notification.request.content.userInfo
// Use this data to present a view controller based
// on the type of notification received
completionHandler()
}
I have problem when using FCM for iOS. I can only receive 1 notification per install, after that, iOS stated that my token is unregistered. Have tried to delete the token using InstanceID.instanceID().deleteToken and deleting instanceID using InstanceID.instanceID().deleteID but I still get the same unregistered token. I've also tried to send the notification from FCM console with the same result.
My code in AppDelegate:
let gcmMessageIDKey = "com.ucpmb"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
Messaging.messaging().shouldEstablishDirectChannel = true
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 })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("delegate", "FCM reg fail")
print("delegate", error.localizedDescription)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print("Message ID: \(userInfo["gcm.message_id"]!)")
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("Message ID: \(userInfo["gcm.message_id"]!)")
print(userInfo)
if userInfo["module"] as! String == "pmb_voucher" {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let centerViewController = storyBoard.instantiateViewController(withIdentifier: "PrePilihJurusanViewController") as! PrePilihJurusanViewController
window?.rootViewController = centerViewController
} else if (userInfo["module"] as! String == "pmb_result") {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let centerViewController = storyBoard.instantiateViewController(withIdentifier: "ResultTableViewController") as! ResultTableViewController
window?.rootViewController = centerViewController
}
completionHandler(UIBackgroundFetchResult.newData)
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
print(notificationSettings.types.rawValue)
}
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
print("Received Local Notification:")
print(notification.alertBody)
}
And for the AppDelegate extension:
#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
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
// [START refresh_token]
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
// [END ios_10_data_message]
}
I'm currently using Swift 4. Thank you for your help!