- Firebase Cloud Messaging on iOS
- Setting Up a Firebase Cloud Messaging Client App on iOS
- Send your First Message to a Backgrounded App
- Send Messages to Multiple Devices
- Receive Messages
- Topic Messaging
- Device Group Messaging
- Sending Upstream Messages
- Send Messages with the Firebase Console
Firebase Cloud Messaging offers a broad range of messaging options and capabilities. I invite you to read the following documentation to have a better understanding about notification messages and data messages and what you can do with them using FCM's options.
One important thing you should know before start using FCM is that FCM API performs method swizzling in two key areas: mapping your APNs token to the FCM registration token and capturing analytics data during downstream message callback handling. Developers who prefer not to use swizzling can disable it by adding the flag FirebaseAppDelegateProxyEnabled
in the app’s Info.plist file and setting it to No
(boolean value). If you decided to disable swizzling, the docs provide example for both scenarios, with and without method swizzling enabled.
You can implement Firebase Cloud Messaging in two complementary ways:
- Receive basic push messages up to 2KB over the Firebase Cloud Messaging APNs interface.
- Send messages upstream and/or receive downstream payloads up to 4KB.
- A physical iOS device
- A project targeting iOS 8 or above
- If you want to enable Notifications specifically, you'll need to create an Apple Push Notification Authentication Key, an App Id and a Provisioning Profile, then upload the key to Firebase and finally enable the app for remote notifications.
- Open Entitlements.plist and check Enable Push Notifications
Support for iOS 7 deprecated: As of v4.5.0 of the Firebase SDK for iOS, support for iOS 7 is deprecated. Upgrade your apps to target iOS 8 or above. To see the breakdown of worldwide iOS versions, go to Apple’s App Store support page.
- Create a Firebase project in the Firebase console, if you don't already have one. If you already have an existing Google project associated with your mobile app, click Import Google Project. Otherwise, click Create New Project.
- Click Add Firebase to your iOS app and follow the setup steps. If you're importing an existing Google project, this may happen automatically and you can just download the config file.
- When prompted, enter your app's bundle ID. It's important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project.
- At the end, you'll download a
GoogleService-Info.plist
file. You can download this file again at any time.
Note: If you have multiple build variants with different bundle IDs defined, each app must be added to your project in Firebase console.
Once you have your GoogleService-Info.plist
file downloaded in your computer, do the following steps in Xamarin Studio:
- Add
GoogleService-Info.plist
file to your app project. - Set
GoogleService-Info.plist
build action behaviour toBundle Resource
by Right clicking/Build Action. - Open
GoogleService-Info.plist
file and changeIS_GCM_ENABLED
value toYes
. - Add the following line of code somewhere in your app, typically in your AppDelegate's
FinishedLaunching
method (don't forget to importFirebase.Core
namespace):
Firebase.Core.App.Configure();
Either at startup, or at the desired point in your application flow, register your app for remote notifications. Call RegisterForRemoteNotifications
method as shown:
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion (10, 0)) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization (authOptions, (granted, error) => {
Console.WriteLine (granted);
});
} else {
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes (allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings (settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications ();
For devices running iOS 10 and above, you must assign your delegate object to the
UNUserNotificationCenter
object to receive display notifications, and theMessaging
object to receive data messages, before your app finishes launching. For example, in an iOS app, you must assign it in theWillFinishLaunching
orFinishedLaunching
method.
By default, the FCM SDK generates a registration token for the client app instance on initial startup of your app. Similar to the APNs device token, this token allows you to target notification messages to this particular instance of the app.
In the same way that iOS typically delivers an APNs device token on app start, FCM provides a registration token via the DidReceiveRegistrationToken
method of the Messaging
delegate on each app startup. During the first app start, and in all situations where the registration token is changed, the FCM SDK retrieves the token. In both cases, the FCM SDK calls DidReceiveRegistrationToken
found in the IMessageDelegate
interface.
The registration token may change when:
- The app is restored on a new device
- The user uninstalls/reinstall the app
- The user clears app data.
To receive registration tokens on app start, implement the IMessagingDelegate
interface in a class and provide it to Messaging
’s Delegate
property after calling App.Configure ()
method. For example, if your application delegate conforms to the IMessagingDelegate
interface, you can set the delegate on FinishedLaunching
to itself:
Messaging.SharedInstance.Delegate = this;
Registration tokens are delivered via the IMessagingDelegate
method DidReceiveRegistrationToken
. This method is called generally once per app start with an FCM token. When this method is called, it is the ideal time to:
- If the registration token is new, send it to your application server (it's recommended to implement server logic to determine whether the token is new).
- Subscribe the registration token to topics. This is required only for new subscriptions or for situations where the user has re-installed the app.
var token = Messaging.SharedInstance.FcmToken ?? "";
Console.WriteLine ($"FCM token: {token}");
After this delegate method is called, the registration token is available via the FcmToken
property of Messaging
class. Prior to this delegate method call, the property may be null
.
To be notified whenever the token is updated, supply a class conforming to the IMessagingDelegate
interface and set it to Messaging
Delegate
property. The following example registers the delegate and adds the proper interface method:
[Export ("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken (Messaging messaging, string fcmToken)
{
Console.WriteLine ($"Firebase registration token: {fcmToken}");
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
Alternatively, you can listen for an NSNotification
named RegistrationTokenRefreshedNotification
rather than supplying a interface method. The Messaging.SharedInstance.FcmToken
property always has the current token value.
If you have disabled method swizzling, you'll need to explicitly map your APNs token to the FCM registration token. Override the AppDelegate
's method RegisteredForRemoteNotifications
to retrieve the APNs token, and then use the ApnsToken
property.
Provide your APNs token using the ApnsToken
property:
public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
{
Messaging.SharedInstance.ApnsToken = deviceToken;
}
After the FCM registration token is generated, you can access it and listen for refresh events using the same methods as with swizzling enabled.
If you have an existing user base that you want to onboard to an FCM client app, use the batchImport API provided by Instance ID. With this API, you can bulk import existing iOS APNs tokens into FCM, mapping them to new, valid registration tokens.
FCM generates an Instance ID, which is used as a registration token within FCM. When an Instance ID is generated the library will upload the identifier and configuration data to Firebase. If you want to get an explicit opt-in before using Instance ID, you can prevent generation at configure time by disabling FCM. To do this, add a metadata value to your Info.plist
(not your GoogleService-Info.plist
):
FirebaseMessagingAutoInitEnabled = NO
To re-enable FCM, you can make a runtime call:
Messaging.SharedInstance.AutoInitEnabled = true;
This value persists across app restarts once set.
To get started with FCM, build out the simplest use case: sending a notification message from the Notifications composer to a specific user's device when the app is in the background on the device.
- Install and run the app on the target device. You'll need to accept the request for permission to receive remote notifications.
- Make sure the app is in the background on the device.
- Open the Notifications composer and select New Message.
- Enter the message text.
- Select Single Device for the message target.
- In the field labeled FCM Registration Token, enter the registration token you obtained in a previous section of this guide.
After you click Send Message, targeted client devices that have the app in the background receive the notification in the notification center.
Firebase Cloud Messaging provides two ways to target a message to multiple devices:
- Topic messaging, which allows you to send a message to multiple devices that have opted in to a particular topic.
- Device group messaging, which allows you to send a single message to multiple instances of an app running on devices belonging to a group.
This part focuses on sending topic messages from your app server using the HTTP or XMPP protocols for FCM, and receiving and handling them in an iOS app.
Client apps can subscribe to any existing topic, or they can create a new topic. To learn more about this, go to Topic Messaging section below.
FCM delivers topic messages in the same way as other downstream messages. To learn how to receive and handle messages, go to Receive Messages section below.
Sending messages to a Firebase Cloud Messaging topic is very similar to sending messages to an individual device or to a user group. To learn more about this, please, read the following documentation.
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.
Handling messages received through the FCM APNs interface is likely to cover most typical use cases. You can also send upstream messages, or receive data messages in foregrounded apps.
When your app is in the background, iOS directs messages with the notification
key to the system tray. A tap on a notification opens the app, and the content of the notification is passed to the DidReceiveRemoteNotification
method in the AppDelegate
.
Implement AppDelegate DidReceiveRemoteNotification
as shown:
public override void ReceivedRemoteNotification (UIApplication application, 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
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine (userInfo);
}
public override void DidReceiveRemoteNotification (UIApplication application, NSDictionary userInfo, Action<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
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine (userInfo);
completionHandler (UIBackgroundFetchResult.NewData);
}
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.
When overriding DidReceiveRemoteNotification
method, you need to add "remote-notification" to the list of your Required background modes in your Info.plist
The payload of notification 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"
}
To receive data-only messages directly from FCM (as opposed to via APNs) when the app is in the foreground, you'll need to connect to the FCM service and handle messages with IMessagingDelegate
DidReceiveMessage
interface method.
To connect, set the ShouldEstablishDirectChannel
property to true
in the AppDelegate
. FCM manages the connection, closing it when your app goes into the background and reopening it whenever the app is foregrounded.
To receive data messages when your app is in the foreground, implement DidReceiveMessage
. Your app can still receive data messages when it is in the background without this callback, but for foreground cases you'll need to handle it.
If you disable method swizzling, you'll need to call method Messaging
AppDidReceiveMessage
method. This lets FCM track message delivery and analytics, which is performed automatically with method swizzling enabled:
// With "FirebaseAppDelegateProxyEnabled": NO
public override void DidReceiveRemoteNotification (UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// Let FCM know about the message for analytics etc.
Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Do your magic to handle the notification data
}
Since iOS 10, you can set UNUserNotificationCenter
Delegate
to receive display notifications from Apple and Messaging
s Delegate
to receive data messages from FCM. If you do not set these two delegates with AppDelegate
, method swizzling for message handling is disabled. You'll need to call method AppDidReceiveMessage
to track message delivery and analytics.
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
[Export ("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification (UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
var userInfo = notification.Request.Content.UserInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine (userInfo);
// Change this to your preferred presentation option
completionHandler (UNNotificationPresentationOptions.None);
}
// Handle notification messages after display notification is tapped by the user.
[Export ("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse (UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
var userInfo = response.Notification.Request.Content.UserInfo;
// Print full message.
Console.WriteLine (userInfo);
completionHandler ();
}
The payload of data messages is a dictionary of keys and values. 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"
}
Apps that connect to FCM to receive data messages should handle Messaging.MessagesDeletedNotification
with NSNotificationCenter
or with Messaging.Notifications.ObserveMessagesDeleted
. You may receive this callback when there are too many messages (>100) pending for your app on a particular device at the time it connects, or if the device hasn't connected to FCM for more than one month. When the app instance receives this callback, it should perform a full sync with your app server.
Based on the publish/subscribe model, FCM topic messaging allows you to send a message to multiple devices that have opted in to a particular topic. You compose topic messages as needed, and FCM handles routing and delivering the message reliably to the right devices.
For example, users of a local weather forecasting app could opt in to a "severe weather alerts" topic and receive notifications of storms threatening specified areas. Users of a sports app could subscribe to automatic updates in live game scores for their favorite teams.
Some things to keep in mind about topics:
- Topic messaging supports unlimited topics and subscriptions for each app.
- Topic messaging is best suited for content such as news, weather, or other publicly available information.
- Topic messages are optimized for throughput rather than latency. For fast, secure delivery to single devices or small groups of devices, target messages to registration tokens, not topics.
- If you need to send messages to multiple devices per user, consider device group messaging for those use cases.
Client apps can subscribe to any existing topic, or they can create a new topic. When a client app subscribes to a new topic name (one that does not already exist for your Firebase project), a new topic of that name is created in FCM and any client can subsequently subscribe to it.
The Messaging
class handles topic messaging functionality. To subscribe to a topic, call Subscribe
method from your application's main thread (FCM is not thread-safe):
Messaging.SharedInstance.Subscribe ("topic", (error) => {
// ...
});
Console.WriteLine ("Subscribed to topic");
// async/away Version
try {
await Messaging.SharedInstance.SubscribeAsync ("topic");
Console.WriteLine ("Subscribed to topic");
} catch (NSErrorException ex) {
// ...
}
This makes an asynchronous request to the FCM backend and subscribes the client to the given topic. Before calling Subscribe
method, make sure that the client app instance has already received a registration token via the callback IMessagingDelegate
DidReceiveRegistrationToken
method.
If the subscription request fails initially, FCM retries until it can subscribe to the topic successfully. Each time the app starts, FCM makes sure that all requested topics have been subscribed.
To unsubscribe, call Unsubscribe
method, and FCM unsubscribes from the topic in the background.
Messaging.SharedInstance.Unsubscribe ("topic", (error) => {
// ...
});
Console.WriteLine ("Unsubscribed to topic");
// async/away Version
try {
await Messaging.SharedInstance.UnsubscribeAsync ("topic");
Console.WriteLine ("Unsubscribed to topic");
} catch (NSErrorException ex) {
// ...
}
You can take advantage of Instance ID APIs to perform basic topic management tasks from the server side. Given the registration token(s) of client app instances, you can do the following:
- Find out details about a client app instance's subscriptions, including each topic name and subscribe date. See Get information about app instances.
- Subscribe or unsubscribe an app instance to a topic. See Create a relationship mapping for an app instance.
- Subscribe or unsubscribe multiple app instances to a topic. See Manage relationship maps for multiple app instances.
FCM delivers topic messages in the same way as other downstream messages. To learn how to receive and handle messages, go to Receive Messages section above.
Sending messages to a Firebase Cloud Messaging topic is very similar to sending messages to an individual device or to a user group. To learn more about this, please, read the following documentation.
With device group messaging, you can send a single message to multiple instances of an app running on devices belonging to a group. Typically, "group" refers a set of different devices that belong to a single user. All devices in a group share a common notification key, which is the token that FCM uses to fan out messages to all devices in the group.
You can use device group messaging with the Admin SDKs, or by implementing the XMPP or HTTP protocols on your app server. The maximum number of members allowed for a notification key is 20.
To learn about this, please, read the following documentation.
To learn about this, please, read the following documentation.
To send upstream messages to device groups on iOS, the iOS client app needs to call Messaging.SendMessage
method.
If your app server implements the XMPP Connection Server protocol, it can receive upstream messages from a user's device to the cloud. To initiate an upstream message, the client app sends a request containing the following:
- The address of the receiving app server in the format SENDER_ID@gcm.googleapis.com.
- A message ID that should be unique for each sender ID.
- The message data comprising the key-value pairs of the message's payload.
When it receives this data, FCM builds an XMPP stanza to send to the app server, adding some additional information about the sending device and app.
To send messages upstream to the server, an iOS client app composes a message, connects to FCM, and calls SendMessage
method.
To connect, set the ShouldEstablishDirectChannel
property to true
in the AppDelegate
. FCM manages the connection, closing it when your app goes into the background and reopening it whenever the app is foregrounded.
Configure the call to SendMessage method as shown:
Messaging.SharedInstance.SendMessage (message, to, messageId, ttl);
where:
message
is aDictionary<object, object>
orNSDictionary
of keys and values as strings. Any key-value pair that is not a string is ignored.to
is the address of the receiving app server in the format SENDER_ID@gcm.googleapis.com.messageId
is a unique message identifier. All the message receiver callbacks are identified on the basis of this message ID.ttl
is the time to live. If FCM can't deliver the message before this expiration is reached, it sends a notification back to the client.
The FCM client library caches the message on the client app and sends it when the client has an active server connection. On receiving the message, the FCM connection server sends it to the app server.
Handle upstream callbacks by adding observers that listen for SendErrorNotification
and SendSuccessNotification
, and then retrieve error information from the methods. In this example, HandleSendMessageError
is the method used to handle the callback:
var sendSuccessToken = Messaging.Notifications.ObserveSendSuccess (HandleSendMessageSuccess);
var sendErrorToken = Messaging.Notifications.ObserveSendError (HandleSendMessageError);
void HandleSendMessageSuccess(object sender, NSNotificationEventArgs e)
{
var messageId = e.Notification.Object.ToString ();
}
void HandleSendMessageError (object sender, NSNotificationEventArgs e)
{
var messageId = e.Notification.Object.ToString ();
var userInfo = e.Notification.UserInfo; // contains error info etc
}
// Call this lines to stop receiving notifications
sendSuccessToken.Dispose ();
sendErrorToken.Dispose ();
// Or
var sendSuccessToken = NSNotificationCenter.DefaultCenter.AddObserver (Messaging.SendSuccessNotification, HandleSendMessageSuccess);
var sendErrorToken = NSNotificationCenter.DefaultCenter.AddObserver (Messaging.SendSuccessNotification, HandleSendMessageError);
void HandleSendMessageSuccess (NSNotification notification)
{
var messageId = notification.Object.ToString ();
}
void HandleSendMessageError (NSNotification notification)
{
var messageId = notification.Object.ToString ();
var userInfo = notification.UserInfo; // contains error info etc
}
// Call this lines to stop receiving notifications
NSNotificationCenter.DefaultCenter.RemoveObserver (sendSuccessToken);
NSNotificationCenter.DefaultCenter.RemoveObserver (sendErrorToken);
To optimize network usage, FCM batches responses to HandleSendMessageError
and HandleSendMessageSuccess
, so the acknowledgement may not be immediate for each message.
To learn about this, please, read the following documentation.
You can send notification messages to iOS and Android devices using the Notifications composer in the Firebase console. To learn more about this, please, read the following documentation.
Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License. Click here to see original Firebase documentation.