How to Receive Fcm Push Notifications When App Is Killed

Is it possible to receive FCM push notifications when app is killed?

There are 2 types of push notifications: Data messages and Notification messages.

If you are using the Data messages you will be in charge of handling the received message and present a notification to the user (if needed of course). But in this case you might miss notifications when your app is closed.

If you are using Notification Messages, FCM is handling the message for you and directly displays a notification if the app is in background/closed.

Please see more here.

FCM messages unable to be handled when app is killed

I was able to resolve the issue. My FirebaseMessagingService implementation had a Dependency Injection call in the constructor which failed when the service was started in the background by the FirebaseIidInstanceReceiver. This caused the service to fail to start and did not generate Android notifications while the app was killed.

Since I've done a lot of digging and information on this topic is so fragmented and out of date, I'll try to compile what I know results in a working solution here:

Follow the steps here, notably setting up your FCM project and downloading the google-services.json file.

Ensure your manifest declares the following permissions:

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />

Add the following within your AndroidManifest <application> tag to listen for message receives:

<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>

Optionally define defaults for notification channel, notification icon (must be white color only, allowing transparency), and notification icon color when the notification tray is expanded, also within the <application> manifest tag:

<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/..."/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/..." />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/..." />

Create a custom class inheriting from FirebaseMessagingService. In Xamarin.Forms, you will need the Xamarin.Firebase.Messaging NuGet package for this class. Within your implementation, you should override OnMessageReceived(RemoteMessage) and add your application logic which will handle messages containing the notification property in the foreground and messages with only the data property in both the foreground and background. Your class should be decorated with the following attributes (note that DirectBootAware is optional; see below):

[Service(DirectBootAware = true, Exported = true, Enabled = true)]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]

If you wish to ensure that notifications can be received after a device reboot and before the device is unlocked, you may consider making your application and your FirebaseMessagingService implementation Direct Boot Aware (more here)

In your MainActivity, ensure a Notification Channel is created for devices running Android O or higher, and this method invoked at some point during OnCreate:

private void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}

var channelId = GetString(Resource.String./*res id here*/);
var notificationManager = (NotificationManager)GetSystemService(NotificationService);

// Don't re-create the notification channel if we already created it
if (notificationManager.GetNotificationChannel(channelId) == null)
{
var channel = new NotificationChannel(channelId,
"<display name>",
NotificationImportance.Default);

notificationManager.CreateNotificationChannel(channel);
}
}

Add a ProGuard config file ("proguard.cfg") to your Android project to prevent the SDK linker from killing Google Play and Firebase libraries. Edit the Properties of this file in Visual Studio and set the Build Action to ProguardConfiguration. Even if the option is missing from the dropdown list, Xamarin will recognize it. If you are using d8 and r8 instead of dx and ProGuard in your build, Xamarin will still use this config file and conform to the rules you define within.

# Keep commands are required to prevent the linker from killing dependencies not directly referenced in code
# See: https://forums.xamarin.com/discussion/95107/firebaseinstanceidreceiver-classnotfoundexception-when-receiving-notifications

-dontwarn com.google.android.gms.**
-keep class com.google.android.gms.** { *; }
-keep class com.google.firebase.** { *; }

Hope this helps and if I've missed anything I will update with further details.

FCM is not working when the app is killed

Many Chinese manufacturers kill the app's background services for saving battery. The running of your notification service is primary to receive push notifications.
However, if you can remove your app from battery optimization in Settings, you'll receive push notifications when your app is in the background or you've killed the app.
This might look like its silly, but when I had the same issue I removed my app from battery optimization and it worked!

How to get push notification custom data from Firebase when app is terminated

If you app startup from FCM message click when your app terminated, you need to custom this

FirebaseMessaging.instance.getInitialMessage().then((message) { //do something })


Related Topics



Leave a reply



Submit