Migrate an existing GCM client app on iOS to Firebase Cloud Messaging (FCM) using the instructions in this guide.
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 FirebaseAppDelegateProxyEnabled
flag 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.
Add your GCM project as a Firebase project
In the Firebase console, select Add project.
Select your GCM project from the list of existing Google Cloud projects, and select Add Firebase.
In the Firebase welcome screen, select Add Firebase to your iOS App.
Provide your bundle name and optional App store ID, and select Add App. A new GoogleServices-info.plist file for your Firebase app is downloaded.
Select Continue and follow the detailed instructions for creating an xcworkspace file for your app and connecting to Firebase on startup.
Prerequisites
Make sure your valid APNs certificates are uploaded to the Firebase console.
- Select the gear icon next to your project name at top left, and select Project Settings.
- Select the Cloud Messaging tab.
- Select the Upload Certificate button for your develpment certificate, your production certificate, or both. At least one is required.
- For each certificate, select the .p12 file, provide the password if any, and select Save.
Switch to FCM in your Podfile
Before
Google/CloudMessaging
After
Firebase/Messaging
Initializing the service
Previously, the GCM API required client apps to start and configure the GCM service. FCM is initialized as part of overall Firebase app initialization.
Before
<pre class="prettyprint">[[GGLInstanceID sharedInstance] startWithConfig:[GGLInstanceIDConfig defaultConfig]]
[GCMService sharedInstance] startWithConfig:[GCMConfig defaultConfig]];
After
// No extra messaging code required. // Configure FCM and other Firebase APIs with a single call. [FIRApp configure];
Default registration token
You must follow different steps to migrate registration token-related code depending on whether or not you disable swizzling. By default, FCM swizzles the AppDelegate methods to:
get the APNs token and associate it with the registration token automatically. The FCM SDK swizzles the AppDelegate’s remote notification handlers to get the APNs token for the device.
automatically report notification related analytics, such "notification opened" and "notifcation foregrounded." These analytics are available if the message is sent from Firebase Notifications.
Generating the token with swizzling enabled
Before
NSDictionary *instanceIDOptions = @{ kGGLInstanceIDRegisterAPNSOption : appDelegate.apnsDeviceToken, kGGLInstanceIDAPNSServerTypeSandboxOption : @([self isSandboxApp]), }; [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:[AppDelegate appGCMSenderID] scope:kGGLInstanceIDScopeGCM options:instanceIDOptions handler:^(NSString *token, NSError *error){ // handle token or error. }];
After
// Get the default token // The first time you call this, the token may not be available, in which case // the SDK returns nil. // Once the token is fetched from the server, the SDK posts a token refresh // notification that you can listen for in order to access the new token. NSString *token = [[FIRInstanceID instanceID] token];
Generating the token with swizzling disabled
Before
NSDictionary *instanceIDOptions = @{ kGGLInstanceIDRegisterAPNSOption : appDelegate.apnsDeviceToken, kGGLInstanceIDAPNSServerTypeSandboxOption : @([self isSandboxApp]), }; [[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:[AppDelegate appGCMSenderID] scope:kGGLInstanceIDScopeGCM options:instanceIDOptions handler:^(NSString *token, NSError *error){ // handle token or error. }];
After
// With "FirebaseAppDelegateProxyEnabled": NO - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeProd]; }
Token Refresh
FCM does not require the GGLInstanceIDDelegate
protocol for token refresh.
Instead, the SDK posts the notification kFIRInstanceIDTokenRefreshNotification
to let the app know when the token is refreshed. The token refresh notification
is invoked whenever the SDK generates a token, including the first time.
Before
@implementation AppDelegate : NSObjectGGLInstanceIDConfig *config = [GGLInstanceIDConfig defaultConfig]; config.delegate = self; [[GGLInstanceID sharedInstance] startWithConfig:config]; //#pragma - GGLInstanceIDDelegate protocol - (void)onTokenRefresh() { // get all new tokens, resubscribe to topics etc. } @end
After
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Add observer to listen for the token refresh notification. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTokenRefresh) name:FIRMessagingRegistrationTokenRefreshedNotification object:nil]; ... } - (void)onTokenRefresh { // Get the default token if the earlier default token was nil. If the we already // had a default token most likely this will be nil too. But that is OK we just // wait for another notification of this type. NSString *token = [[FIRInstanceID instanceID] token]; // custom stuff as before. }
Downstream send callbacks
In FCM, swizzling relieves your client app of the need to call
appDidReceiveMessage
for message handling. If you disable swizzling, the
API closely resembles GCM’s, only with updated FIRMessaging
naming.
Handling downstream callbacks with swizzling enabled
Before
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult))completionHandler { // Let GCM know about the message for analytics etc. [GCMService appDidReceiveMessage:userInfo]; // handle your message. }
After
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult))completionHandler { // Handle your message. With swizzling enabled, no need to indicate // that a message was received. }
Handling downstream callbacks with swizzling disabled
Before
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult))completionHandler { // Let GCM know about the message for analytics etc. [GCMService appDidReceiveMessage:userInfo]; // handle your message. }
After
- (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. }
Upstream send callbacks
To receive status updates for upstream sends, GCM apps must implement the
GCMReceiverDelegate
protocol and implement its methods. With FCM, client apps
listen for the relevant notifications by adding observers for each of them.
Before
@implementation AppDelegate : NSObjectGCMConfig *config = [GCMConfig defaultConfig]; config.delegate = self; [[GCMConfig sharedInstance] startWithConfig:config]; // GCMReceiverDelegate protocol methods - (void)willSendDataMessageWithID:(NSString *)messageID error:(NSError *)error; // check if any error while sending message } - (void)didSendDataMessageWithID:(NSString *)messageID { // successfully sent upstream message with id ‘messageID` } - (void)didDeleteMessagesOnServer { // some messages were deleted(TTL expired) on the server, lets’ retrieve them. } @end
After
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendDataMessageFailure:) name:FIRMessagingSendErrorNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendDataMessageSuccess:) name:FIRMessagingSendSuccessNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didDeleteMessagesOnServer) name:FIRMessagingMessagesDeletedNotification object:nil]; // contains error info - (void)sendDataMessageFailure:(NSNotification *)notification { NSString *messageID = (NSString *)message.object; } - (void)sendDataMessageSuccess:(NSNotification *)notification { NSString *messageID = (NSString *)message.object; NSDictionary *userInfo = message.userInfo; } - (void)didDeleteMessagesOnServer { }
Update server endpoints
Update your server code to use new FCM endpoints for sending messages
via HTTP and XMPP. Note that the new FCM version of gcm-http.googleapis.com/gcm/
is
fcm.googleapis.com/fcm/
(without "http"):
GCM endpoint | FCM endpoint |
---|---|
gcm-http.googleapis.com/gcm/ |
fcm.googleapis.com/fcm/ |
gcm-xmpp.googleapis.com |
fcm-xmpp.googleapis.com |
FCM supports HTTP and XMPP protocols that are virtually identical to the GCM server protocols, so you don't need to update your sending logic for the migration. Optionally, you may want to evaluate the FCM HTTP v1 API, which offers an improved security model and new capabilities for customizing messages across platforms.