My application is implementing Firebase Cloud messaging to send notifications. Whenever I use the Firebase console to test the Firebase Notifications, the notifications are being handled by userNotificationCenter functions will present and didReceiveRemoteNotification and not by the Firebase applicationReceivedRemoteMessage function, am I missing something? Also, the userNotification functions do not have any data when I try to print the notification that just came from Firebase. here is my set up:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, FIRMessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
FIRMessaging.messaging().remoteMessageDelegate = self
FIRApp.configure()
registerForFireBaseNotifications()
//Other set up variables
connectToFcm()
return true
}
func registerForFireBaseNotifications(){
let authOptions: UNAuthorizationOptions = [.alert, .sound, .badge]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: {_, _ in })
application.registerForRemoteNotifications()
}
func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
print("Recieved remote firebase notification: %#", remoteMessage.appData)
}
func tokenRefreshNotification(notification: NSNotification) {
let refreshedToken = FIRInstanceID.instanceID().token()
print("FCM: Connected to FCM. Token : \(String(describing: refreshedToken))")
connectToFcm()
}
func connectToFcm() {
// Won't connect since there is no token
guard FIRInstanceID.instanceID().token() != nil else {
print("FCM: Token does not exist.")
return
}
// Disconnect previous FCM connection if it exists.
FIRMessaging.messaging().disconnect()
FIRMessaging.messaging().connect { (error) in
if error != nil {
print("FCM: Unable to connect with FCM. \(error.debugDescription)")
} else {
print("Connected to FCM.")
}
}
}
//Non firebase notifications
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
//do something with notifications that came while on foreground
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//do something with notifications that came from background
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.sandbox)
}
I was able to keep digging and found the answer that I was looking for. For anybody that is struggling with this and understanding how the Firebase notifications work with IOS. The code above for the set up is correct. The main issue that I was having was that notification were not being addressed through the Firebase function applicationReceivedRemoteMessage. This was incorrect from my understanding! Firebase console allows you to send messages as notifications only! which means your app will get the notification through apns! If you want to fire the applicationReceivedRemoteMessage function you need to send a message as a data json object. Which you can do so through postman look more here: Unable to send data message using firebase console . Hope this helps!
Related
Last night I was testing Push Notifications from Firebase in my iOS app, and it was working as expected
I was able to send a notification from at Cloud Function to a specific FCM token.
This morning notification doesn't arrive when using the same method.
Cloud Function
Here's the function that I use to send the notification:
function sendNotification(title: string, body: string, token: string): Promise<void> {
const message: admin.messaging.Message = {
apns: {
headers: {
'apns-priority': '10'
},
payload: {
aps: {
alert: {
title: title,
body: body,
},
sound: "default"
}
}
},
token: token
}
return admin.messaging().send(message).then(response => { console.log(`Notification response ${response}`) }).then(justVoid)
}
Here token is the token I received from the InstanceId in the iOS app.
When this function is triggered, I see the following in Firebase web console's Cloud Function log:
Notification response projects/project-name/messages/0:1571998931167276%0f7d46fcf9fd7ecd
Which, as far as I understand, is a success message. So I'm expecting the notification to show up on the device at this point, but nothing.
iOS App
I've followed this guide to troubleshoot, and am sure that the setup is right: https://firebase.google.com/docs/cloud-messaging/ios/first-message?authuser=0
I did try to re-install the app on the device on which Im testing: I've verified that the app does through these step after re-install:
call: UNUserNotificationCenter.current().requestAuthorization(options:, completionHandler:)
call: UIApplication.shared.registerForRemoteNotifications()
listen to updated FCM token by implementing: func messaging(_ messaging:, didReceiveRegistrationToken fcmToken:)
call: InstanceID.instanceID().instanceID(handler:)
double check that notifications is allowed for my application in the iOS settings app.
Test Notification from console
I've tried sending a Test Notification in from Notification Composer, using a the recent FCM token for the test device, but this notification doesn't show up either, and it doesn't give me any feedback on screen whether the notification is successfully sendt or not.
What am I doing wrong here?
Any Suggestions to how I can debug this issue?
When we are working with Push Notification then it is very harder to debug issue.
As per my experience, there is nothing wrong with your typescript or iOS code because earlier it was worked perfectly. Below is the possible reason if the push notification is not working.
Generally, the APNS related issue occurs due to the certificate.
Make sure you are uploading the correct APNS profile to the firebase
console for both development and release mode.
Make sure you have enabled the notification in capabilities.
Your Project -> capabilities -> turn on Push Notifications
Make sure you're added correct GoogleService-Info.plist to the
project.
APNS Certificate is not expired.
Make sure you're using the latest version of the firebase.
Your device time should be automatic, not feature time.
If you still think it is code related issue and the above solution is not working then you can go with the below wrapper class of HSAPNSHelper class which is created by me and it is working for iOS 10 and later .
import Foundation
import UserNotifications
import Firebase
class HSAPNSHelper: NSObject {
static let shared = HSAPNSHelper()
let local_fcm_token = "local_fcm_token"
var notificationID = ""
func registerForPushNotification(application:UIApplication){
FirebaseApp.configure()
self.getFCMToken()
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
DispatchQueue.main.async {
self.getFCMToken()
}
}
application.registerForRemoteNotifications()
}
}
extension HSAPNSHelper:UNUserNotificationCenterDelegate {
fileprivate func getFCMToken() {
InstanceID.instanceID().instanceID(handler: { (result, error) in
if error == nil, let fcmToken = result?.token{
print("FCM Token HS: \(fcmToken)")
UserDefaults.standard.set(fcmToken, forKey: self.local_fcm_token)
}
})
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("didFailToRegisterForRemoteNotificationsWithError : \(error)")
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var token = ""
for i in 0..<deviceToken.count {
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
Messaging.messaging().apnsToken = deviceToken
getFCMToken()
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo as! [String: Any]
print(userInfo)
completionHandler([.alert, .badge, .sound])
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print(userInfo)
self.notificationRedirection()
}
private func notificationRedirection(){
}
func fcmToken() -> String{
return UserDefaults.standard.string(forKey:local_fcm_token) ?? ""
}
}
How to use?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//For Push notification implementation
HSAPNSHelper.shared.registerForPushNotification(application: application)
return true
}
Use fcmToken() to get current FCM token.
I have a problem with FCM push notifications.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Swift.Void)
and
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Swift.Void)
are not called when I receive a push. The notification is generated in my iPhone.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
is called instead but I don't understand why because it's deprecated.
The content of my notification:
{
"to": "FCM Token",
"priority": "high",
"content_available": true,
"notification": {
"sound": "default",
"title": "Test",
"body": "Test",
"description": "Test"
},
"data": {
"id": 123456,
"status": "11",
}
}
In my AppDelegate.swift:
import UIKit
import CoreData
import Firebase
import Fabric
import Crashlytics
import GoogleMaps
import GooglePlaces
import FBSDKLoginKit
import GoogleSignIn
import NotificationBannerSwift
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
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
Messaging.messaging().shouldEstablishDirectChannel = true
return ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func applicationWillResignActive(_ application: UIApplication) {
pprint(" - applicationWillResignActive - ")
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
AppEvents.activateApp()
}
func applicationDidEnterBackground(_ application: UIApplication) {
pprint(" - applicationDidEnterBackground - ")
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
pprint(" - applicationWillEnterForeground - ")
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
pprint(" - applicationDidBecomeActive - ")
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
pprint(" - applicationWillTerminate - ")
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
private func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
pprint("apns token: ", deviceToken)
Messaging.messaging().apnsToken = deviceToken as Data
}
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.
print(" ")
print("-- New message classique --")
print("Notification received : \(userInfo)")
print(" ")
// Print full message.
print(userInfo)
completionHandler(.noData)
}
// MARK: - UNUserNotificationCenterDelegate methods
extension AppDelegate: UNUserNotificationCenterDelegate {
// FOREGROUND: The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Swift.Void) {
DispatchQueue.main.async {
// print("will present: ", notification)
// Messaging.messaging().appDidReceiveMessage(notification.request.content.userInfo)
// completionHandler(.alert)
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.
print(" ")
print("Notification received : \(notification)")
print("-- New message from Notification ios10 only --")
print(" ")
guard
let aps = userInfo[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String,
let title = alert["title"] as? String
else {
// handle any error here
return
}
print("Title: \(title) \nBody:\(body)")
let banner = NotificationBanner(title: title, subtitle: body, style: .success)
banner.show()
// Change this to your preferred presentation option
//completionHandler([])
}
}
// BACKGROUND: The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Swift.Void) {
DispatchQueue.main.async {
print("didReceive")
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo["gcmMessageIDKey"] {
print("Message ID: \(messageID)")
}
print(userInfo)
if let body = userInfo["body"] as? String {
print("inbody")
NotificationCenter.default.post(name: Notification.Name("userInfo"), object: body)
}
//Push().handlePush(info: userInfo)
// Print full message.
print(userInfo)
Messaging.messaging().appDidReceiveMessage(response.notification.request.content.userInfo)
completionHandler()
}
}
}
// MARK: - MessagingDelegate methods
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
//log.info("FCM registration token received = \(fcmToken)")
print("FCM registration token received = \(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) {
//log.info("didReceive message = \(remoteMessage)")
print("didReceive message = \(remoteMessage)")
}
func applicationReceivedRemoteMessage(_ remoteMessage: MessagingRemoteMessage) {
print(" - - - FIR Remote message - - - ")
print("%#", remoteMessage.appData)
//Push().handlePush(info: remoteMessage.appData)
}
}
In my Info.plist I have FirebaseAppdelegateProxyEnable set to NO
In capabilities, I have Push Notifications enabled and Remote Notifications are enabled too in Background Mode.
I'm using Xcode 11.1. I have converted my project to Swift 5 (it was created with Swift 3), I have changed the build system to the new one.
I have two targets with this project I don't know if it can be related to my issue.
I try with an empty new project with the same AppDelegate.swift, same bundle identifier and it works.
try this
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// put your code here
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// put your code here
}
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.
I need to handle push notification and that's done with a lower version of ios but in ios 11 never receive any push notification. I using Firebase Cloud Messaging. please, anyone has a solution then please share.
Please Check as
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Use Firebase library to configure APIs
FirebaseApp.configure()
self.registerForPushNotifications(application: application)
Messaging.messaging().delegate = self
if let token = InstanceID.instanceID().token() {
NSLog("FCM TOKEN : \(token)")
DataModel.sharedInstance.onSetUserFCMStringToken(FCM: token)
self.connectToFcm()
}
if launchOptions != nil {
//opened from a push notification when the app is closed
_ = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] ?? [AnyHashable: Any]()
}
else {
//opened app without a push notification.
}
return true
}
#available(iOS 10, *)
extension AppDelegate: UNUserNotificationCenterDelegate {
// iOS10+, called when presenting notification in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
NSLog("[UserNotificationCenter] willPresentNotification: \(userInfo)")
//TODO: Handle foreground notification
completionHandler([.alert])
}
// iOS10+, called when received response (default open, dismiss or custom action) for a notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
NSLog("[UserNotificationCenter] didReceiveResponse: \(userInfo)")
//TODO: Handle background notification
completionHandler()
}}
extension AppDelegate : MessagingDelegate {
//MARK: FCM Token Refreshed
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
NSLog("[RemoteNotification] didRefreshRegistrationToken: \(fcmToken)")
}
// Receive data message on iOS 10 devices while app is in the foreground.
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
NSLog("remoteMessage: \(remoteMessage.appData)")
}}
//Register for push notification.
func registerForPushNotifications(application: UIApplication) {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert,.sound]) { (granted, error) in
if error == nil{
DispatchQueue.main.async(execute: {
application.registerForRemoteNotifications()
})
}
}
}
else {
let settings = UIUserNotificationSettings(types: [.alert,.sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
// Add observer for InstanceID token refresh callback.
NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification), name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
}
#objc func tokenRefreshNotification(_ notification: Notification) {
print(#function)
if let refreshedToken = InstanceID.instanceID().token() {
NSLog("Notification: refresh token from FCM -> \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
func connectToFcm() {
// Won't connect since there is no token
guard InstanceID.instanceID().token() != nil else {
NSLog("FCM: Token does not exist.")
return
}
Messaging.messaging().shouldEstablishDirectChannel = true
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NSLog("Notification: 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 InstanceID token.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
// iOS9, called when presenting notification in foreground
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
NSLog("didReceiveRemoteNotification for iOS9: \(userInfo)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
}
Problem seems to be with
FirebaseInstanceID Version less than 1.0.9
FirebaseInstanceID Version between 2.0.1 - 2.0.3
Set your pod file as below :
For Swift 2.3 and Xcode 8 : (FirebaseInstanceID v1.1.0 gets installed)
pod 'Firebase/Core', '3.8.0'
pod 'Firebase/Messaging'
For Swift 3 and Xcode 9 :
pod 'Firebase/Core'
pod 'Firebase/Messaging'
pod 'FirebaseInstanceID', "2.0.0
I didn't want to upgrade to FirebaseInstanceID 2.0.0 to fix the issue as I wanted use Swift 2.3 only
I had the same problem, the issue was I was missing my APN configuration in firebase console.
I've got FCM working, but I can't get the traditional banner notifications working.
Here's what I have in my AppDelegate.swift file:
import UIKit
import Firebase
import UserNotifications
#UIApplicationMain
final class AppDelegate: UIResponder {
var window: UIWindow?
override init() {
super.init()
FIRApp.configure()
}
}
// MARK: - UIApplicationDelegate
extension AppDelegate: UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { _, _ in })
UNUserNotificationCenter.current().delegate = self
FIRMessaging.messaging().remoteMessageDelegate = self
application.registerForRemoteNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(tokenRefreshNotification), name: .firInstanceIDTokenRefresh, object: nil)
return true
}
func tokenRefreshNotification(notification: Notification) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
}
connectToFcm()
}
func connectToFcm() {
FIRMessaging.messaging().connect { error in
if error != nil {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
}
}
func applicationDidBecomeActive(_ application: UIApplication) {
connectToFcm()
}
}
// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
print("Message ID: \(userInfo["gcm.message_id"]!)")
print(userInfo)
completionHandler([.alert, .sound])
}
}
// MARK:
extension AppDelegate: FIRMessagingDelegate {
func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
print("FIRMessagingRemoteMessage Received: \(remoteMessage.appData)")
}
}
Everything is configured according to the documentation. I'm getting console outputs when I send messages to my app via the notifications console on Firebase.
However, banners don't appear when notifications are sent. When the app is backgrounded, notifications don't appear to be sent either - only when the app is in the foreground.
Looking for help. Thanks in advance!
Try disabling method swizzling.
Add FirebaseAppDelegateProxyEnabled to info.plist and set it to NO.
Then add this code to the app delegate
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenTypeSandbox)
}
Delete your app from the device and reinstall it.
please test if application:didRegisterForRemoteNotificationsWithDeviceToken is called. If its called, now try sending a notification from the firebase console.