From c052494b8aec072302d00dd1dbfcdabe0e45b87c Mon Sep 17 00:00:00 2001 From: Cayley Humphries Date: Wed, 13 Jan 2021 11:17:35 -0800 Subject: [PATCH] [Android] Add hooks to intent handling and bundle parsing Allows easier customization of intent handling and bundle parsing behaviour on Android. This can be used to send notifications sent by 3rd party messaging management platforms that have custom message formats the same onNotification() JS codepath. --- README.md | 43 +++++++++++++++++++ .../modules/RNPushNotification.java | 21 +++++++++ 2 files changed, 64 insertions(+) diff --git a/README.md b/README.md index e7520914d..56c85ed1a 100644 --- a/README.md +++ b/README.md @@ -702,6 +702,49 @@ Uses the [ShortcutBadger](https://github.com/leolin310148/ShortcutBadger) on And `PushNotification.unsubscribeFromTopic(topic: string)` Unsubscribe from a topic (works only with Firebase) +## Android Custom Notification Handling + +Unlike iOS, Android apps handle the creation of their own notifications. React Native Push Notifications does a "best guess" to create and handle incoming notifications. However, when using 3rd party notification platforms and tools, the initial notification creation process may need to be customized. + +### Customizing Notification Creation + +If your notification service uses a custom data payload format, React Native Push Notifications will not be able to parse the data correctly to create an initial notification. + +For these cases, you should: + +1. Remove the intent handler configuration for React Native Push Notifications from your `android/app/src/main/AndroidManifest.xml`. +2. Implement initial notification creation as per the instructions from your Provider. + +### Handling Custom Payloads + +Data payloads of notifications from 3rd party services may not match the format expected by React Native Push Notification. When tapped, these notifications will not pass the details and data to the `onNotification()` event handler. Custom `IntentHandlers` allow you to fix this so that correct `notification` objects are sent to your `onNotification()` method. + +Custom handlers are added in Application init or `MainActivity.onCreate()` methods: + +``` +RNPushNotification.IntentHandlers.add(new RNPushNotification.RNIntentHandler() { + @Override + public void onNewIntent(Intent intent) { + // If your provider requires some parsing on the intent before the data can be + // used, add that code here. Otherwise leave empty. + } + + @Nullable + @Override + public Bundle getBundleFromIntent(Intent intent) { + // This should return the bundle data that will be serialized to the `notification.data` + // property sent to the `onNotification()` handler. Return `null` if there is no data + // or this is not an intent from your provider. + + // Example: + if (intent.hasExtra("MY_NOTIFICATION_PROVIDER_DATA_KEY")) { + return intent.getBundleExtra("MY_NOTIFICATION_PROVIDER_DATA_KEY"); + } + return null; + } +}); +``` + ## Checking Notification Permissions `PushNotification.checkPermissions(callback: Function)` Check permissions diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java index f6b1dba6a..0e940916e 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -9,6 +9,7 @@ import android.content.IntentFilter; import android.os.Bundle; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.app.NotificationManagerCompat; import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; @@ -27,6 +28,7 @@ import java.io.IOException; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -42,6 +44,15 @@ public class RNPushNotification extends ReactContextBaseJavaModule implements Ac public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag public static final String KEY_TEXT_REPLY = "key_text_reply"; + public interface RNIntentHandler { + void onNewIntent(Intent intent); + + @Nullable + Bundle getBundleFromIntent(Intent intent); + } + + public static ArrayList IntentHandlers = new ArrayList(); + private RNPushNotificationHelper mRNPushNotificationHelper; private final SecureRandom mRandomNumberGenerator = new SecureRandom(); private RNPushNotificationJsDelivery mJsDelivery; @@ -81,6 +92,12 @@ private Bundle getBundleFromIntent(Intent intent) { bundle.putBundle("data", intent.getExtras()); } + if (bundle == null) { + for (RNIntentHandler handler : IntentHandlers) { + bundle = handler.getBundleFromIntent(intent); + } + } + if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("userInteraction")) { bundle.putBoolean("userInteraction", true); } @@ -90,6 +107,10 @@ private Bundle getBundleFromIntent(Intent intent) { @Override public void onNewIntent(Intent intent) { + for (RNIntentHandler handler : IntentHandlers) { + handler.onNewIntent(intent); + } + Bundle bundle = this.getBundleFromIntent(intent); if (bundle != null) { mJsDelivery.notifyNotification(bundle);