FCM Push notifications do not work on iOS 11
It appears that with FirebaseInstanceID 2.0.3 push notifications don't work. It helped me to set: pod 'FirebaseInstanceID', "2.0.0".
Maybe in next version this will be fixed.
FCM Push notification not working in iOS 11
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) {
}
Firebase FCM push notifications stopped working iOS 11.1.1
Ok, fixed it. I disable firebase's message swizzling by adding this to my Info.plist: FirebaseAppDelegateProxyEnabled: NO
Further I removed all firebase messaging delegate methods. And generated my own APN token in didRegisterForRemoteNotificationsWithDeviceToken and setting Messaging.messaging().apnsToken = deviceToken in the didRegisterForRemoteNotificationsWithDeviceToken method once token generated.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let refreshedToken = InstanceID.instanceID().token() {
defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)
Messaging.messaging().apnsToken = deviceToken
print("Token generated: ", refreshedToken)
} else {
print("Could not save token becuase error with instance id token")
}
}
Previously I used the firebase swizzling, it appears as if this stopped working for some reason.
As this was a tough experience for me, I would like to post the steps that I would now reccommend to enable iOS client for FCM:
- In the Apple Developer console generate your APN and then select APNs. Select Continue and download your APN certificate. Take note of your Key ID.
Then in the firebase console under settings, cloud messaging, upload your APN key, add the key ID and bundle id, do not upload any p12 certificates.
- Disable firebase message swizzling by adding this to your Info.plist:
FirebaseAppDelegateProxyEnabled: NO
Then add the following in your AppDelegate.swift file in the didFinishLaunchingWithOptions method:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// [START set_messaging_delegate]
Messaging.messaging().delegate = self
// [END set_messaging_delegate]
// get push notification token id for user
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()
return true}
Since swizzling is disabled you need to take care of generating your APN token and assigning it to the firebase messaging apnsToken. You do this by having the following method in your AppDelegate.swift file:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let refreshedToken = InstanceID.instanceID().token() {
defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)
Messaging.messaging().apnsToken = deviceToken
print("Token generated: ", refreshedToken)
} else {
print("Could not save token becuase error with instance id token")
}
}
I then save the token in the userdefaults to later persist to the database see above:
defaults.set(refreshedToken, forKey: Constant.UserDefaults.token)
You can test that your token is working by copying the token printed out in the console and using the FCM messaging console. Or by using a curl request in the terminal as below. Note you have to replace YOUR_LEGACY_SERVER_KEY with the legacy server key which you can find in the firebase console under settings and cloud messaging and replace YOUR_TOKEN with the token printed in the console (which was generated above):
curl -X "POST" "https://fcm.googleapis.com/fcm/send" \
-H "Authorization: key=YOUR_LEGACY_SERVER_KEY” \
-H "Content-Type: application/json" \
-d $'{
"notification": {
"body": "Testing with direct FCM API",
"title": "Test Message",
"badge": "0",
"sound": "default"
},
"registration_ids": [YOUR_TOKEN]
}'
Firebase Push notification not working in iOS 11
I was able to solve the problem with push notifications and scheduled push notifications on iOS 11.1 by replicating the same code present in the sample firebase project - https://github.com/firebase/quickstart-ios/tree/master/messaging
The steps given here are clear and helps you resolve the issue.
Firebase notifications not working in iOS 11
This is an issue with Firebase. It seems to be related to a recent update of theirs instead of iOS 11. They are working on a fix for it.
In the meantime if you add pod 'FirebaseInstanceID', '2.0.0'
to your podfile it will fix it.
You can read more here: https://github.com/firebase/quickstart-ios/issues/327#issuecomment-332655731
Unable to receive IOS notifications from Firebase Console
Go to firebase->Project Settings->Cloud Messaging -> then scroll down to Apple app configuration and make sure you've provided APNs Production Certificate or not, if not then generate production certificate and upload it there. Alternatively i suggest you to upload APNs Authentication Key instead of certificates.
Firebase Push Notifications with Swift not working in ios 11.4
first make sure you have a paid developer account, activate notification from the project capabilities section, set up all the certificate with apple member center and add this certificate to gcm (see this How to use Apple's new .p8 certificate for APNs in firebase console) , you also must test with a real device
I assume that you already have these 3 Pods
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications
first you need to add this to didfinishlaunchingwithoptions
FirebaseApp.configure()
Messaging.messaging().delegate = self
registerForPushNotifications()
then add this two func to get the user permission
func getNotificationSettings() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
} else {
// Fallback on earlier versions
}
}
func registerForPushNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
guard granted else { return }
self.getNotificationSettings()
}
} else {
let settings = UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
}
}
to get the firebase token add this
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print(fcmToken)
}
from now you should be able to see the permission prompt and to push notification from the Firebase console
if you need to perform a notification from code here is what I do (make sure to replace with your api key from firebase)
func sendPushNotification(notData: [String: Any]) {
let url = URL(string: "https://fcm.googleapis.com/fcm/send")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("key=YOUR-SERVER-API-KEY", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: notData, options: [])
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error ?? "")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print(response ?? "")
}
let responseString = String(data: data, encoding: .utf8)
print(responseString ?? "")
}
task.resume()
}
then call this func when you need
let notifMessage: [String: Any] = [
"to" : "fcm token you need to send the notification",
"notification" :
["title" : "title you want to display", "body": "content you need to display", "badge" : 1, "sound" : "default"]
]
sendPushNotification(notData: notifMessage)
Related Topics
Why Would a 'Scheduledtimer' Fire Properly When Setup Outside a Block, But Not Within a Block
Uitextview Adding New Line Unintentionally
How to Save Created PDF in Document Folder and Merge in iOS
Swift JSON Error:Could Not Cast Value of Type '_Nsdictionarym' to 'Nsarray'
Arc4Random_Uniform Not Available in Xcode 7.0 Beta (7A176X) on Osx 10.10.4
New Itunes Connect Interface -- Should It Immediately Be Seen on "Prerelease"
iOS Scatter Core Plot with a Gap
How to Set Cornerradius for Only Bottom-Left,Bottom-Right and Top-Left Corner of a Uiview
How to Prevent Screen Lock on My Application with Swift on iOS
Unarchive Array with Nskeyedunarchiver Unarchivedobject(Ofclass:From:)
How to Use Objective-C Code with #Define MACros in Swift
How to Make Offline Database for My App
Tap Gesture on Animating Uiview Not Working
Fix Cordova Geolocation Ask for Location Message
Timestamp Function That Has Been Working Reliably Just Caused Exc_Bad_Instruction