From 7ce7f5ae589ce5b02e8fae6a71c732c39dc70a27 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Thu, 8 Mar 2018 09:28:27 +0000 Subject: [PATCH] [messaging] Support FCM data-only messages in the background --- .../messaging/MessagingSerializer.java | 43 +++++++++++++++++++ .../RNFirebaseBackgroundMessagingService.java | 30 +++++++++++++ .../messaging/RNFirebaseMessaging.java | 38 +--------------- .../messaging/RNFirebaseMessagingService.java | 36 ++++++++++------ .../android/app/src/main/AndroidManifest.xml | 2 + tests/index.js | 6 +++ tests/src/bgMessaging.js | 17 ++++++++ 7 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java create mode 100644 android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java create mode 100644 tests/src/bgMessaging.js diff --git a/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java b/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java new file mode 100644 index 00000000..2bba2ec0 --- /dev/null +++ b/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java @@ -0,0 +1,43 @@ +package io.invertase.firebase.messaging; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; +import com.google.firebase.messaging.RemoteMessage; + +import java.util.Map; + + +public class MessagingSerializer { + public static WritableMap parseRemoteMessage(RemoteMessage message) { + WritableMap messageMap = Arguments.createMap(); + WritableMap dataMap = Arguments.createMap(); + + if (message.getCollapseKey() != null) { + messageMap.putString("collapseKey", message.getCollapseKey()); + } + + if (message.getData() != null) { + for (Map.Entry e : message.getData().entrySet()) { + dataMap.putString(e.getKey(), e.getValue()); + } + } + messageMap.putMap("data", dataMap); + + if (message.getFrom() != null) { + messageMap.putString("from", message.getFrom()); + } + if (message.getMessageId() != null) { + messageMap.putString("messageId", message.getMessageId()); + } + if (message.getMessageType() != null) { + messageMap.putString("messageType", message.getMessageType()); + } + messageMap.putDouble("sentTime", message.getSentTime()); + if (message.getTo() != null) { + messageMap.putString("to", message.getTo()); + } + messageMap.putDouble("ttl", message.getTtl()); + + return messageMap; + } +} diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java new file mode 100644 index 00000000..de3c1382 --- /dev/null +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java @@ -0,0 +1,30 @@ +package io.invertase.firebase.messaging; + +import android.content.Intent; +import android.os.Bundle; + +import com.facebook.react.HeadlessJsTaskService; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.jstasks.HeadlessJsTaskConfig; +import com.google.firebase.messaging.RemoteMessage; + +import javax.annotation.Nullable; + +public class RNFirebaseBackgroundMessagingService extends HeadlessJsTaskService { + @Override + protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) { + Bundle extras = intent.getExtras(); + if (extras != null) { + RemoteMessage message = intent.getParcelableExtra("message"); + WritableMap messageMap = MessagingSerializer.parseRemoteMessage(message); + return new HeadlessJsTaskConfig( + "RNFirebaseBackgroundMessage", + messageMap, + 10000, + false + ); + } + return null; + } +} diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java index c133d0a5..5e7c7067 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java @@ -7,7 +7,6 @@ import android.content.IntentFilter; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -21,8 +20,6 @@ import com.google.firebase.messaging.RemoteMessage; import io.invertase.firebase.Utils; -import java.util.Map; - public class RNFirebaseMessaging extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebaseMessaging"; @@ -115,44 +112,11 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { Log.d(TAG, "Received new message"); RemoteMessage message = intent.getParcelableExtra("message"); - WritableMap messageMap = buildMessageMap(message); + WritableMap messageMap = MessagingSerializer.parseRemoteMessage(message); Utils.sendEvent(getReactApplicationContext(), "messaging_message_received", messageMap); } } - - private WritableMap buildMessageMap(RemoteMessage message) { - WritableMap messageMap = Arguments.createMap(); - WritableMap dataMap = Arguments.createMap(); - - if (message.getCollapseKey() != null) { - messageMap.putString("collapseKey", message.getCollapseKey()); - } - - if (message.getData() != null) { - for (Map.Entry e : message.getData().entrySet()) { - dataMap.putString(e.getKey(), e.getValue()); - } - } - messageMap.putMap("data", dataMap); - - if (message.getFrom() != null) { - messageMap.putString("from", message.getFrom()); - } - if (message.getMessageId() != null) { - messageMap.putString("messageId", message.getMessageId()); - } - if (message.getMessageType() != null) { - messageMap.putString("messageType", message.getMessageType()); - } - messageMap.putDouble("sentTime", message.getSentTime()); - if (message.getTo() != null) { - messageMap.putString("to", message.getTo()); - } - messageMap.putDouble("ttl", message.getTtl()); - - return messageMap; - } } private class RefreshTokenReceiver extends BroadcastReceiver { diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java index 662ed5c5..6ba60c25 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java @@ -4,9 +4,12 @@ import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; +import com.facebook.react.HeadlessJsTaskService; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; +import io.invertase.firebase.Utils; + public class RNFirebaseMessagingService extends FirebaseMessagingService { private static final String TAG = "RNFMessagingService"; public static final String MESSAGE_EVENT = "messaging-message"; @@ -16,19 +19,28 @@ public class RNFirebaseMessagingService extends FirebaseMessagingService { public void onMessageReceived(RemoteMessage message) { Log.d(TAG, "onMessageReceived event received"); - Intent event; - if (message.getNotification() != null) { - // It's a notification, pass to the notification module - event = new Intent(REMOTE_NOTIFICATION_EVENT); - event.putExtra("notification", message); - } else { - // It's a data message, pass to the messaging module - event = new Intent(MESSAGE_EVENT); - event.putExtra("message", message); - } + // It's a notification, pass to the Notifications module + Intent notificationEvent = new Intent(REMOTE_NOTIFICATION_EVENT); + notificationEvent.putExtra("notification", message); - // Broadcast it so it is only available to the RN Application - LocalBroadcastManager.getInstance(this).sendBroadcast(event); + // Broadcast it to the (foreground) RN Application + LocalBroadcastManager.getInstance(this).sendBroadcast(notificationEvent); + } else { + // It's a data message + // If the app is in the foreground we send it to the Messaging module + if (Utils.isAppInForeground(this.getApplicationContext())) { + Intent messagingEvent = new Intent(MESSAGE_EVENT); + messagingEvent.putExtra("message", message); + // Broadcast it so it is only available to the RN Application + LocalBroadcastManager.getInstance(this).sendBroadcast(messagingEvent); + } else { + // If the app is in the background we send it to the Headless JS Service + Intent headlessIntent = new Intent(this.getApplicationContext(), RNFirebaseBackgroundMessagingService.class); + headlessIntent.putExtra("message", message); + this.getApplicationContext().startService(headlessIntent); + HeadlessJsTaskService.acquireWakeLockNow(this.getApplicationContext()); + } + } } } diff --git a/tests/android/app/src/main/AndroidManifest.xml b/tests/android/app/src/main/AndroidManifest.xml index aa4f2cd3..08d12b4d 100644 --- a/tests/android/app/src/main/AndroidManifest.xml +++ b/tests/android/app/src/main/AndroidManifest.xml @@ -30,6 +30,8 @@ + + diff --git a/tests/index.js b/tests/index.js index 597382bc..744aa791 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,4 +1,10 @@ import { AppRegistry } from 'react-native'; import bootstrap from './src/main'; +import bgMessaging from './src/bgMessaging'; AppRegistry.registerComponent('ReactNativeFirebaseDemo', () => bootstrap); +// Task registered to handle background data-only FCM messages +AppRegistry.registerHeadlessTask( + 'RNFirebaseBackgroundMessage', + () => bgMessaging +); diff --git a/tests/src/bgMessaging.js b/tests/src/bgMessaging.js new file mode 100644 index 00000000..3a633122 --- /dev/null +++ b/tests/src/bgMessaging.js @@ -0,0 +1,17 @@ +import RNfirebase from './../firebase'; + +export default async message => { + console.log('Message', message); + + const notification = new RNfirebase.notifications.Notification(); + notification + .setTitle('Background notification') + .setBody('Background body') + .setNotificationId('background') + .android.setChannelId('test') + .android.setClickAction('action') + .android.setPriority(RNfirebase.notifications.Android.Priority.Max); + + await RNfirebase.notifications().displayNotification(notification); + return Promise.resolve(); +};