Search This Blog

Sunday, September 18, 2016

Migrate a GCM Client App for Android to Firebase Cloud Messaging

Import your GCM project as a Firebase project


  1. In the Firebase console, select Import Google Project.
  2. Select your GCM project from the list of existing projects and select Add Firebase.
  3. In the Firebase welcome screen, select Add Firebase to your Android App.
  4. Provide your package name and SHA-1, and select Add App. A new google-services.json file for your Firebase app is downloaded.
  5. Select Continue and follow the detailed instructions for adding the Google Services plugin in Android Studio.

Switch to FCM in the app-level build.gradle

BEFORE
dependencies {
  compile "com.google.android.gms:play-services-gcm:8.4.0"
}
AFTER
dependencies {
  compile "com.google.firebase:firebase-messaging:9.0.0"
}

Remove the permissions required by GCM

All the permissions required by FCM are now added automatically by library

BEFORE

<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="<your-package-name>.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
<uses-permission android:name="<your-package-name>.permission.C2D_MESSAGE" />

AFTER

No permissions


Remove the receiver from the app manifest
With FCM, com.google.android.gms.gcm.GcmReceiver is added automatically.
AndroidManifest.xml Before
<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver"
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>

AndroidManifest.xml After

No receiver


Migrate your listener service

A service extending InstanceIDListenerService is now required only if you want to access 
the FCM token.

This is needed if you want to
  • Manage device tokens to send a messages to single device directly, or
  • Send messages to device group, or
  • Subscribe devices to topics with the server subscription management API.
If you don't use these features, you can completely remove this service along with client code to initiate the generation of a registration token.

Update the Android Manifest

AndroidManifest.xml Before
<service
    android:name=".MyInstanceIDListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID" />
    </intent-filter>
</service>
AndroidManifest.xml After

<service
   android:name=".MyInstanceIDListenerService">
   <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
   </intent-filter>
</service>

Update your InstanceIDListenerService

Change MyInstanceIDListenerService to extend FirebaseInstanceIdService, and update code to listen for token updates and get the token whenever a new token is generated. MyInstanceIDListenerService.java Before public class MyInstanceIDListenerService extends InstanceIDListenerService { @Override public void onTokenRefresh() { // Fetch updated Instance ID token and notify our app's server of any changes (if applicable). Intent intent = new Intent(this, RegistrationIntentService.class); startService(intent); } } MyInstanceIDListenerService.java After

public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
  /**
   * Called if InstanceID token is updated. This may occur if the security of
   * the previous token had been compromised. Note that this is also called
   * when the InstanceID token is initially generated, so this is where
   * you retrieve the token.
   */
  
   // [START refresh_token]
  
   @Override
   public void onTokenRefresh() {
   // Get updated InstanceID token.
   String refreshedToken = FirebaseInstanceId.getInstance().getToken();
   Log.d(TAG, "Refreshed token: " + refreshedToken);
   // TODO: Implement this method to send any registration to your app's servers.
   sendRegistrationToServer(refreshedToken);
  }
}
Remove registration

You no longer need to explicitly initiate the generation of a registration token — the library does this automatically. Therefore, you can remove code like the following:
  InstanceID instanceID = InstanceID.getInstance(this);
  String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
          GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
  // [END get_token]
  Log.i(TAG, "GCM Registration Token: " + token);
Migrate your GcmListenerService

A service extending GcmListenerService is now required only for the following use cases:
  • receiving messages with notification payload while the application is in foreground
  • receiving messages with data payload only
  • receiving errors in case of upstream message failures.
If you don't use these features, and you only care about displaying notifications messages when the app is not in the foreground, you can completely remove this service.

Update the Android Manifest

AndroidManifest.xml Before


<service
    android:name=".MyGcmListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>

AndroidManifest.xml After

<service
    android:name=".MyFcmListenerService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Update your GcmListenerService

Change MyGcmListenerService to extend FirebaseMessagingService and update the signature of the method onMessageReceived(). This example updates the service name to MyFcmListenerService.

MyGcmListenerService.java Before

public class MyGcmListenerService extends GcmListenerService {
  @Override
  public void onMessageReceived(String from, Bundle data){
    ...
  }
}

MyFcmListenerService.java after

public class MyFcmListenerService extends FirebaseMessagingService {
   @Override
   public void onMessageReceived(RemoteMessage message){ 
      String from = message.getFrom();
       Map data = message.getData();
  }
}

Firebase has three message types:

Notification messages : Notification message works on background or foreground. When app is in background, Notification messages are delivered to the system tray. If the app is in the foreground, messages are handled by onMessageReceived() or didReceiveRemoteNotification callbacks. These are essentially what is referred to as Display messages.

Data messages: On Android platform, data message can work on background and foreground. The data message will be handled by onMessageReceived(). A platform specific note here would be: On Android, the data payload can be retrieved in the Intent used to launch your activity. To elaborate, if you have "click_action":"launch_Activity_1", you can retrieve this intent through getIntent() from only Activity_1.

Messages with both notification and data payloads: When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification. When in the foreground, your app receives a message object with both payloads available. Secondly, the click_action parameter is often used in notification payload and not in data payload. If used inside data payload, this parameter would be treated as custom key-value pair and therefore you would need to implement custom logic for it to work as intended.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.