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 FirebaseAppDelegateProxyEnabledflag 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.
Import your GCM project as a Firebase project
-
In the Firebase console, select Import Google Project.
-
Select your GCM project from the list of existing 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 |
|---|
[[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 {
[FIRInstanceID instanceID] setAPNSToken:deviceToken
type:FIRInstanceIDAPNSTokenTypeProd];
}
|
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 : NSObject |
| 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:kFIRInstanceIDTokenRefreshNotification 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 : NSObject |
| 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
You can 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 |
Updating these endpoints is not strictly required, as Google will continue to support the existing GCM endpoints.