This is a quick tip to update our FCM stuff in our app targeting to API 26 (Oreo).

Last week, I had to update the current app (changing the targetSdkVersion to 26) to support Android Oreo (8.0). Everything works great (in previous versions) but in Oreo that was not the happy case. The notifications were not working as expected: the app was crashing when a push notification was received by device. This was the exception in logcat:

Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.google.firebase.iid.FirebaseInstanceIdInternalReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=PACKAGE cmp=COMPONENT }: app is in background uid UidRecord{c5e5e69 u0a325 RCVR bg:+1m25s411ms idle procs:1 seq(0,0,0)}
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3397)
at android.app.ActivityThread.-wrap18(Unknown Source)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1780)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Well, I’ll be honest and I should confess that I wasted one day researching information about this problem. In addition, the project has a gradle file with a lot of dependencies to be used in every module. This distribution helps to keep all dependencies in one place and then make a reference to them from the specific build.gradle file.

Research the problem

After make a quick research about the problem, the main cause was: “Not allowed to start service”. This message is thrown from Android system when you try to start a service when the app is in background or it is not running. That was the starting point. All posts were referenced to Background Execution Limits: the best solution is create a notification receiver in the middle to execute the service as it matches. First mistake: that was not I have in my code. Using Firebase Messaging Cloud, there was not place where a service was starting. So? Are there other solution?

Well, the main problem was the FCM version I had: it was pointing to 8.4.0 which it does not support Oreo.

Update FCM at least to 11.2.0

After play around on this, I figured out the FCM version 11.4.0 supports Android Oreo. Actually, Oreo support was introduced in 11.2.0. You can use whatever you want.

dependencies {
compile 'com.google.firebase:firebase-core:11.4.0'
compile 'com.google.firebase:firebase-messaging:11.4.0'
}

The official documentation suggests use 11.8.0 instead. Again, you can choose whatever you want.

“Nice, so that’s all, right?” Well, not really. Oreo introduced a new concept for notifications named Notification ChannelsAll notifications must be assigned to a channel or it will not appear. So, if we have our app targeting to API 26 and we should display a notification for any reason, we must assign it to a channel. Otherwise, you will get a warning toast message like this one:

Assign Notification to a channel

The first step is create a channel id. The best place to create one is in strings.xml file.

<string name="default_notification_channel_id" translatable="false">fcm_default_channel</string>

Then, you must add a meta-data in manifest file to enable it:

<application>
...
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id"/>
</application>

Perfect, our last step is the assignment on code side. In the same place where you are calling to notify method to display the notification, you should add the channel assignment:

...
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = context.getString(R.string.default_notification_channel_id);
NotificationChannel channel = new NotificationChannel(channelId, title, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(body);
mNotificationManager.createNotificationChannel(channel);
builder.setChannelId(channelId);
}
mNotificationManager.notify(1, notification);
...

And that’s it! Now the app should work on devices with Oreo.

You can check the following repo to make sure you are doing it in a right way:

firebase/quickstart-android
quickstart-android – Firebase Quickstart Samples for Androidgithub.com

Please, feel free to comment, suggest or ask anything you want. Happy coding!

Read the article in Medium