Migrating from GCM to Pusher Beams
This tutorial uses an Android demo app.
Introduction
As most of you are aware, Google deprecated Google Cloud Messaging (GCM) on April 10, 2018, and completely removed support for it on May 29, 2019. And so, it is expected that by now you should have migrated to another messaging service or be on the verge of doing so.
Fortunately, Pusher has a solution called Beams that serves this purpose. In this tutorial, we will see how we can migrate an app built with GCM to Pusher Beams.
Understanding a GCM project
For this post, we will be looking at Google’s sample project using GCM here. Let us gain some understanding of what the major files and classes there do:
MyGcmListenerService
: this is a service class that helps us detect when there is a new message. This service extends theGcmListenerService
class and overrides theonMessageReceived
method to give information about the new message.RegistrationIntentService
: this service is where we fetch our device token and send to the server. As you know, with messaging services, each device will have a device token that you can send to your server in case you need to send messages to a specific device. This service helps us register the token.MyInstanceIDListenerService
: this service is used to tell us then the device token has been updated.MainActivity
: this is the main activity of the application where the receiver is registered and unregistered. Using GCM requires Google Play Services, in this class, checks like that are performed.
Having understood what these files do, let us see how we can migrate our app to use Pusher Beams instead.
Creating a Firebase project
Recent GCM apps were created with Firebase and if you fall into this category, you can skip this part. However, if your app was created from the Google developers console, follow along.
Go to your Firebase console, choose the Add a project card, then you select your former project from the dropdown and add Firebase to it like this.
This will create a new project on Firebase with the same name. Now, select the Android icon to add an Android app to your Firebase project. Add your package name and register the app.
Thereafter, you download the google-services.json
file. After downloading the file, skip the rest of the guide. Now, open your project and add the google-services.json
file to your app directory (GCMSample/app/google-services.json
).
Creating a Pusher Beams instance
Before creating a Pusher Beams instance, you need an FCM key. By now, you should have your Firebase project ready. Open the project, select the project settings and select the Cloud messaging tab. There, you will find the server key. Copy it out as you will need soon.
After that, open your Pusher Beams dashboard and create a new instance.
After creating the instance, select the Android quickstart. The first step is to enter your server key which you got from Firebase. After that, cancel the rest of the quickstart.
Updating our dependencies
Open your project build.gradle
file and make sure you have this dependency:
dependencies {
// other dependencies
classpath 'com.google.gms:google-services:4.2.0'
}
Next, open your app build.gradle
file, remove this dependency:
implementation "com.google.android.gms:play-services-gcm:15.0.1"
And add these dependencies:
implementation 'com.google.firebase:firebase-messaging:17.6.0'
implementation 'com.pusher:push-notifications-android:1.4.0'
Also, make sure this plugin is applied at the end of the file:
apply plugin: 'com.google.gms.google-services'
After that, sync your gradle files so that the new dependencies will be downloaded for you.
Rewriting our services
Now, we will delete all the service classes from our project - MyGcmListenerService
, MyInstanceIDListenerService
and RegistrationIntentService
. We will then replace all these services with a single service class.
Create a new class named NotificationsMessagingService
and paste this:
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.RemoteMessage
import com.pusher.pushnotifications.fcm.MessagingService
class NotificationsMessagingService : MessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
showNotification(remoteMessage)
}
}
This class extends the MessagingService
class. And so, we can implement two methods essential to our migration:
onNewToken
- This is called when the device token is updated.onMessageReceived
- This is called when a new message is received.
Implementing the onMessageReceived
method is compulsory, while the onNewToken
method is not. In the onMessageReceived
method, we called another function to display a notification. You can add the function like so:
private fun showNotification(remoteMessage: RemoteMessage) {
val notificationId = 10
val channelId = "migration"
lateinit var channel:NotificationChannel
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val mBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(remoteMessage.notification!!.title!!)
.setContentText(remoteMessage.notification!!.body!!)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = applicationContext.getSystemService(NotificationManager::class.java)
val name = getString(R.string.channel_name)
val description = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
channel = NotificationChannel("migration-channel", name, importance)
channel.description = description
notificationManager!!.createNotificationChannel(channel)
notificationManager.notify(notificationId, mBuilder.build())
} else {
val notificationManager = NotificationManagerCompat.from(this)
notificationManager.notify(notificationId, mBuilder.build())
}
}
Since devices running Android O and above have a unique way of handling notifications, we have to cater to that in the method. You also need to add these resources in the strings.xml
file as we used them in the snippet above:
<string name="channel_name">beams</string>
<string name="channel_description">Display notifications with Pusher Beams</string>
After writing our service class, the next thing is to declare it in our AndroidManifest.xml
file. Remove the previously declared services and add this new one:
<service android:name=".NotificationsMessagingService">
<intent-filter android:priority="1">
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
You should also remove these permissions as you do not need them any longer:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
Also, remove the receiver from the manifest:
<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.neo.gcmsample" />
</intent-filter>
</receiver>
Finishing up
Finally, we need to initialize Pusher Beams and subscribe for specific topics and we will do that in the MainActivity
which is the starting activity.
In the class, replace everything with this:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.pusher.pushnotifications.PushNotifications
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
PushNotifications.start(applicationContext, "PUSHER_INSTANCE_ID")
PushNotifications.addDeviceInterest("hello")
}
}
Replace the
PUSHER_INSTANCE_ID
placeholder with your own key from your dashboard.
In this final snippet, we initialized Beams and subscribed to the hello topic. You can subscribe to as many topics as you want.
Conclusion
Great! You have successfully migrated your app from using GCM to Pusher Beams. You have nothing to fear as Google is about to remove support for GCM. Feel free to play around with the repository and comment if you encounter any hurdles.
11 June 2019
by Neo Ighodaro