Android: Handling Push Notifications In App Background or Killed State - oracle/pushiomanager-react-native GitHub Wiki
NOTE: This guide will be helpful if your app uses the @react-native-firebase/messaging plugin. If your app uses a different Firebase Messaging plugin then you can follow the concepts explained below and adapt them for your use-case.
Due to certain restrictions imposed by the React-Native Firebase Messaging plugin, your app may get the following error in the logs when a push notification is received while the app is not in memory.
E/RNFirebaseMsgReceiver: Background messages only work if the message priority is set to 'high'
In some cases, this leads to the app force-closing.
Following code changes will allow your app to receive push notifications even when the app is in killed-state.
- Create a new file -
MyRNFirebaseMessagingReceiver.java
inandroid/app/src/main/java/<your-package-name>
with the following code,
package com.awesomeproject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.core.app.JobIntentService;
import com.google.firebase.messaging.RemoteMessage;
import com.pushio.manager.PIOGCMRegistrationIntentService;
import com.pushio.manager.PushIOConstants;
import com.pushio.manager.PushIOManager;
import com.pushio.manager.rn.RCTPIOFirebaseMessagingService;
import com.pushio.manager.rn.RCTPIONotificationHandlerService;
import io.invertase.firebase.app.ReactNativeFirebaseApp;
import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
import io.invertase.firebase.common.SharedUtils;
import io.invertase.firebase.messaging.ReactNativeFirebaseMessagingSerializer;
public class MyRNFirebaseMessagingReceiver extends BroadcastReceiver {
private static final String TAG = "MyRNFirebaseMsgReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Push notification broadcast received");
Bundle extras = intent.getExtras();
if (extras == null) {
Log.d(TAG, "empty Intent");
return;
}
RemoteMessage remoteMessage = new RemoteMessage(extras);
if (PushIOManager.getInstance(context).isResponsysPush(remoteMessage)) {
Log.d(TAG, "Push message will be handled by Responsys SDK");
Intent pushHandlerIntent = new Intent(context, RCTPIONotificationHandlerService.class);
pushHandlerIntent.putExtras(intent);
JobIntentService.enqueueWork(context, RCTPIONotificationHandlerService.class,
1, pushHandlerIntent);
abortBroadcast();
} else {
Log.d(TAG, "Push message forwarded to FCM");
if (SharedUtils.isAppInForeground(context)) {
Log.d(TAG, "App is in foreground, passing it to firebase onMessage handler");
if (ReactNativeFirebaseApp.getApplicationContext() == null) {
ReactNativeFirebaseApp.setApplicationContext(context.getApplicationContext());
}
ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance();
emitter.sendEvent(ReactNativeFirebaseMessagingSerializer.remoteMessageToEvent(remoteMessage, false));
abortBroadcast();
}else{
Log.d(TAG, "App not in foreground");
Log.d(TAG, "Push message forwarded to FCM");
}
}
}
}
- Remember to change the package name at the top of the file to your app's package name.
- Add a reference to this new BroadcastReceiver in
AndroidManifest.xml
as follows,
<receiver
android:name=".MyRNFirebaseMessagingReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND"
android:priority="999">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
Open android/app/build.gradle
and add the following line in dependencies
section,
implementation project(':PushIOManager')
implementation 'androidx.core:core:1.6.0'
implementation 'com.google.firebase:firebase-messaging:17.3.0'
- In
index.js
, add the following code,
import {AppRegistry} from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Push message received in background: ', remoteMessage);
// Not a Responsys Push, your app should handle this notification
});
AppRegistry.registerComponent(appName, () => App);
- This code block is called when the app is in killed-state and push notification is received from any push message provider other than Responsys.
- Push notifications received from Responsys in this app state are automatically handled by the Responsys SDK.
- In
App.js
or your main/home JS file, add the following code,
useEffect(() => {
const messageHandler = messaging().onMessage(async remoteMessage => {
console.log('New FCM message received: ', JSON.stringify(remoteMessage));
PushIOManager.isResponsysPush(remoteMessage, (error, response) => {
if (response) {
console.log("Received Push Message from Responsys");
PushIOManager.handleMessage(remoteMessage);
} else {
// Not a Responsys Push, handle it appropriately
}
});
});
return messageHandler;
}, []);
- This code block is called when the app is in foreground and a push notification is received from Responsys or any other push message provider.
Copyright (c) 2024 Oracle and/or its affiliates and released under the Universal Permissive License (UPL), Version 1.0.
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.