Receive Messages in an iOS App

Once your client app is installed on a device, it can receive messages through the FCM APNs interface. You can immediately start sending notifications to user segments with the Notifications composer, or your application server can send messages with a notification payload through the APNs interface.

To receive or send messages through FCM (not just the APNs interface), you'll need to connect to the FCM service and handle messages with AppDelegate application:didReceiveRemoteNotification:. The rest of this page describes how to connect and handle messages in your iOS client app.

Connect to FCM

Connect when your application becomes active and whenever a new registration token is available. Once your app is connected, FCM ignores subsequent attempts to connect.

Objective-C

- (void)connectToFcm {
  // Won't connect since there is no token
  if (![[FIRInstanceID instanceID] token]) {
    return;
  }

  // Disconnect previous FCM connection if it exists.
  [[FIRMessaging messaging] disconnect];

  [[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
    if (error != nil) {
      NSLog(@"Unable to connect to FCM. %@", error);
    } else {
      NSLog(@"Connected to FCM.");
    }
  }];
}

Swift

func connectToFcm() {
  // Won't connect since there is no token
  guard FIRInstanceID.instanceID().token() != nil else {
    return
  }

  // Disconnect previous FCM connection if it exists.
  FIRMessaging.messaging().disconnect()

  FIRMessaging.messaging().connect { (error) in
    if error != nil {
      print("Unable to connect with FCM. \(error?.localizedDescription ?? "")")
    } else {
      print("Connected to FCM.")
    }
  }
}

After your app is connected, you can send downstream and upstream messages and use topic messaging and device group messaging. When your app goes into the background, disconnect from FCM:

Objective-C

- (void)applicationDidEnterBackground:(UIApplication *)application {
  [[FIRMessaging messaging] disconnect];
  NSLog(@"Disconnected from FCM");
}

Swift

func applicationDidEnterBackground(_ application: UIApplication) {
  FIRMessaging.messaging().disconnect()
  print("Disconnected from FCM.")
}

Handle messages

Implement AppDelegate application:didReceiveRemoteNotification: to handle notifications received when the client app is in the foreground, and all data messages that are sent to the client. The message is a dictionary of keys and values.

Objective-C

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
  // 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

  // Print message ID.
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

  // Print full message.
  NSLog(@"%@", userInfo);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // 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

  // Print message ID.
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

  // Print full message.
  NSLog(@"%@", userInfo);

  completionHandler(UIBackgroundFetchResultNewData);
}

Swift

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
  // 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

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)
}

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

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)

  completionHandler(UIBackgroundFetchResult.newData)
}

Receive and handle messages with notification in the payload

When your app is in the background, iOS directs messages with the notification key to the system tray. A user tap on a notification opens the app, and the content of the notification is passed to the didReceiveRemoteNotification callback if implemented in the AppDelegate.

If you want to open your app and perform a specific action, set click_action in the notification payload. Use the value that you would use for the category key in the APNs payload.

Receive data messages on iOS 10

To receive data messages when your app is in the foreground, on iOS 10 devices, you'll need to handle applicationReceivedRemoteMessage:. Your app can still receive data messages when it is in the background without this callback, but for foreground cases you'll need logic like the following in your app delegate:
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// Receive data message on iOS 10 devices while app is in the foreground.
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
  // Print full message
  NSLog(@"%@", remoteMessage.appData);
}
#endif

Handle messages with method swizzling disabled

If you disable method swizzling, you'll need to call method appDidReceiveMessage:. This lets FCM track message delivery and analytics, which is performed automatically with method swizzling enabled.

Objective-C

// With "FirebaseAppDelegateProxyEnabled": NO
   - (void)application:(UIApplication *)application
     didReceiveRemoteNotification:(NSDictionary *)userInfo
           fetchCompletionHandler:
               (void (^)(UIBackgroundFetchResult))completionHandler {
   // Let FCM know about the message for analytics etc.
   [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
   // handle your message.
 }
 

Swift

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
     // Let FCM know about the message for analytics etc.
     FIRMessaging.messaging().appDidReceiveMessage(userInfo)
     // handle your message
   }
 

Interpreting message payload

The payload of both notification and data messages is a dictionary of keys and values. Notification messages sent through APNs follow the APNs payload format as below:

  {
    "aps" : {
      "alert" : {
        "body" : "great match!",
        "title" : "Portugal vs. Denmark",
      },
      "badge" : 1,
    },
    "customKey" : "customValue"
  }

Data messages sent to the devices directly by FCM server are expressed in the format of a dictionary as below:

  {
    "body" : "great match!",
    "title" : "Portugal vs. Denmark",
    "icon" : "myicon"
  }

Send feedback about...

Need help? Visit our support page.