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.

4.5 (8) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

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)

Screenshot of the FirebaseAppDelegateProxyEnabled entry in the info.plist, with the value 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:

  1. It configures your app to work with Firebase.
  2. 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:

  1. Sets AppDelegate as the delegate for UNUserNotificationCenter. You implemented the necessary delegate methods in the previous step.
  2. 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.
  3. 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.

Add push notification capability

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.

Screenshot of Good News app showing 'Good News would like to send you notifications' dialog

Now, go to your Firebase project and select Cloud Messaging found under Engage. Then select Send your first message.

Send your first notification

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:

Send notification 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:

First notification coming through

Note: If you didn’t receive a notification, go back through the instructions to get everything set up. You might have missed a setting or failed to upload your .p8 file. Additionally, you can implement 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:

  1. This gets the information needed in your notification payload.
  2. 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.

Screenshot showing a notification that added a news item

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.