Firebase Cloud Messaging for iOS: Push Notifications
Learn how to use Firebase Cloud Messaging to send and receive remote push notifications in your SwiftUI iOS app. By Andy Pereira.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Firebase Cloud Messaging for iOS: Push Notifications
25 mins
- Getting Started
- Configuring Firebase
- Creating the p8 Certificate
- Setting up the Firebase Project
- Adding the Package
- Configuring Your App
- Launching Firebase
- Registering for Notifications
- Sending Notifications
- Sending Data in Notifications
- Subscribing to Topics
- Sending Images
- Adding a Notification Service Extension
- Customizing Notifications
- Analytics
- Tracking Custom Events
- Where to Go From Here?
Configuring Your App
Start by opening Info.plist and adding the following entry:
- Key: FirebaseAppDelegateProxyEnabled
- Type: Boolean
- Value: NO (Xcode will show this as 0)
By default, FirebaseMessaging uses method swizzling to handle push notifications. You’ll handle all the code yourself, so turn this off using the plist entry you just added.
Next, you’ll add an app delegate to your project, which will be responsible for setting up push notifications. Create a new file called AppDelegate.swift and replace its code with the following:
import UIKit
import Firebase
import FirebaseMessaging
import FirebaseAnalytics
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
return true
}
}
In the code above, you first import the necessary Firebase frameworks and then implement the UIApplicationDelegate
protocol.
Next, add a new property to AppMain
inside AppMain.swift:
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
This will make SwiftUI aware of your newly created app delegate. Now you can get started with configuring Firebase.
Launching Firebase
Open AppDelegate.swift again and add the following to application(_:didFinishLaunchingWithOptions:)
, just before return
:
// 1
FirebaseApp.configure()
// 2
FirebaseConfiguration.shared.setLoggerLevel(.min)
Here’s what this does:
- It configures your app to work with Firebase.
- It sets how much Firebase will log. Setting this to
min
reduces the amount of data you’ll see in your debugger.
Since you’re not letting Firebase automatically handle notification code through swizzling, you’ll need to conform to UNUserNotificationCenterDelegate
. Add the following to the end of AppDelegate.swift:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([[.banner, .sound]])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
completionHandler()
}
}
The user notification center will call these methods when notifications arrive or when the user interacts with them. You’ll be working with them a little later.
Registering for Notifications
With Firebase configured, you can start registering to receive notifications. Add the method below to the UNUserNotificationCenterDelegate
extension:
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
}
APNs will generate and register a token when a user grants permission for push notifications. This token identifies the individual device so you can send notifications to it. You’ll use Firebase to distribute your notifications, and this code makes that token available in Firebase.
You can now add the following to application(_:didFinishLaunchingWithOptions:)
, before return
:
// 1
UNUserNotificationCenter.current().delegate = self
// 2
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions) { _, _ in }
// 3
application.registerForRemoteNotifications()
Here’s what the code does:
- Sets
AppDelegate
as the delegate forUNUserNotificationCenter
. You implemented the necessary delegate methods in the previous step. - Creates options related to what kind of push notification permissions your app will request. In this case, you’re asking for alerts, badges and sound.
- Registers your app for remote notifications.
Next, add the following extension at the bottom of your file:
extension AppDelegate: MessagingDelegate {
func messaging(
_ messaging: Messaging,
didReceiveRegistrationToken fcmToken: String?
) {
let tokenDict = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: tokenDict)
}
}
Messaging
is Firebase’s class that manages everything related to push notifications. Like a lot of iOS APIs, it features a delegate called MessagingDelegate
, which you implement in the code above. Whenever your app starts up or Firebase updates your token, Firebase will call the method you just added to keep the app in sync with it.
Now, add the following to application(_:didFinishLaunchingWithOptions:)
, just before return
:
Messaging.messaging().delegate = self
This sets AppDelegate
as the delegate for Messaging
.
You’re close — only one more step to get your app ready. In Xcode, open your app’s project settings and go to Signing & Capabilities. Select the + Capability button. Search for Push Notifications in the field and press Enter.
Sending Notifications
Your app is now ready to receive notifications! Build and run on a real device. It should look the same as before, but with an alert asking for permission to send you notifications. Be sure to select Allow.
Now, go to your Firebase project and select Cloud Messaging found under Engage. Then select Send your first message.
Under Step 1, enter the following:
- Notification title: Notification Test
- Notification text: This is a test
Next, pick your app from the drop-down in Step 2:
This will target your specific app when using the Cloud Messaging console.
Finally, select Review and then Publish. On your device, you’ll see this notification:
application(_:didFailToRegisterForRemoteNotificationsWithError:)
in AppDelegate.swift to print out any possible errors that happen during registering for notifications.Sending Data in Notifications
Firebase makes it easy to send additional data in your notification through the Cloud Messaging console. For this next section, you’ll add data to your notification payload so you can add a news story to the feed when the notification arrives.
First, in AppDelegate.swift, add the following code inside the UNUserNotificationCenterDelegate
extension:
private func process(_ notification: UNNotification) {
// 1
let userInfo = notification.request.content.userInfo
// 2
UIApplication.shared.applicationIconBadgeNumber = 0
if let newsTitle = userInfo["newsTitle"] as? String,
let newsBody = userInfo["newsBody"] as? String {
let newsItem = NewsItem(title: newsTitle, body: newsBody, date: Date())
NewsModel.shared.add([newsItem])
}
}
Here’s what you added:
- This gets the information needed in your notification payload.
- If
userInfo
has the values to make a news item, this code creates one and adds it to the news feed of the starter project.
Then, add the following to userNotificationCenter(_:willPresent:withCompletionHandler:)
before the call to completionHandler
:
process(notification)
userNotificationCenter(_:willPresent:withCompletionHandler:)
gets called whenever you receive a notification while the app is in the foreground. This makes sure news items get added when new notifications arrive while a user is using your app.
Then, add the code below to userNotification(_:didReceive:withCompletionHandler:)
before the call to completionHandler
:
process(response.notification)
userNotification(_:didReceive:withCompletionHandler:)
gets called when a user taps a notification. Again, you’ll add a news item whenever this happens.
Build and run. The app will look the same as before, but it’ll be ready to process additional notification data.
Back in the console, create a new notification. Like before, enter the notification title and text and select your app. Then go to Step 5 and add the following items under Custom data:
- Key: newsTitle
- Value: Child Saves Kittens
This will send a title to the app. Now, add the entry for the body:
- Key: newsBody
- Value: Local child saves kittens from a tall tree.
The keys and values you added will get sent as the userInfo
of the notification, which you’ll parse in process(_:)
. Send the notification. If you have your app open, or if you tap on the notification when it arrives, you’ll see the new news item in the feed.
It’s also possible to handle notifications from a background process, without any interaction from the user. While this is out of scope for this tutorial, background handling of push notifications and many other topics are covered in our Push Notifications video course as well as the Push Notifications by Tutorials book.