Somewhat recently at the Google I/O event Google renovated Firebase & added a lot of new features, and touched up on the remaining ones. I have been trying to implement the iOS Push Notifications via Firebase into my app through the most basic level, So I created a very simple app that really does nothing besides receive remote push notifications.
Inside of Firebase, I have uploaded my certificate and within Xcode my provisioning profiles have been added to both the target and project, and in Firebase I have uploaded the correct certificate. Below is the code contained inside of my AppDelegate.swift
file but because my ViewController.swift
is "empty," I did not include it.
Although there are no crashes or runtime errors, when I load the app, I accept the notifications. Then, I exit the app and turn off my device. In Firebase, I send the notification to the correct app. After a couple of minutes, in Firebase it says the notification was "Completed".
However, I never received the notification on the device. So, in conclusion, I need a solution to send Firebase this deviceToken
and then use 'Firebase Notifications' to send the push notification Message.
Any help for my code or in general would be greatly appreciated and I hope this helps future viewers. Thank you! My code in AppDelegate.swift
:
import UIKit
import Firebase
import FirebaseMessaging
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
let notificationTypes : UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let notificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
application.registerForRemoteNotifications()
application.registerUserNotificationSettings(notificationSettings)
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
print("Device Token: \(deviceToken)")
}
func applicationWillResignActive(application: UIApplication) {
}
func applicationDidEnterBackground(application: UIApplication) {
}
func applicationWillEnterForeground(application: UIApplication) {
}
func applicationDidBecomeActive(application: UIApplication) {
}
func applicationWillTerminate(application: UIApplication) {
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("MessageID : \(userInfo["gcm.messgae_id"]!)") // or gcm_etc...
print(userInfo)
}
}
Updated: As of Firebase 4.0.4, you can follow https://github.com/onmyway133/blog/issues/64
HOW APNS DEVICE TOKEN IS HANDLED
I've been reading Send a Notification to a User Segment on iOS but there is no mention of APNS device token, which is crucial to push notifications.
So Firebase must be doing some swizzling under the hood. In fact it is. Reading backend documentation Downstream Messages gives us the idea
Swizzling disabled: mapping your APNs token and registration token
If you have disabled method swizzling, you'll need to explicitly map your APNs token to the FCM registration token. Override the
methods
didRegisterForRemoteNotificationsWithDeviceToken
to retrieve the APNs token, and then callsetAPNSToken
.
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenTypeSandbox)
}
I particularly try to avoid swizzling as much as possible. Reading Migrate a GCM Client App for iOS to Firebase Cloud Messaging gives us how to do disable it
Enabling/disabling method swizzling
Method swizzling available with FCM simplifies your client code. However, for developers who prefer not to use it, FCM allows you to disable method swizzling by adding the FIRMessagingAutoRegisterEnabledflag in the app’s Info.plist file and setting its value to NO (boolean value).
FCM swizzling affects how you handle the default registration token, and how you handle downstream message callbacks. Where
applicable, this guide provides migration examples both with and without method swizzling enabled.
SHOW ME THE CODE
Have this in your Podfile
pod 'Firebase'
pod 'FirebaseMessaging'
Here is the completed code
import Firebase
import FirebaseMessaging
override func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(tokenRefreshNotification(_:)),
name: kFIRInstanceIDTokenRefreshNotification,
object: nil)
}
// NOTE: Need to use this when swizzling is disabled
public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
}
func tokenRefreshNotification(notification: NSNotification) {
// NOTE: It can be nil here
let refreshedToken = FIRInstanceID.instanceID().token()
print("InstanceID token: \(refreshedToken)")
connectToFcm()
}
func connectToFcm() {
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
}
}
public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With