From fcf12b9268d404b35588165ecc468aa47c803273 Mon Sep 17 00:00:00 2001 From: "Andrew Tremblay (Pear profile)" <43054023+andrewtremblay-pear@users.noreply.github.com> Date: Thu, 16 May 2019 09:42:02 -0400 Subject: [PATCH 001/179] typo --- submitting-a-pull-request.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/submitting-a-pull-request.md b/submitting-a-pull-request.md index 53e46e7ce..8611b5230 100644 --- a/submitting-a-pull-request.md +++ b/submitting-a-pull-request.md @@ -23,7 +23,7 @@ If you are testing someones PR, please provide the following feedback: * are you happy that the change in behaviour works as described, and you have tested the change on all affected operating systems? * in your opinion, is the code written _sensibly_? * is it clean and tidy? - * there are and unnecessary changes? + * there are any unnecessary changes? * is it documented appropriately? - \ No newline at end of file + From 9d3967b5a1f60fe47ee6fb399cfa3668cfdc871d Mon Sep 17 00:00:00 2001 From: Daniel Schlaug Date: Fri, 2 Aug 2019 10:05:18 +0200 Subject: [PATCH 002/179] Add PushNotificationIOS installation instruction link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b83be78fb..f5164e371 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Changelog is available from version 3.1.3 here: [Changelog](https://github.com/z `react-native link react-native-push-notification` +If you target iOS you also need to follow the [installation instructions for PushNotificationIOS](https://github.com/react-native-community/react-native-push-notification-ios) since this package depends on it. + **NOTE: For Android, you will still have to manually update the AndroidManifest.xml (as below) in order to use Scheduled Notifications.** ## Issues From 9c6b090b1d1f8bfce2684464e3ff2dad8806ef1a Mon Sep 17 00:00:00 2001 From: Narender Singh Date: Thu, 19 Mar 2020 17:47:07 +0530 Subject: [PATCH 003/179] add fire date in notification resposne --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index e43141fdb..d5c32021b 100644 --- a/index.js +++ b/index.js @@ -225,6 +225,7 @@ Notifications._onNotification = function(data, isFromBackground = null) { badge: data.getBadgeCount(), alert: data.getAlert(), sound: data.getSound(), + fireDate: data._fireDate, finish: (res) => data.finish(res) }); } else { From ad3888bce3546e704bcf7ff059240c0eaad5e962 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 9 May 2020 15:55:57 +0200 Subject: [PATCH 004/179] Prevent crash for NaN. --- .../modules/RNPushNotificationHelper.java | 32 ++++++++++++++---- index.js | 33 ++++++++++++++++--- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index bea187acc..3752ff466 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -80,13 +80,19 @@ private AlarmManager getAlarmManager() { } private PendingIntent toScheduleNotificationIntent(Bundle bundle) { - int notificationID = Integer.parseInt(bundle.getString("id")); + try { + int notificationID = Integer.parseInt(bundle.getString("id")); + + Intent notificationIntent = new Intent(context, RNPushNotificationPublisher.class); + notificationIntent.putExtra(RNPushNotificationPublisher.NOTIFICATION_ID, notificationID); + notificationIntent.putExtras(bundle); - Intent notificationIntent = new Intent(context, RNPushNotificationPublisher.class); - notificationIntent.putExtra(RNPushNotificationPublisher.NOTIFICATION_ID, notificationID); - notificationIntent.putExtras(bundle); + return PendingIntent.getBroadcast(context, notificationID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + } catch (Exception e) { + Log.e(LOG_TAG, "Unable to parse Notification ID", e); + } - return PendingIntent.getBroadcast(context, notificationID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + return null; } public void sendNotificationScheduled(Bundle bundle) { @@ -137,6 +143,10 @@ public void sendNotificationScheduledCore(Bundle bundle) { // notification to the user PendingIntent pendingIntent = toScheduleNotificationIntent(bundle); + if(pendingIntent == null) { + return; + } + Log.d(LOG_TAG, String.format("Setting a notification with id %s at time %s", bundle.getString("id"), Long.toString(fireDate))); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -636,7 +646,11 @@ private void cancelScheduledNotification(String notificationIDString) { // remove it from the alarm manger schedule Bundle b = new Bundle(); b.putString("id", notificationIDString); - getAlarmManager().cancel(toScheduleNotificationIntent(b)); + PendingIntent pendingIntent = toScheduleNotificationIntent(b); + + if(pendingIntent != null) { + getAlarmManager().cancel(pendingIntent); + } if (scheduledNotificationsPersistence.contains(notificationIDString)) { // remove it from local storage @@ -650,7 +664,11 @@ private void cancelScheduledNotification(String notificationIDString) { // removed it from the notification center NotificationManager notificationManager = notificationManager(); - notificationManager.cancel(Integer.parseInt(notificationIDString)); + try { + notificationManager.cancel(Integer.parseInt(notificationIDString)); + } catch (Exception e) { + Log.e(LOG_TAG, "Unable to parse Notification ID " + notificationIDString, e); + } } private NotificationManager notificationManager() { diff --git a/index.js b/index.js index a99c5f3ea..a89d2466e 100644 --- a/index.js +++ b/index.js @@ -141,13 +141,26 @@ Notifications.localNotification = function(details) { }); } else { if(details && typeof details.id === 'number') { - details.id = '' + details.id; + if(isNaN(details.id)) { + console.warn('NaN value has been passed as id'); + delete details.id; + } + else { + details.id = '' + details.id; + } } if(details && typeof details.number === 'number') { - details.number = '' + details.number; + if(isNaN(details.number)) { + console.warn('NaN value has been passed as number'); + delete details.number; + } + else { + details.number = '' + details.number; + } } + this.handler.presentLocalNotification(details); } }; @@ -187,11 +200,23 @@ Notifications.localNotificationSchedule = function(details) { this.handler.scheduleLocalNotification(iosDetails); } else { if(details && typeof details.id === 'number') { - details.id = '' + details.id; + if(isNaN(details.id)) { + console.warn('NaN value has been passed as id'); + delete details.id; + } + else { + details.id = '' + details.id; + } } if(details && typeof details.number === 'number') { - details.number = '' + details.number; + if(isNaN(details.number)) { + console.warn('NaN value has been passed as number'); + delete details.number; + } + else { + details.number = '' + details.number; + } } details.fireDate = details.date.getTime(); From fe5b52132cc4986c79abdfc57273b35312803eff Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 9 May 2020 16:07:55 +0200 Subject: [PATCH 005/179] Update CHANGELOG.md. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42a1287cc..94a6a93ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- (Android) `number` and `id` do not crash if NaN is passed in Android. + ## [3.4.0] - 2020-05-08 ### Features From 2948bb66facc0ca0e0e4a2b2d751d9d89b84f5d3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 13 May 2020 08:20:12 +0200 Subject: [PATCH 006/179] Prevent sound to be mute in default state. --- .../modules/RNPushNotificationHelper.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 3752ff466..141bf147f 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -369,11 +369,13 @@ public void sendToNotificationCentre(Bundle bundle) { } soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher - channel_id = channel_id + "-" + soundName; - } } + } else { + soundName = "default"; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher + channel_id = channel_id + "-" + soundName; } notification.setSound(soundUri); @@ -687,10 +689,13 @@ public void checkOrCreateDefaultChannel() { NotificationManager manager = notificationManager(); int importance = NotificationManager.IMPORTANCE_HIGH; + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-default-" + importance + "-" + DEFAULT_VIBRATION; + checkOrCreateChannel(manager, channel_id, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); - String channel_id = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; - - checkOrCreateChannel(manager, channel_id, null, importance, new long[] {0, DEFAULT_VIBRATION}); + String channel_id_no_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; + checkOrCreateChannel(manager, channel_id_no_sound, null, importance, new long[] {0, DEFAULT_VIBRATION}); } private void checkOrCreateChannel(NotificationManager manager, String channel_id, Uri soundUri, int importance, long[] vibratePattern) { From 807c6fdf760c74f1fbfb6f978c1d803a1e69777b Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 13 May 2020 08:24:27 +0200 Subject: [PATCH 007/179] Missing change on variable name. --- .../modules/RNPushNotificationHelper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 141bf147f..ff0cabe75 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -691,9 +691,11 @@ public void checkOrCreateDefaultChannel() { int importance = NotificationManager.IMPORTANCE_HIGH; Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + // Instanciate a default channel with default sound. String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-default-" + importance + "-" + DEFAULT_VIBRATION; - checkOrCreateChannel(manager, channel_id, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); + checkOrCreateChannel(manager, channel_id_sound, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); + // Instanciate a default channel without sound defined for backward compatibility. String channel_id_no_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; checkOrCreateChannel(manager, channel_id_no_sound, null, importance, new long[] {0, DEFAULT_VIBRATION}); } From 7e861c4246642865365eddf7ab464f9a50a72adc Mon Sep 17 00:00:00 2001 From: sarah denaci Date: Fri, 15 May 2020 17:48:24 -0400 Subject: [PATCH 008/179] feat: multiple push providers fix: fix naming fix: more fixes fix: more fixes fix: add activity service fix: update naming --- .../RNPushNotificationListenerService.java | 193 +--------------- .../modules/RNReceivedMessageHandler.java | 210 ++++++++++++++++++ 2 files changed, 213 insertions(+), 190 deletions(-) create mode 100644 android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index 4071b29f9..3ac932e5d 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -1,203 +1,16 @@ package com.dieam.reactnativepushnotification.modules; -import java.util.Map; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.Application; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.WritableMap; - -import org.json.JSONObject; - -import java.util.List; -import java.util.Random; - -import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; +import com.dieam.reactnativepushnotification.modules.RNReceivedMessageHandler; public class RNPushNotificationListenerService extends FirebaseMessagingService { - @Override - public void onNewToken(String token) { - final String deviceToken = token; - Log.d(LOG_TAG, "Refreshed token: " + deviceToken); - - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - public void run() { - // Construct and load our normal React JS code bundle - ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); - ReactContext context = mReactInstanceManager.getCurrentReactContext(); - // If it's constructed, send a notificationre - if (context != null) { - handleNewToken((ReactApplicationContext) context, deviceToken); - } else { - // Otherwise wait for construction, then send the notification - mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { - public void onReactContextInitialized(ReactContext context) { - handleNewToken((ReactApplicationContext) context, deviceToken); - } - }); - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - // Construct it in the background - mReactInstanceManager.createReactContextInBackground(); - } - } - } - }); - } - - private void handleNewToken(ReactApplicationContext context, String token) { - RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); - - WritableMap params = Arguments.createMap(); - params.putString("deviceToken", token); - jsDelivery.sendEvent("remoteNotificationsRegistered", params); - } - + private RNReceivedMessageHandler mMessageReceivedHandler = new RNReceivedMessageHandler(this); @Override public void onMessageReceived(RemoteMessage message) { - String from = message.getFrom(); - RemoteMessage.Notification remoteNotification = message.getNotification(); - final Bundle bundle = new Bundle(); - // Putting it from remoteNotification first so it can be overriden if message - // data has it - if (remoteNotification != null) { - // ^ It's null when message is from GCM - bundle.putString("title", remoteNotification.getTitle()); - bundle.putString("message", remoteNotification.getBody()); - bundle.putString("sound", remoteNotification.getSound()); - bundle.putString("color", remoteNotification.getColor()); - } - - Map notificationData = message.getData(); - - // Copy `twi_body` to `message` to support Twilio - if (notificationData.containsKey("twi_body")) { - bundle.putString("message", notificationData.get("twi_body")); - } - JSONObject data = getPushData(notificationData.get("data")); - - if (data != null) { - if (!bundle.containsKey("message")) { - bundle.putString("message", data.optString("alert", null)); - } - if (!bundle.containsKey("title")) { - bundle.putString("title", data.optString("title", null)); - } - if (!bundle.containsKey("sound")) { - bundle.putString("soundName", data.optString("sound", null)); - } - if (!bundle.containsKey("color")) { - bundle.putString("color", data.optString("color", null)); - } - - final int badge = data.optInt("badge", -1); - if (badge >= 0) { - ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(this, badge); - } - } - - Bundle dataBundle = new Bundle(); - for(Map.Entry entry : notificationData.entrySet()) { - dataBundle.putString(entry.getKey(), entry.getValue()); - } - bundle.putParcelable("data", dataBundle); - - Log.v(LOG_TAG, "onMessageReceived: " + bundle); - - // We need to run this on the main thread, as the React code assumes that is true. - // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: - // "Can't create handler inside thread that has not called Looper.prepare()" - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - public void run() { - // Construct and load our normal React JS code bundle - ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); - ReactContext context = mReactInstanceManager.getCurrentReactContext(); - // If it's constructed, send a notificationre - if (context != null) { - handleRemotePushNotification((ReactApplicationContext) context, bundle); - } else { - // Otherwise wait for construction, then send the notification - mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { - public void onReactContextInitialized(ReactContext context) { - handleRemotePushNotification((ReactApplicationContext) context, bundle); - } - }); - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - // Construct it in the background - mReactInstanceManager.createReactContextInBackground(); - } - } - } - }); - } - - private JSONObject getPushData(String dataString) { - try { - return new JSONObject(dataString); - } catch (Exception e) { - return null; - } - } - - private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) { - - // If notification ID is not provided by the user for push notification, generate one at random - if (bundle.getString("id") == null) { - Random randomNumberGenerator = new Random(System.currentTimeMillis()); - bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); - } - - RNPushNotificationConfig config = new RNPushNotificationConfig(getApplication()); - - Boolean isForeground = isApplicationInForeground(); - - RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); - bundle.putBoolean("foreground", isForeground); - bundle.putBoolean("userInteraction", false); - jsDelivery.notifyNotification(bundle); - - // If contentAvailable is set to true, then send out a remote fetch event - if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) { - jsDelivery.notifyRemoteFetch(bundle); - } - - Log.v(LOG_TAG, "sendNotification: " + bundle); - - if (config.getNotificationForeground() || !isForeground) { - Application applicationContext = (Application) context.getApplicationContext(); - RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); - pushNotificationHelper.sendToNotificationCentre(bundle); - } - } - - private boolean isApplicationInForeground() { - ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); - List processInfos = activityManager.getRunningAppProcesses(); - if (processInfos != null) { - for (RunningAppProcessInfo processInfo : processInfos) { - if (processInfo.processName.equals(getApplication().getPackageName()) - && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND - && processInfo.pkgList.length > 0) { - return true; - } - } - } - return false; + mMessageReceivedHandler.handleReceivedMessage(message); } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java new file mode 100644 index 000000000..9a7d33d59 --- /dev/null +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -0,0 +1,210 @@ +package com.dieam.reactnativepushnotification.modules; + +import java.util.Map; +import com.google.firebase.messaging.FirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.Application; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.support.annotation.NonNull; + +import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.WritableMap; + +import org.json.JSONObject; + +import java.util.List; +import java.util.Random; + +import static android.content.Context.ACTIVITY_SERVICE; +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; + + + +public class RNReceivedMessageHandler { + private FirebaseMessagingService mFirebaseMessagingService; + + public RNReceivedMessageHandler(@NonNull FirebaseMessagingService service) { + this.mFirebaseMessagingService = service; + } + + public void onNewToken(String token) { + final String deviceToken = token; + Log.d(LOG_TAG, "Refreshed token: " + deviceToken); + + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + public void run() { + // Construct and load our normal React JS code bundle + ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager(); + ReactContext context = mReactInstanceManager.getCurrentReactContext(); + // If it's constructed, send a notification + if (context != null) { + handleNewToken((ReactApplicationContext) context, deviceToken); + } else { + // Otherwise wait for construction, then send the notification + mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { + public void onReactContextInitialized(ReactContext context) { + handleNewToken((ReactApplicationContext) context, deviceToken); + } + }); + if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + mReactInstanceManager.createReactContextInBackground(); + } + } + } + }); + } + + private void handleNewToken(ReactApplicationContext context, String token) { + RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); + + WritableMap params = Arguments.createMap(); + params.putString("deviceToken", token); + jsDelivery.sendEvent("remoteNotificationsRegistered", params); + } + + public void handleReceivedMessage(RemoteMessage message) { + String from = message.getFrom(); + RemoteMessage.Notification remoteNotification = message.getNotification(); + final Bundle bundle = new Bundle(); + // Putting it from remoteNotification first so it can be overriden if message + // data has it + if (remoteNotification != null) { + // ^ It's null when message is from GCM + bundle.putString("title", remoteNotification.getTitle()); + bundle.putString("message", remoteNotification.getBody()); + bundle.putString("sound", remoteNotification.getSound()); + bundle.putString("color", remoteNotification.getColor()); + } + + Map notificationData = message.getData(); + + // Copy `twi_body` to `message` to support Twilio + if (notificationData.containsKey("twi_body")) { + bundle.putString("message", notificationData.get("twi_body")); + } + JSONObject data = getPushData(notificationData.get("data")); + + if (data != null) { + if (!bundle.containsKey("message")) { + bundle.putString("message", data.optString("alert", null)); + } + if (!bundle.containsKey("title")) { + bundle.putString("title", data.optString("title", null)); + } + if (!bundle.containsKey("sound")) { + bundle.putString("soundName", data.optString("sound", null)); + } + if (!bundle.containsKey("color")) { + bundle.putString("color", data.optString("color", null)); + } + + final int badge = data.optInt("badge", -1); + if (badge >= 0) { + ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(mFirebaseMessagingService, badge); + } + } + + Bundle dataBundle = new Bundle(); + for(Map.Entry entry : notificationData.entrySet()) { + dataBundle.putString(entry.getKey(), entry.getValue()); + } + bundle.putParcelable("data", dataBundle); + + Log.v(LOG_TAG, "onMessageReceived: " + bundle); + + // We need to run this on the main thread, as the React code assumes that is true. + // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: + // "Can't create handler inside thread that has not called Looper.prepare()" + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + public void run() { + // Construct and load our normal React JS code bundle + ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager(); + ReactContext context = mReactInstanceManager.getCurrentReactContext(); + // If it's constructed, send a notificationre + if (context != null) { + handleRemotePushNotification((ReactApplicationContext) context, bundle); + } else { + // Otherwise wait for construction, then send the notification + mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { + public void onReactContextInitialized(ReactContext context) { + handleRemotePushNotification((ReactApplicationContext) context, bundle); + } + }); + if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + mReactInstanceManager.createReactContextInBackground(); + } + } + } + }); + } + + private JSONObject getPushData(String dataString) { + try { + return new JSONObject(dataString); + } catch (Exception e) { + return null; + } + } + + private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) { + + // If notification ID is not provided by the user for push notification, generate one at random + if (bundle.getString("id") == null) { + Random randomNumberGenerator = new Random(System.currentTimeMillis()); + bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); + } + + RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); + + Boolean isForeground = isApplicationInForeground(); + + RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); + bundle.putBoolean("foreground", isForeground); + bundle.putBoolean("userInteraction", false); + jsDelivery.notifyNotification(bundle); + + // If contentAvailable is set to true, then send out a remote fetch event + if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) { + jsDelivery.notifyRemoteFetch(bundle); + } + + Log.v(LOG_TAG, "sendNotification: " + bundle); + + if (config.getNotificationForeground() || !isForeground) { + Application applicationContext = (Application) context.getApplicationContext(); + RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); + pushNotificationHelper.sendToNotificationCentre(bundle); + } + } + + private boolean isApplicationInForeground() { + ActivityManager activityManager = (ActivityManager) mFirebaseMessagingService.getSystemService(ACTIVITY_SERVICE); + List processInfos = activityManager.getRunningAppProcesses(); + if (processInfos != null) { + for (RunningAppProcessInfo processInfo : processInfos) { + if (processInfo.processName.equals(mFirebaseMessagingService.getPackageName()) + && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND + && processInfo.pkgList.length > 0) { + return true; + } + } + } + return false; + } + +} From 5716f1e8e1d722f0e3855c080fe5f7384fa08bbf Mon Sep 17 00:00:00 2001 From: sarah denaci Date: Mon, 18 May 2020 13:12:47 -0400 Subject: [PATCH 009/179] feat: explicitly override onNewToken --- .../modules/RNPushNotificationListenerService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index 3ac932e5d..80b4afc12 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -9,6 +9,11 @@ public class RNPushNotificationListenerService extends FirebaseMessagingService private RNReceivedMessageHandler mMessageReceivedHandler = new RNReceivedMessageHandler(this); + @Override + public void onNewToken(String token) { + mMessageReceivedHandler.onNewToken(token); + } + @Override public void onMessageReceived(RemoteMessage message) { mMessageReceivedHandler.handleReceivedMessage(message); From 821cad25872676e3f4082cb1f8753317f36d8023 Mon Sep 17 00:00:00 2001 From: Taymer Ragazzini Date: Tue, 19 May 2020 19:20:48 +0200 Subject: [PATCH 010/179] #1431 --- .../modules/RNPushNotification.java | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) 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 98fa1b185..dc9786034 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -38,7 +38,7 @@ import com.google.firebase.iid.InstanceIdResult; import com.google.firebase.messaging.FirebaseMessaging; -public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener { +public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener , Application.ActivityLifecycleCallbacks{ public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag private RNPushNotificationHelper mRNPushNotificationHelper; @@ -51,6 +51,7 @@ public RNPushNotification(ReactApplicationContext reactContext) { reactContext.addActivityEventListener(this); Application applicationContext = (Application) reactContext.getApplicationContext(); + applicationContext.registerActivityLifecycleCallbacks(this); // The @ReactNative methods use this mRNPushNotificationHelper = new RNPushNotificationHelper(applicationContext); @@ -81,6 +82,8 @@ private Bundle getBundleFromIntent(Intent intent) { } return bundle; } + + @Override public void onNewIntent(Intent intent) { Bundle bundle = this.getBundleFromIntent(intent); if (bundle != null) { @@ -277,4 +280,45 @@ public void run() { } }).start(); } + + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityStarted(Activity activity) { + Intent intent = activity.getIntent(); + Bundle bundle = this.getBundleFromIntent(intent); + if (bundle != null) { + bundle.putBoolean("foreground", false); + intent.putExtra("notification", bundle); + mJsDelivery.notifyNotification(bundle); + } + } + + @Override + public void onActivityResumed(Activity activity) { + + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } } From 2254fd4ae333a4bb65db8e5030c0ab39df4b4d26 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 19 May 2020 21:12:01 +0200 Subject: [PATCH 011/179] Move back onNewToken to Firebase service. --- .../RNPushNotificationListenerService.java | 48 ++++++++++++++++++- .../modules/RNReceivedMessageHandler.java | 41 +--------------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index 80b4afc12..9756c5416 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -3,7 +3,20 @@ import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.support.annotation.NonNull; + import com.dieam.reactnativepushnotification.modules.RNReceivedMessageHandler; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.WritableMap; + +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; public class RNPushNotificationListenerService extends FirebaseMessagingService { @@ -11,7 +24,40 @@ public class RNPushNotificationListenerService extends FirebaseMessagingService @Override public void onNewToken(String token) { - mMessageReceivedHandler.onNewToken(token); + final String deviceToken = token; + Log.d(LOG_TAG, "Refreshed token: " + deviceToken); + + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + public void run() { + // Construct and load our normal React JS code bundle + ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); + ReactContext context = mReactInstanceManager.getCurrentReactContext(); + // If it's constructed, send a notification + if (context != null) { + handleNewToken((ReactApplicationContext) context, deviceToken); + } else { + // Otherwise wait for construction, then send the notification + mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { + public void onReactContextInitialized(ReactContext context) { + handleNewToken((ReactApplicationContext) context, deviceToken); + } + }); + if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + mReactInstanceManager.createReactContextInBackground(); + } + } + } + }); + } + + private void handleNewToken(ReactApplicationContext context, String token) { + RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); + + WritableMap params = Arguments.createMap(); + params.putString("deviceToken", token); + jsDelivery.sendEvent("remoteNotificationsRegistered", params); } @Override diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 9a7d33d59..47244d89c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -1,6 +1,5 @@ package com.dieam.reactnativepushnotification.modules; -import java.util.Map; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; @@ -23,14 +22,13 @@ import org.json.JSONObject; +import java.util.Map; import java.util.List; import java.util.Random; import static android.content.Context.ACTIVITY_SERVICE; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; - - public class RNReceivedMessageHandler { private FirebaseMessagingService mFirebaseMessagingService; @@ -38,43 +36,6 @@ public RNReceivedMessageHandler(@NonNull FirebaseMessagingService service) { this.mFirebaseMessagingService = service; } - public void onNewToken(String token) { - final String deviceToken = token; - Log.d(LOG_TAG, "Refreshed token: " + deviceToken); - - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - public void run() { - // Construct and load our normal React JS code bundle - ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager(); - ReactContext context = mReactInstanceManager.getCurrentReactContext(); - // If it's constructed, send a notification - if (context != null) { - handleNewToken((ReactApplicationContext) context, deviceToken); - } else { - // Otherwise wait for construction, then send the notification - mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { - public void onReactContextInitialized(ReactContext context) { - handleNewToken((ReactApplicationContext) context, deviceToken); - } - }); - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - // Construct it in the background - mReactInstanceManager.createReactContextInBackground(); - } - } - } - }); - } - - private void handleNewToken(ReactApplicationContext context, String token) { - RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); - - WritableMap params = Arguments.createMap(); - params.putString("deviceToken", token); - jsDelivery.sendEvent("remoteNotificationsRegistered", params); - } - public void handleReceivedMessage(RemoteMessage message) { String from = message.getFrom(); RemoteMessage.Notification remoteNotification = message.getNotification(); From 70b7e7c7937c361ccd541e6c3cdfbe22f24bef9c Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 20 May 2020 19:35:06 +0200 Subject: [PATCH 012/179] Bump to 3.5.0. --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a6a93ca..9c38be55a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +## [3.5.0] - 2020-05-20 + +### Features + +- (Android) Enables the ability to support multiple push providers [#1445](https://github.com/zo0r/react-native-push-notification/pull/1445) + +### Fixed + +- (Android) No sound on notifications [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432) +- (Android) onNotification is not calling when app is in background [#1446](https://github.com/zo0r/react-native-push-notification/pull/1446) - (Android) `number` and `id` do not crash if NaN is passed in Android. ## [3.4.0] - 2020-05-08 diff --git a/package.json b/package.json index b1b84c444..8ee938ee4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "3.4.0", + "version": "3.5.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 278c9aec39b04dcb26f34efb32ec4db437cc72bc Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 21 May 2020 21:17:57 +0200 Subject: [PATCH 013/179] Switch from support library to androidx. #1449 --- .../modules/RNPushNotificationListenerService.java | 1 - .../modules/RNReceivedMessageHandler.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index 9756c5416..df0c52d02 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -6,7 +6,6 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.support.annotation.NonNull; import com.dieam.reactnativepushnotification.modules.RNReceivedMessageHandler; import com.facebook.react.ReactApplication; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 47244d89c..04038bc07 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -10,7 +10,7 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; import com.facebook.react.ReactApplication; From 24529091d202f7e45d2c428bfa3cc561b0344ef7 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 21 May 2020 21:23:05 +0200 Subject: [PATCH 014/179] Bump to 3.5.1. --- CHANGELOG.md | 8 +++++++- package.json | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c38be55a..0781577ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +## [3.5.1] - 2020-05-20 + +### Fixed + +- (Android) When updating 3.4 to 3.5, unable to compile Android [#1449](https://github.com/zo0r/react-native-push-notification/pull/1449) + ## [3.5.0] - 2020-05-20 ### Features @@ -20,7 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - (Android) No sound on notifications [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432) -- (Android) onNotification is not calling when app is in background [#1446](https://github.com/zo0r/react-native-push-notification/pull/1446) +- (Android) onNotification is not calling when app is in background [#1446](https://github.com/zo0r/react-native-push-notification/pull/1446) - (Android) `number` and `id` do not crash if NaN is passed in Android. ## [3.4.0] - 2020-05-08 diff --git a/package.json b/package.json index 8ee938ee4..235e47ed2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "3.5.0", + "version": "3.5.1", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { @@ -14,7 +14,7 @@ "notifications", "push", "apns", - "gcm" + "firebase" ], "bugs": { "url": "https://github.com/zo0r/react-native-push-notification/issues" From 23e0cb4ee17395c634e687f3b1b74cb7cb2824ea Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 24 May 2020 18:33:55 +0200 Subject: [PATCH 015/179] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b718613b..f06bbfe6c 100644 --- a/README.md +++ b/README.md @@ -478,7 +478,7 @@ https://developer.android.com/training/monitoring-device-state/doze-standby ## Repeating Notifications -(optional) Specify `repeatType` and optionally `repeatTime` while scheduling the local notification. Check the local notification example above. +(optional) Specify `repeatType` and optionally `repeatTime` (Android-only) while scheduling the local notification. Check the local notification example above. Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, `time`. If specified as time, it should be accompanied by one more parameter `repeatTime` which should the number of milliseconds between each interval. From 9f69896c7cda24df4410f5a5694a50d7ab691cc9 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 25 May 2020 09:46:40 +0200 Subject: [PATCH 016/179] Fix sounds volume and DND is ignored. Fix #1455 `onNotification fires every time when the app goes from background to foreground` --- .../modules/RNPushNotification.java | 42 ------------------- .../modules/RNPushNotificationHelper.java | 2 +- index.js | 15 ++++--- 3 files changed, 10 insertions(+), 49 deletions(-) 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 dc9786034..168230fea 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -51,7 +51,6 @@ public RNPushNotification(ReactApplicationContext reactContext) { reactContext.addActivityEventListener(this); Application applicationContext = (Application) reactContext.getApplicationContext(); - applicationContext.registerActivityLifecycleCallbacks(this); // The @ReactNative methods use this mRNPushNotificationHelper = new RNPushNotificationHelper(applicationContext); @@ -280,45 +279,4 @@ public void run() { } }).start(); } - - @Override - public void onActivityCreated(Activity activity, Bundle bundle) { - - } - - @Override - public void onActivityStarted(Activity activity) { - Intent intent = activity.getIntent(); - Bundle bundle = this.getBundleFromIntent(intent); - if (bundle != null) { - bundle.putBoolean("foreground", false); - intent.putExtra("notification", bundle); - mJsDelivery.notifyNotification(bundle); - } - } - - @Override - public void onActivityResumed(Activity activity) { - - } - - @Override - public void onActivityPaused(Activity activity) { - - } - - @Override - public void onActivityStopped(Activity activity) { - - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { - - } - - @Override - public void onActivityDestroyed(Activity activity) { - - } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ff0cabe75..84bb493ee 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -719,7 +719,7 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id if (soundUri != null) { AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_ALARM) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) .build(); channel.setSound(soundUri, audioAttributes); diff --git a/index.js b/index.js index a89d2466e..3dd36a8f9 100644 --- a/index.js +++ b/index.js @@ -18,7 +18,7 @@ var Notifications = { onNotification: false, onRemoteFetch: false, isLoaded: false, - hasPoppedInitialNotification: false, + idInitialNotification: null, isPermissionsRequestPending: false, @@ -84,14 +84,17 @@ Notifications.configure = function(options) { this.isLoaded = true; } - if ( this.hasPoppedInitialNotification === false && - ( options.popInitialNotification === undefined || options.popInitialNotification === true ) ) { + if (options.popInitialNotification === undefined || options.popInitialNotification === true) { this.popInitialNotification(function(firstNotification) { if ( firstNotification !== null ) { - this._onNotification(firstNotification, true); + if(this.idInitialNotification === firstNotification.id) { + return; + } + + this.idInitialNotification = firstNotification.id; + this._onNotification(firstNotification, true); } - }.bind(this)); - this.hasPoppedInitialNotification = true; + }.bind(this)); } if ( options.requestPermissions !== false ) { From f8a00487755a39d4b03ad7b6d435ab2eac82eb37 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 25 May 2020 09:52:24 +0200 Subject: [PATCH 017/179] Remove extra interface. --- .../reactnativepushnotification/modules/RNPushNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 168230fea..4ceb65d5c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -38,7 +38,7 @@ import com.google.firebase.iid.InstanceIdResult; import com.google.firebase.messaging.FirebaseMessaging; -public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener , Application.ActivityLifecycleCallbacks{ +public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener { public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag private RNPushNotificationHelper mRNPushNotificationHelper; From 1d497e60a142b4a846907ec19b80ab72a5ae5c8d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 25 May 2020 09:57:38 +0200 Subject: [PATCH 018/179] Bump to 3.5.2. --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0781577ee..22a882392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +## [3.5.2] - 2020-05-25 + +### Fixed + +- (Android) Sounds are playing even in Do Not Disturb [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432#issuecomment-633367111) +- (Android) onNotification fires every time when the app goes from background to foreground [#1455](https://github.com/zo0r/react-native-push-notification/issues/1455) +- (Android) Cannot send to notification centre because there is no 'message' field in: Bundle [#1452](https://github.com/zo0r/react-native-push-notification/issues/1452) + ## [3.5.1] - 2020-05-20 ### Fixed diff --git a/package.json b/package.json index 235e47ed2..cc11f1c34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "3.5.1", + "version": "3.5.2", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 742204b56ffcaa10e8506cd8b605383e76210343 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 25 May 2020 09:58:46 +0200 Subject: [PATCH 019/179] Add the possibility to override Channel Name and Channel Description based on channel ID. --- .../modules/RNPushNotificationConfig.java | 36 ++++++++++--------- .../modules/RNPushNotificationHelper.java | 4 +-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index f65a8dfc5..e2a6aa170 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -30,29 +30,31 @@ public RNPushNotificationConfig(Context context) { } } - public String getChannelName() { + private String getStringValue(String key, String defaultValue) { try { - final String name = metadata.getString(KEY_CHANNEL_NAME); - if (name != null && name.length() > 0) { - return name; + final String value = metadata.getString(key); + + if (value != null && name.length() > 0) { + return value; } } catch (Exception e) { - Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_NAME + " in manifest. Falling back to default"); + Log.w(RNPushNotification.LOG_TAG, "Unable to find " + key + " in manifest. Falling back to default"); } + // Default - return "rn-push-notification-channel"; + return defaultValue; } - public String getChannelDescription() { - try { - final String description = metadata.getString(KEY_CHANNEL_DESCRIPTION); - if (description != null) { - return description; - } - } catch (Exception e) { - Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_DESCRIPTION + " in manifest. Falling back to default"); - } - // Default - return ""; + + public String getChannelName(String channel_id) { + String overrided = this.getStringValue(KEY_CHANNEL_NAME + "." + channel_id, "rn-push-notification-channel"); + + return this.getStringValue(KEY_CHANNEL_NAME, overrided); + } + + public String getChannelDescription(String channel_id) { + String overrided = this.getStringValue(KEY_CHANNEL_DESCRIPTION + "." + channel_id, ""); + + return this.getStringValue(KEY_CHANNEL_DESCRIPTION, overrided); } public int getNotificationColor() { diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 84bb493ee..6e5d47a17 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -709,9 +709,9 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id NotificationChannel channel = manager.getNotificationChannel(channel_id); if (channel == null) { - channel = new NotificationChannel(channel_id, this.config.getChannelName() != null ? this.config.getChannelName() : "rn-push-notification-channel", importance); + channel = new NotificationChannel(channel_id, this.config.getChannelName(channel_id), importance); - channel.setDescription(this.config.getChannelDescription()); + channel.setDescription(this.config.getChannelDescription(channel_id)); channel.enableLights(true); channel.enableVibration(true); channel.setVibrationPattern(vibratePattern); From f0406bee16afcee2d97a5d4b86a81f5911407b26 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 25 May 2020 10:05:44 +0200 Subject: [PATCH 020/179] Fix changelog, wrong issue mentioned. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a882392..b0e8773c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Sounds are playing even in Do Not Disturb [#1432](https://github.com/zo0r/react-native-push-notification/issues/1432#issuecomment-633367111) - (Android) onNotification fires every time when the app goes from background to foreground [#1455](https://github.com/zo0r/react-native-push-notification/issues/1455) -- (Android) Cannot send to notification centre because there is no 'message' field in: Bundle [#1452](https://github.com/zo0r/react-native-push-notification/issues/1452) +- (Android) java.lang.NullPointerException: Attempt to invoke virtual method 'void com.dieam.reactnativepushnotification.modules.d.c(android.os.Bundle)' on a null object reference [#1431](https://github.com/zo0r/react-native-push-notification/issues/1431#issuecomment-633315150) ## [3.5.1] - 2020-05-20 From bbe5248223eac03bff8ac26150cdf036cb364418 Mon Sep 17 00:00:00 2001 From: xvonabur Date: Fri, 15 May 2020 16:51:58 +0300 Subject: [PATCH 021/179] Add missing push timestamp for Android 7+ --- .../modules/RNPushNotificationHelper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index bea187acc..e0482609b 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -265,6 +265,12 @@ public void sendToNotificationCentre(Bundle bundle) { .setPriority(priority) .setAutoCancel(bundle.getBoolean("autoCancel", true)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24 and higher + // Restore showing timestamp on Android 7+ + // Source: https://developer.android.com/reference/android/app/Notification.Builder.html#setShowWhen(boolean) + notification.setShowWhen(true); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher // Changing Default mode of notification notification.setDefaults(Notification.DEFAULT_LIGHTS); From a85e681a7679634a78981280b7ebd40667e0ba20 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 19:09:59 +0200 Subject: [PATCH 022/179] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a882392..772db677d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features +- (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) + ### Fixed ## [3.5.2] - 2020-05-25 From af4373165383bed12559337fc00f97627e4da191 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 19:10:52 +0200 Subject: [PATCH 023/179] Add custom channel-id support. --- README.md | 2 +- .../modules/RNPushNotificationHelper.java | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f06bbfe6c..3aa934e62 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,7 @@ PushNotification.localNotification({ importance: "high", // (optional) set notification importance, default: high allowWhileIdle: false, // (optional) set notification to work while on doze, default: false ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) + channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created custom channel, it will apply options of the channel. /* iOS only properties */ alertAction: "view", // (optional) default: view @@ -418,7 +419,6 @@ Removes the specified notifications from Notification Center | ----------- | ----- | -------- | ---------------------------------- | | identifiers | array | Yes | Array of notification identifiers. | - ## Abandon Permissions `PushNotification.abandonPermissions()` Revokes the current token and unregister for all remote notifications received via APNS or FCM. diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 6e5d47a17..8dbfe49b3 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -419,7 +419,14 @@ public void sendToNotificationCentre(Bundle bundle) { vibratePattern = new long[]{0, vibration}; - notification.setVibrate(vibratePattern); + notification.setVibrate(vibratePattern); + } + + // Override channel_id if there is one provided + String customChannelId = bundle.getString("channelId"); + + if (customChannelId != null) { + channel_id = customChannelId; } checkOrCreateChannel(notificationManager, channel_id, soundUri, importance, vibratePattern); From 86bbf60aa3e537a05c97ebe7fa1348408ac7c555 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 20:32:15 +0200 Subject: [PATCH 024/179] Add shortcutId for better badge management. --- CHANGELOG.md | 2 + README.md | 1 + .../modules/RNPushNotificationHelper.java | 67 +-- index.js | 465 +++++++++--------- 4 files changed, 283 insertions(+), 252 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 772db677d..2f889387d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features +- (Android) Add `shortcutId` for better badges management. +- (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) ### Fixed diff --git a/README.md b/README.md index 3aa934e62..ed92396d1 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,7 @@ PushNotification.localNotification({ importance: "high", // (optional) set notification importance, default: high allowWhileIdle: false, // (optional) set notification to work while on doze, default: false ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) + shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created custom channel, it will apply options of the channel. /* iOS only properties */ diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 8dbfe49b3..c1436c609 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -217,35 +217,35 @@ public void sendToNotificationCentre(Bundle bundle) { } int importance = NotificationManager.IMPORTANCE_HIGH; - final String importanceString = bundle.getString("importance"); - - if (importanceString != null) { - switch(importanceString.toLowerCase()) { - case "default": - importance = NotificationManager.IMPORTANCE_DEFAULT; - break; - case "max": - importance = NotificationManager.IMPORTANCE_MAX; - break; - case "high": - importance = NotificationManager.IMPORTANCE_HIGH; - break; - case "low": - importance = NotificationManager.IMPORTANCE_LOW; - break; - case "min": - importance = NotificationManager.IMPORTANCE_MIN; - break; - case "none": - importance = NotificationManager.IMPORTANCE_NONE; - break; - case "unspecified": - importance = NotificationManager.IMPORTANCE_UNSPECIFIED; - break; - default: - importance = NotificationManager.IMPORTANCE_HIGH; - } - } + final String importanceString = bundle.getString("importance"); + + if (importanceString != null) { + switch(importanceString.toLowerCase()) { + case "default": + importance = NotificationManager.IMPORTANCE_DEFAULT; + break; + case "max": + importance = NotificationManager.IMPORTANCE_MAX; + break; + case "high": + importance = NotificationManager.IMPORTANCE_HIGH; + break; + case "low": + importance = NotificationManager.IMPORTANCE_LOW; + break; + case "min": + importance = NotificationManager.IMPORTANCE_MIN; + break; + case "none": + importance = NotificationManager.IMPORTANCE_NONE; + break; + case "unspecified": + importance = NotificationManager.IMPORTANCE_UNSPECIFIED; + break; + default: + importance = NotificationManager.IMPORTANCE_HIGH; + } + } channel_id = channel_id + "-" + importance; @@ -422,6 +422,15 @@ public void sendToNotificationCentre(Bundle bundle) { notification.setVibrate(vibratePattern); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Define the shortcutId + String shortcutId = bundle.getString("shortcutId"); + + if (shortcutId != null) { + notification.setShortcutId(shortcutId); + } + } + // Override channel_id if there is one provided String customChannelId = bundle.getString("channelId"); diff --git a/index.js b/index.js index 3ae6a3ec1..cb52e1e47 100644 --- a/index.js +++ b/index.js @@ -12,137 +12,137 @@ var RNNotifications = RNNotificationsComponent.component; var Platform = require('react-native').Platform; var Notifications = { - handler: RNNotifications, - onRegister: false, - onError: false, - onNotification: false, + handler: RNNotifications, + onRegister: false, + onError: false, + onNotification: false, onRemoteFetch: false, - isLoaded: false, - idInitialNotification: null, + isLoaded: false, + idInitialNotification: null, - isPermissionsRequestPending: false, + isPermissionsRequestPending: false, - permissions: { - alert: true, - badge: true, - sound: true - } + permissions: { + alert: true, + badge: true, + sound: true + } }; Notifications.callNative = function(name, params) { - if ( typeof this.handler[name] === 'function' ) { - if ( typeof params !== 'array' && - typeof params !== 'object' ) { - params = []; - } - - return this.handler[name](...params); - } else { - return null; - } + if ( typeof this.handler[name] === 'function' ) { + if ( typeof params !== 'array' && + typeof params !== 'object' ) { + params = []; + } + + return this.handler[name](...params); + } else { + return null; + } }; /** * Configure local and remote notifications - * @param {Object} options - * @param {function} options.onRegister - Fired when the user registers for remote notifications. - * @param {function} options.onNotification - Fired when a remote notification is received. - * @param {function} options.onError - None - * @param {Object} options.permissions - Permissions list - * @param {Boolean} options.requestPermissions - Check permissions when register + * @param {Object} options + * @param {function} options.onRegister - Fired when the user registers for remote notifications. + * @param {function} options.onNotification - Fired when a remote notification is received. + * @param {function} options.onError - None + * @param {Object} options.permissions - Permissions list + * @param {Boolean} options.requestPermissions - Check permissions when register */ Notifications.configure = function(options) { - if ( typeof options.onRegister !== 'undefined' ) { - this.onRegister = options.onRegister; - } - - if ( typeof options.onError !== 'undefined' ) { - this.onError = options.onError; - } - - if ( typeof options.onNotification !== 'undefined' ) { - this.onNotification = options.onNotification; - } - - if ( typeof options.permissions !== 'undefined' ) { - this.permissions = options.permissions; - } - - if ( typeof options.onRemoteFetch !== 'undefined' ) { - this.onRemoteFetch = options.onRemoteFetch; - } - - if ( this.isLoaded === false ) { - this._onRegister = this._onRegister.bind(this); - this._onNotification = this._onNotification.bind(this); - this._onRemoteFetch = this._onRemoteFetch.bind(this); - this.callNative( 'addEventListener', [ 'register', this._onRegister ] ); - this.callNative( 'addEventListener', [ 'notification', this._onNotification ] ); - this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] ); - Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null - - this.isLoaded = true; - } - - if (options.popInitialNotification === undefined || options.popInitialNotification === true) { - this.popInitialNotification(function(firstNotification) { - if ( firstNotification !== null ) { + if ( typeof options.onRegister !== 'undefined' ) { + this.onRegister = options.onRegister; + } + + if ( typeof options.onError !== 'undefined' ) { + this.onError = options.onError; + } + + if ( typeof options.onNotification !== 'undefined' ) { + this.onNotification = options.onNotification; + } + + if ( typeof options.permissions !== 'undefined' ) { + this.permissions = options.permissions; + } + + if ( typeof options.onRemoteFetch !== 'undefined' ) { + this.onRemoteFetch = options.onRemoteFetch; + } + + if ( this.isLoaded === false ) { + this._onRegister = this._onRegister.bind(this); + this._onNotification = this._onNotification.bind(this); + this._onRemoteFetch = this._onRemoteFetch.bind(this); + this.callNative( 'addEventListener', [ 'register', this._onRegister ] ); + this.callNative( 'addEventListener', [ 'notification', this._onNotification ] ); + this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] ); + Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null + + this.isLoaded = true; + } + + if (options.popInitialNotification === undefined || options.popInitialNotification === true) { + this.popInitialNotification(function(firstNotification) { + if ( firstNotification !== null ) { if(this.idInitialNotification === firstNotification.id) { return; } this.idInitialNotification = firstNotification.id; this._onNotification(firstNotification, true); - } + } }.bind(this)); - } + } - if ( options.requestPermissions !== false ) { - this._requestPermissions(); - } + if ( options.requestPermissions !== false ) { + this._requestPermissions(); + } }; /* Unregister */ Notifications.unregister = function() { - this.callNative( 'removeEventListener', [ 'register', this._onRegister ] ) - this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] ) - this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] ) - Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null - this.isLoaded = false; + this.callNative( 'removeEventListener', [ 'register', this._onRegister ] ) + this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] ) + this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] ) + Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null + this.isLoaded = false; }; /** * Local Notifications - * @param {Object} details - * @param {String} details.title - The title displayed in the notification alert. - * @param {String} details.message - The message displayed in the notification alert. - * @param {String} details.ticker - ANDROID ONLY: The ticker displayed in the status bar. - * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert. + * @param {Object} details + * @param {String} details.title - The title displayed in the notification alert. + * @param {String} details.message - The message displayed in the notification alert. + * @param {String} details.ticker - ANDROID ONLY: The ticker displayed in the status bar. + * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert. */ Notifications.localNotification = function(details) { - if ( Platform.OS === 'ios' ) { - // https://developer.apple.com/reference/uikit/uilocalnotification - - let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour - - if (details.hasOwnProperty('playSound') && !details.playSound) { - soundName = ''; // empty string results in no sound (and no vibration) - } - - // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html - // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle - - this.handler.presentLocalNotification({ - alertTitle: details.title, - alertBody: details.message, - alertAction: details.alertAction, - category: details.category, - soundName: soundName, - applicationIconBadgeNumber: details.number, - userInfo: details.userInfo - }); - } else { + if ( Platform.OS === 'ios' ) { + // https://developer.apple.com/reference/uikit/uilocalnotification + + let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour + + if (details.hasOwnProperty('playSound') && !details.playSound) { + soundName = ''; // empty string results in no sound (and no vibration) + } + + // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html + // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle + + this.handler.presentLocalNotification({ + alertTitle: details.title, + alertBody: details.message, + alertAction: details.alertAction, + category: details.category, + soundName: soundName, + applicationIconBadgeNumber: details.number, + userInfo: details.userInfo + }); + } else { if(details && typeof details.id === 'number') { if(isNaN(details.id)) { console.warn('NaN value has been passed as id'); @@ -162,46 +162,55 @@ Notifications.localNotification = function(details) { details.number = '' + details.number; } } + + if(details && typeof details.shortcutId === 'number') { + if(isNaN(details.shortcutId)) { + console.warn('NaN value has been passed as shortcutId'); + delete details.shortcutId; + } + else { + details.shortcutId = '' + details.shortcutId; + } + } - - this.handler.presentLocalNotification(details); - } + this.handler.presentLocalNotification(details); + } }; /** * Local Notifications Schedule - * @param {Object} details (same as localNotification) - * @param {Date} details.date - The date and time when the system should deliver the notification + * @param {Object} details (same as localNotification) + * @param {Date} details.date - The date and time when the system should deliver the notification */ Notifications.localNotificationSchedule = function(details) { - if ( Platform.OS === 'ios' ) { - let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour - - if (details.hasOwnProperty('playSound') && !details.playSound) { - soundName = ''; // empty string results in no sound (and no vibration) - } - - const iosDetails = { - fireDate: details.date.toISOString(), - alertTitle: details.title, - alertBody: details.message, - category: details.category, - soundName: soundName, - userInfo: details.userInfo, - repeatInterval: details.repeatType, - category: details.category, - }; - - if(details.number) { - iosDetails.applicationIconBadgeNumber = parseInt(details.number, 10); - } - - // ignore Android only repeatType - if (!details.repeatType || details.repeatType === 'time') { - delete iosDetails.repeatInterval; - } - this.handler.scheduleLocalNotification(iosDetails); - } else { + if ( Platform.OS === 'ios' ) { + let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour + + if (details.hasOwnProperty('playSound') && !details.playSound) { + soundName = ''; // empty string results in no sound (and no vibration) + } + + const iosDetails = { + fireDate: details.date.toISOString(), + alertTitle: details.title, + alertBody: details.message, + category: details.category, + soundName: soundName, + userInfo: details.userInfo, + repeatInterval: details.repeatType, + category: details.category, + }; + + if(details.number) { + iosDetails.applicationIconBadgeNumber = parseInt(details.number, 10); + } + + // ignore Android only repeatType + if (!details.repeatType || details.repeatType === 'time') { + delete iosDetails.repeatInterval; + } + this.handler.scheduleLocalNotification(iosDetails); + } else { if(details && typeof details.id === 'number') { if(isNaN(details.id)) { console.warn('NaN value has been passed as id'); @@ -221,121 +230,131 @@ Notifications.localNotificationSchedule = function(details) { details.number = '' + details.number; } } + + if(details && typeof details.shortcutId === 'number') { + if(isNaN(details.shortcutId)) { + console.warn('NaN value has been passed as shortcutId'); + delete details.shortcutId; + } + else { + details.shortcutId = '' + details.shortcutId; + } + } - details.fireDate = details.date.getTime(); - delete details.date; - // ignore iOS only repeatType - if (['year'].includes(details.repeatType)) { - delete details.repeatType; - } - this.handler.scheduleLocalNotification(details); - } + details.fireDate = details.date.getTime(); + delete details.date; + // ignore iOS only repeatType + if (['year'].includes(details.repeatType)) { + delete details.repeatType; + } + this.handler.scheduleLocalNotification(details); + } }; /* Internal Functions */ Notifications._onRegister = function(token) { - if ( this.onRegister !== false ) { - this.onRegister({ - token: token, - os: Platform.OS - }); - } + if ( this.onRegister !== false ) { + this.onRegister({ + token: token, + os: Platform.OS + }); + } }; Notifications._onRemoteFetch = function(notificationData) { - if ( this.onRemoteFetch !== false ) { - this.onRemoteFetch(notificationData) - } + if ( this.onRemoteFetch !== false ) { + this.onRemoteFetch(notificationData) + } }; Notifications._onNotification = function(data, isFromBackground = null) { - if ( isFromBackground === null ) { - isFromBackground = ( - data.foreground === false || - AppState.currentState === 'background' - ); - } - - if ( this.onNotification !== false ) { - if ( Platform.OS === 'ios' ) { - this.onNotification({ - foreground: ! isFromBackground, - userInteraction: isFromBackground, - message: data.getMessage(), - data: data.getData(), - badge: data.getBadgeCount(), - alert: data.getAlert(), - sound: data.getSound(), - fireDate: data._fireDate, - finish: (res) => data.finish(res) - }); - } else { - var notificationData = { - foreground: ! isFromBackground, - finish: () => {}, - ...data - }; - - if ( typeof notificationData.data === 'string' ) { - try { - notificationData.data = JSON.parse(notificationData.data); - } catch(e) { - /* void */ - } - } - - this.onNotification(notificationData); - } - } + if ( isFromBackground === null ) { + isFromBackground = ( + data.foreground === false || + AppState.currentState === 'background' + ); + } + + if ( this.onNotification !== false ) { + if ( Platform.OS === 'ios' ) { + this.onNotification({ + foreground: ! isFromBackground, + userInteraction: isFromBackground, + message: data.getMessage(), + data: data.getData(), + badge: data.getBadgeCount(), + alert: data.getAlert(), + sound: data.getSound(), + fireDate: data._fireDate, + finish: (res) => data.finish(res) + }); + } else { + var notificationData = { + foreground: ! isFromBackground, + finish: () => {}, + ...data + }; + + if ( typeof notificationData.data === 'string' ) { + try { + notificationData.data = JSON.parse(notificationData.data); + } catch(e) { + /* void */ + } + } + + this.onNotification(notificationData); + } + } }; /* onResultPermissionResult */ Notifications._onPermissionResult = function() { - this.isPermissionsRequestPending = false; + this.isPermissionsRequestPending = false; }; // Prevent requestPermissions called twice if ios result is pending Notifications._requestPermissions = function() { - if ( Platform.OS === 'ios' ) { - if ( this.isPermissionsRequestPending === false ) { - this.isPermissionsRequestPending = true; - return this.callNative( 'requestPermissions', [ this.permissions ]) - .then(this._onPermissionResult.bind(this)) - .catch(this._onPermissionResult.bind(this)); - } - } else if (Platform.OS === 'android') { - return this.callNative( 'requestPermissions', []); - } + if ( Platform.OS === 'ios' ) { + if ( this.isPermissionsRequestPending === false ) { + this.isPermissionsRequestPending = true; + return this.callNative( 'requestPermissions', [ this.permissions ]) + .then(this._onPermissionResult.bind(this)) + .catch(this._onPermissionResult.bind(this)); + } + } else if (Platform.OS === 'android') { + return this.callNative( 'requestPermissions', []); + } }; // Stock requestPermissions function Notifications.requestPermissions = function() { - if ( Platform.OS === 'ios' ) { - return this.callNative( 'requestPermissions', [ this.permissions ]); - } else if (Platform.OS === 'android') { - return this.callNative( 'requestPermissions', []); - } + if ( Platform.OS === 'ios' ) { + return this.callNative( 'requestPermissions', [ this.permissions ]); + } else if (Platform.OS === 'android') { + return this.callNative( 'requestPermissions', []); + } }; /* Fallback functions */ Notifications.subscribeToTopic = function() { - return this.callNative('subscribeToTopic', arguments); + return this.callNative('subscribeToTopic', arguments); }; Notifications.unsubscribeFromTopic = function () { - return this.callNative('unsubscribeFromTopic', arguments); + return this.callNative('unsubscribeFromTopic', arguments); }; Notifications.presentLocalNotification = function() { - return this.callNative('presentLocalNotification', arguments); + return this.callNative('presentLocalNotification', arguments); }; Notifications.scheduleLocalNotification = function() { - return this.callNative('scheduleLocalNotification', arguments); + return this.callNative('scheduleLocalNotification', arguments); }; Notifications.cancelLocalNotifications = function() { - return this.callNative('cancelLocalNotifications', arguments); + return this.callNative('cancelLocalNotifications', arguments); }; Notifications.clearLocalNotification = function() { @@ -343,51 +362,51 @@ Notifications.clearLocalNotification = function() { }; Notifications.cancelAllLocalNotifications = function() { - return this.callNative('cancelAllLocalNotifications', arguments); + return this.callNative('cancelAllLocalNotifications', arguments); }; Notifications.setApplicationIconBadgeNumber = function() { - return this.callNative('setApplicationIconBadgeNumber', arguments); + return this.callNative('setApplicationIconBadgeNumber', arguments); }; Notifications.getApplicationIconBadgeNumber = function() { - return this.callNative('getApplicationIconBadgeNumber', arguments); + return this.callNative('getApplicationIconBadgeNumber', arguments); }; Notifications.popInitialNotification = function(handler) { - this.callNative('getInitialNotification').then(function(result){ - handler(result); - }); + this.callNative('getInitialNotification').then(function(result){ + handler(result); + }); }; Notifications.checkPermissions = function() { - return this.callNative('checkPermissions', arguments); + return this.callNative('checkPermissions', arguments); }; /* Abandon Permissions */ Notifications.abandonPermissions = function() { - return this.callNative('abandonPermissions', arguments); + return this.callNative('abandonPermissions', arguments); } Notifications.registerNotificationActions = function() { - return this.callNative('registerNotificationActions', arguments) + return this.callNative('registerNotificationActions', arguments) } Notifications.clearAllNotifications = function() { - // Only available for Android - return this.callNative('clearAllNotifications', arguments) + // Only available for Android + return this.callNative('clearAllNotifications', arguments) } Notifications.removeAllDeliveredNotifications = function() { - return this.callNative('removeAllDeliveredNotifications', arguments); + return this.callNative('removeAllDeliveredNotifications', arguments); } Notifications.getDeliveredNotifications = function() { - return this.callNative('getDeliveredNotifications', arguments); + return this.callNative('getDeliveredNotifications', arguments); } Notifications.removeDeliveredNotifications = function() { - return this.callNative('removeDeliveredNotifications', arguments); + return this.callNative('removeDeliveredNotifications', arguments); } module.exports = Notifications; From b619e923b41df07f4c37f3ed4a542963e478e0a3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 20:32:42 +0200 Subject: [PATCH 025/179] Improve documentation for Channel Management. --- README.md | 47 ++++++++++++++++++- .../android/app/src/main/AndroidManifest.xml | 7 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ed92396d1..1dcf404fa 100644 --- a/README.md +++ b/README.md @@ -293,7 +293,7 @@ PushNotification.localNotification({ allowWhileIdle: false, // (optional) set notification to work while on doze, default: false ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined - channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created custom channel, it will apply options of the channel. + channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. /* iOS only properties */ alertAction: "view", // (optional) default: view @@ -335,6 +335,51 @@ In the location notification json specify the full file name: soundName: 'my_sound.mp3' +## Channel Management (Android) + +This library doesn't include a full Channel Management at the moment. Channels are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. + +The pattern of `channel_id` is: + +``` +rn-push-notification-channel-id(-soundname, default if playSound "-default")-(importance: default "4")-(vibration, default "300") +``` + +By default, 2 channels are created: + +- rn-push-notification-channel-id-default-4-300 (used for remote notification if none already exist). +- rn-push-notification-channel-id-4-300 (previously used for remote notification but without sounds). + +In the notifications options, you can provide a custom channel id with `channelId: "your-custom-channel-id"`, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your `channelId` is different if you change these options. If you have created a custom channel in another way, it will apply options of the channel. + +Custom and generated channels can have custom name and description in the `AndroidManifest.xml`, only if the library is responsible of the creation of the channel. + +```xml + + +``` + +For example: + +```xml + + +``` + +If you want to use a different default channel for remote notification, refer to the documentation of Firebase: + +[Set up a Firebase Cloud Messaging client app on Android](https://firebase.google.com/docs/cloud-messaging/android/client?hl=fr) + +```xml + +``` + ## Cancelling notifications ### 1) cancelLocalNotifications diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8f8efe768..4af3a8b54 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -52,6 +52,13 @@ android:value="Super channel description"/> + + + + + From 502180be08244db50f367766881c02bfba3e390c Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 21:30:59 +0200 Subject: [PATCH 026/179] Fix name of variable. --- .../modules/RNPushNotificationConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index e2a6aa170..491bdc9a1 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -34,7 +34,7 @@ private String getStringValue(String key, String defaultValue) { try { final String value = metadata.getString(key); - if (value != null && name.length() > 0) { + if (value != null && value.length() > 0) { return value; } } catch (Exception e) { From b1673a91a09fd68eb1152870bd30510c719afa82 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 27 May 2020 22:03:00 +0200 Subject: [PATCH 027/179] Fix order of default values. --- .../modules/RNPushNotificationConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index 491bdc9a1..9be0d7b67 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -46,15 +46,15 @@ private String getStringValue(String key, String defaultValue) { } public String getChannelName(String channel_id) { - String overrided = this.getStringValue(KEY_CHANNEL_NAME + "." + channel_id, "rn-push-notification-channel"); + String overrided = this.getStringValue(KEY_CHANNEL_NAME, "rn-push-notification-channel"); - return this.getStringValue(KEY_CHANNEL_NAME, overrided); + return this.getStringValue(KEY_CHANNEL_NAME + "." + channel_id, overrided); } public String getChannelDescription(String channel_id) { - String overrided = this.getStringValue(KEY_CHANNEL_DESCRIPTION + "." + channel_id, ""); + String overrided = this.getStringValue(KEY_CHANNEL_DESCRIPTION, ""); - return this.getStringValue(KEY_CHANNEL_DESCRIPTION, overrided); + return this.getStringValue(KEY_CHANNEL_DESCRIPTION + "." + channel_id, overrided); } public int getNotificationColor() { From 142fde631e57fae66dcaf7a735c525cf6ecae0f4 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 12:42:17 +0200 Subject: [PATCH 028/179] Add largeIconUrl and bigPictureUrl. --- CHANGELOG.md | 4 + README.md | 2 + .../modules/RNPushNotificationAttributes.java | 43 ++++++- .../modules/RNPushNotificationHelper.java | 83 +++++++++---- .../RNPushNotificationPicturesAggregator.java | 114 ++++++++++++++++++ 5 files changed, 220 insertions(+), 26 deletions(-) create mode 100644 android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f889387d..bfbc48173 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features +- (Android) Add `largeIconUrl` to load a largeIcon based on Url. +- (Android) Add `bigPictureUrl` to load a picture based on Url. - (Android) Add `shortcutId` for better badges management. - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) ### Fixed +- (Android) Some options were ignored on scheduled/repeating notifications (allowWhileIdle, ignoreInForeground). + ## [3.5.2] - 2020-05-25 ### Fixed diff --git a/README.md b/README.md index 1dcf404fa..7828c1b5b 100644 --- a/README.md +++ b/README.md @@ -278,9 +278,11 @@ PushNotification.localNotification({ ticker: "My Notification Ticker", // (optional) autoCancel: true, // (optional) default: true largeIcon: "ic_launcher", // (optional) default: "ic_launcher" + largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher" bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop subText: "This is a subText", // (optional) default: none + bigPictureUl: "https://www.example.tld/picture.jpg", // (optional) default: undefined color: "red", // (optional) default: system default vibrate: true, // (optional) default: true vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 0d2099ab7..4af08da2c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -20,9 +20,13 @@ public class RNPushNotificationAttributes { private static final String TICKER = "ticker"; private static final String AUTO_CANCEL = "autoCancel"; private static final String LARGE_ICON = "largeIcon"; + private static final String LARGE_ICON_URL = "largeIconUrl"; private static final String SMALL_ICON = "smallIcon"; private static final String BIG_TEXT = "bigText"; private static final String SUB_TEXT = "subText"; + private static final String BIG_PICTURE_URL = "bigPictureUrl"; + private static final String SHORTCUT_ID = "shortcutId"; + private static final String CHANNEL_ID = "channelId"; private static final String NUMBER = "number"; private static final String SOUND = "sound"; private static final String COLOR = "color"; @@ -36,6 +40,8 @@ public class RNPushNotificationAttributes { private static final String REPEAT_TYPE = "repeatType"; private static final String REPEAT_TIME = "repeatTime"; private static final String ONGOING = "ongoing"; + private static final String ALLOW_WHILE_IDLE = "allowWhileIdle"; + private static final String IGNORE_IN_FOREGROUND = "ignoreInForeground"; private final String id; private final String message; @@ -44,10 +50,14 @@ public class RNPushNotificationAttributes { private final String ticker; private final boolean autoCancel; private final String largeIcon; + private final String largeIconUrl; private final String smallIcon; private final String bigText; private final String subText; + private final String bigPictureUrl; + private final String shortcutId; private final String number; + private final String channelId; private final String sound; private final String color; private final String group; @@ -60,6 +70,8 @@ public class RNPushNotificationAttributes { private final String repeatType; private final double repeatTime; private final boolean ongoing; + private final boolean allowWhileIdle; + private final boolean ignoreInForeground; public RNPushNotificationAttributes(Bundle bundle) { id = bundle.getString(ID); @@ -69,10 +81,14 @@ public RNPushNotificationAttributes(Bundle bundle) { ticker = bundle.getString(TICKER); autoCancel = bundle.getBoolean(AUTO_CANCEL); largeIcon = bundle.getString(LARGE_ICON); + largeIconUrl = bundle.getString(LARGE_ICON_URL); smallIcon = bundle.getString(SMALL_ICON); bigText = bundle.getString(BIG_TEXT); subText = bundle.getString(SUB_TEXT); + bigPictureUrl= bundle.getString(BIG_PICTURE_URL); + shortcutId = bundle.getString(SHORTCUT_ID); number = bundle.getString(NUMBER); + channelId = bundle.getString(CHANNEL_ID); sound = bundle.getString(SOUND); color = bundle.getString(COLOR); group = bundle.getString(GROUP); @@ -85,6 +101,8 @@ public RNPushNotificationAttributes(Bundle bundle) { repeatType = bundle.getString(REPEAT_TYPE); repeatTime = bundle.getDouble(REPEAT_TIME); ongoing = bundle.getBoolean(ONGOING); + allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE); + ignoreInForeground = bundle.getBoolean(IGNORE_IN_FOREGROUND); } private RNPushNotificationAttributes(JSONObject jsonObject) { @@ -96,10 +114,14 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { ticker = jsonObject.has(TICKER) ? jsonObject.getString(TICKER) : null; autoCancel = jsonObject.has(AUTO_CANCEL) ? jsonObject.getBoolean(AUTO_CANCEL) : true; largeIcon = jsonObject.has(LARGE_ICON) ? jsonObject.getString(LARGE_ICON) : null; + largeIconUrl = jsonObject.has(LARGE_ICON_URL) ? jsonObject.getString(LARGE_ICON_URL) : null; smallIcon = jsonObject.has(SMALL_ICON) ? jsonObject.getString(SMALL_ICON) : null; bigText = jsonObject.has(BIG_TEXT) ? jsonObject.getString(BIG_TEXT) : null; subText = jsonObject.has(SUB_TEXT) ? jsonObject.getString(SUB_TEXT) : null; + bigPictureUrl = jsonObject.has(BIG_PICTURE_URL) ? jsonObject.getString(BIG_PICTURE_URL) : null; + shortcutId = jsonObject.has(SHORTCUT_ID) ? jsonObject.getString(SHORTCUT_ID) : null; number = jsonObject.has(NUMBER) ? jsonObject.getString(NUMBER) : null; + channelId = jsonObject.has(CHANNEL_ID) ? jsonObject.getString(CHANNEL_ID) : null; sound = jsonObject.has(SOUND) ? jsonObject.getString(SOUND) : null; color = jsonObject.has(COLOR) ? jsonObject.getString(COLOR) : null; group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null; @@ -112,6 +134,8 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null; repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0; ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false; + allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; + ignoreInForeground = jsonObject.has(IGNORE_IN_FOREGROUND) ? jsonObject.getBoolean(IGNORE_IN_FOREGROUND) : false; } catch (JSONException e) { throw new IllegalStateException("Exception while initializing RNPushNotificationAttributes from JSON", e); } @@ -180,10 +204,14 @@ public Bundle toBundle() { bundle.putString(TICKER, ticker); bundle.putBoolean(AUTO_CANCEL, autoCancel); bundle.putString(LARGE_ICON, largeIcon); + bundle.putString(LARGE_ICON_URL, largeIconUrl); bundle.putString(SMALL_ICON, smallIcon); bundle.putString(BIG_TEXT, bigText); bundle.putString(SUB_TEXT, subText); + bundle.putString(BIG_PICTURE_URL, bigPictureUrl); + bundle.putString(SHORTCUT_ID, shortcutId); bundle.putString(NUMBER, number); + bundle.putString(CHANNEL_ID, channelId); bundle.putString(SOUND, sound); bundle.putString(COLOR, color); bundle.putString(GROUP, group); @@ -196,6 +224,8 @@ public Bundle toBundle() { bundle.putString(REPEAT_TYPE, repeatType); bundle.putDouble(REPEAT_TIME, repeatTime); bundle.putBoolean(ONGOING, ongoing); + bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle); + bundle.putBoolean(IGNORE_IN_FOREGROUND, ignoreInForeground); return bundle; } @@ -209,10 +239,14 @@ public JSONObject toJson() { jsonObject.put(TICKER, ticker); jsonObject.put(AUTO_CANCEL, autoCancel); jsonObject.put(LARGE_ICON, largeIcon); + jsonObject.put(LARGE_ICON_URL, largeIconUrl); jsonObject.put(SMALL_ICON, smallIcon); jsonObject.put(BIG_TEXT, bigText); + jsonObject.put(BIG_PICTURE_URL, bigPictureUrl); jsonObject.put(SUB_TEXT, subText); + jsonObject.put(SHORTCUT_ID, shortcutId); jsonObject.put(NUMBER, number); + jsonObject.put(CHANNEL_ID, channelId); jsonObject.put(SOUND, sound); jsonObject.put(COLOR, color); jsonObject.put(GROUP, group); @@ -225,6 +259,8 @@ public JSONObject toJson() { jsonObject.put(REPEAT_TYPE, repeatType); jsonObject.put(REPEAT_TIME, repeatTime); jsonObject.put(ONGOING, ongoing); + jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle); + jsonObject.put(IGNORE_IN_FOREGROUND, ignoreInForeground); } catch (JSONException e) { Log.e(LOG_TAG, "Exception while converting RNPushNotificationAttributes to " + "JSON. Returning an empty object", e); @@ -244,10 +280,14 @@ public String toString() { ", ticker='" + ticker + '\'' + ", autoCancel=" + autoCancel + ", largeIcon='" + largeIcon + '\'' + + ", largeIconUrl='" + largeIconUrl + '\'' + ", smallIcon='" + smallIcon + '\'' + ", bigText='" + bigText + '\'' + ", subText='" + subText + '\'' + + ", bigPictureUrl='" + bigPictureUrl + '\'' + + ", shortcutId='" + shortcutId + '\'' + ", number='" + number + '\'' + + ", channelId='" + channelId + '\'' + ", sound='" + sound + '\'' + ", color='" + color + '\'' + ", group='" + group + '\'' + @@ -260,6 +300,8 @@ public String toString() { ", repeatType='" + repeatType + '\'' + ", repeatTime=" + repeatTime + ", ongoing=" + ongoing + + ", allowWhileIdle=" + allowWhileIdle + + ", ignoreInForeground=" + ignoreInForeground + '}'; } @@ -270,5 +312,4 @@ public String getId() { public double getFireDate() { return fireDate; } - } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index c1436c609..329d5ec72 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -1,6 +1,5 @@ package com.dieam.reactnativepushnotification.modules; - import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.AlarmManager; @@ -160,7 +159,19 @@ public void sendNotificationScheduledCore(Bundle bundle) { } } - public void sendToNotificationCentre(Bundle bundle) { + + public void sendToNotificationCentre(final Bundle bundle) { + RNPushNotificationPicturesAggregator aggregator = new RNPushNotificationPicturesAggregator(new RNPushNotificationPicturesAggregator.Callback() { + public void call(Bitmap largeIconImage, Bitmap bigPictureImage) { + sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage); + } + }); + + aggregator.setLargeIconUrl(context, bundle.getString("largeIconUrl")); + aggregator.setBigPictureUrl(context, bundle.getString("bigPictureUrl")); + } + + public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconBitmap, Bitmap bigPictureBitmap) { try { Class intentClass = getMainActivityClass(); if (intentClass == null) { @@ -286,23 +297,13 @@ public void sendToNotificationCentre(Bundle bundle) { notification.setGroup(group); } - notification.setContentText(bundle.getString("message")); - - String largeIcon = bundle.getString("largeIcon"); - - String subText = bundle.getString("subText"); - - if (subText != null) { - notification.setSubText(subText); - } - String numberString = bundle.getString("number"); if (numberString != null) { notification.setNumber(Integer.parseInt(numberString)); } + // Small icon int smallIconResId; - int largeIconResId; String smallIcon = bundle.getString("smallIcon"); @@ -320,26 +321,59 @@ public void sendToNotificationCentre(Bundle bundle) { } } - if (largeIcon != null) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); - } else { - largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); - } + notification.setSmallIcon(smallIconResId); - Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); + // Large icon + if(largeIconBitmap == null) { + int largeIconResId; - if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { - notification.setLargeIcon(largeIconBitmap); + String largeIcon = bundle.getString("largeIcon"); + + if (largeIcon != null) { + largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); + } else { + largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); + } + + // Before Lolipop there was no large icon for notifications. + if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { + largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); + } + } + + if (largeIconBitmap != null){ + notification.setLargeIcon(largeIconBitmap); } - notification.setSmallIcon(smallIconResId); + String message = bundle.getString("message"); + + notification.setContentText(message); + + String subText = bundle.getString("subText"); + + if (subText != null) { + notification.setSubText(subText); + } + String bigText = bundle.getString("bigText"); if (bigText == null) { - bigText = bundle.getString("message"); + bigText = message; } - notification.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText)); + NotificationCompat.Style style; + + if(bigPictureBitmap != null) { + style = new NotificationCompat.BigPictureStyle() + .bigPicture(bigPictureBitmap) + .setBigContentTitle(title) + .setSummaryText(message); + } + else { + style = new NotificationCompat.BigTextStyle().bigText(bigText); + } + + notification.setStyle(style); Intent intent = new Intent(context, intentClass); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); @@ -761,5 +795,4 @@ private boolean isApplicationInForeground(Context context) { } return false; } - } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java new file mode 100644 index 000000000..3645715af --- /dev/null +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java @@ -0,0 +1,114 @@ +package com.dieam.reactnativepushnotification.modules; + +import androidx.annotation.Nullable; +import com.facebook.common.executors.CallerThreadExecutor; +import com.facebook.common.references.CloseableReference; +import com.facebook.datasource.DataSource; +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.imagepipeline.common.Priority; +import com.facebook.imagepipeline.core.ImagePipeline; +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; +import com.facebook.imagepipeline.image.CloseableImage; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; + +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import java.util.concurrent.atomic.AtomicInteger; + +public class RNPushNotificationPicturesAggregator { + interface Callback { + public void call(Bitmap largeIconImage, Bitmap bigPictureImage); + } + + final private int wait = 2; + private AtomicInteger count = new AtomicInteger(0); + + private Bitmap largeIconImage; + private Bitmap bigPictureImage; + + private ImagePipeline imagePipeline; + + private Callback callback; + + public RNPushNotificationPicturesAggregator(Callback callback) { + this.imagePipeline = Fresco.getImagePipeline(); + + this.callback = callback; + } + + public void setBigPicture(Bitmap bitmap) { + this.bigPictureImage = bitmap; + this.finished(); + } + + public void setBigPictureUrl(Context context, String url) { + if(null == url) { + this.setBigPicture(null); + return; + } + + final RNPushNotificationPicturesAggregator aggregator = this; + + this.downloadRequest(context, url, new BaseBitmapDataSubscriber() { + @Override + public void onNewResultImpl(@Nullable Bitmap bitmap) { + aggregator.setBigPicture(bitmap); + } + + @Override + public void onFailureImpl(DataSource dataSource) { + aggregator.setBigPicture(null); + } + }); + } + + public void setLargeIcon(Bitmap bitmap) { + this.largeIconImage = bitmap; + this.finished(); + } + + public void setLargeIconUrl(Context context, String url) { + if(null == url) { + this.setLargeIcon(null); + return; + } + + final RNPushNotificationPicturesAggregator aggregator = this; + + this.downloadRequest(context, url, new BaseBitmapDataSubscriber() { + @Override + public void onNewResultImpl(@Nullable Bitmap bitmap) { + aggregator.setLargeIcon(bitmap); + } + + @Override + public void onFailureImpl(DataSource dataSource) { + aggregator.setLargeIcon(null); + } + }); + } + + private void downloadRequest(Context context, String url, BaseBitmapDataSubscriber subscriber) { + ImageRequest imageRequest = ImageRequestBuilder + .newBuilderWithSource(Uri.parse(url)) + .setRequestPriority(Priority.HIGH) + .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) + .build(); + + DataSource> dataSource = this.imagePipeline.fetchDecodedImage(imageRequest, context); + + dataSource.subscribe(subscriber, CallerThreadExecutor.getInstance()); + } + + private void finished() { + synchronized(this.count) { + int val = this.count.incrementAndGet(); + + if(val >= this.wait && this.callback != null) { + this.callback.call(this.largeIconImage, this.bigPictureImage); + } + } + } +} \ No newline at end of file From 562e250c6ae54b0942e53491781e5aad57e2ddef Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 12:44:52 +0200 Subject: [PATCH 029/179] Reference original PR #1444. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfbc48173..de0532106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features -- (Android) Add `largeIconUrl` to load a largeIcon based on Url. -- (Android) Add `bigPictureUrl` to load a picture based on Url. +- (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) +- (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `shortcutId` for better badges management. - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) From 90a2af1d60ccda33b3e633114fd9d910d987ae3d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 13:50:50 +0200 Subject: [PATCH 030/179] Check URI before load. --- .../RNPushNotificationPicturesAggregator.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java index 3645715af..cbb6ddb7c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java @@ -12,11 +12,14 @@ import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; +import android.util.Log; import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; import java.util.concurrent.atomic.AtomicInteger; +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; + public class RNPushNotificationPicturesAggregator { interface Callback { public void call(Bitmap largeIconImage, Bitmap bigPictureImage); @@ -49,9 +52,19 @@ public void setBigPictureUrl(Context context, String url) { return; } + Uri uri = null; + + try { + uri = Uri.parse(url); + } catch(Exception ex) { + Log.e(LOG_TAG, "Failed to parse bigPictureUrl", ex); + this.setBigPicture(null); + return; + } + final RNPushNotificationPicturesAggregator aggregator = this; - this.downloadRequest(context, url, new BaseBitmapDataSubscriber() { + this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() { @Override public void onNewResultImpl(@Nullable Bitmap bitmap) { aggregator.setBigPicture(bitmap); @@ -75,9 +88,19 @@ public void setLargeIconUrl(Context context, String url) { return; } + Uri uri = null; + + try { + uri = Uri.parse(url); + } catch(Exception ex) { + Log.e(LOG_TAG, "Failed to parse largeIconUrl", ex); + this.setLargeIcon(null); + return; + } + final RNPushNotificationPicturesAggregator aggregator = this; - this.downloadRequest(context, url, new BaseBitmapDataSubscriber() { + this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() { @Override public void onNewResultImpl(@Nullable Bitmap bitmap) { aggregator.setLargeIcon(bitmap); @@ -90,9 +113,9 @@ public void onFailureImpl(DataSource dataSource) { }); } - private void downloadRequest(Context context, String url, BaseBitmapDataSubscriber subscriber) { + private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber subscriber) { ImageRequest imageRequest = ImageRequestBuilder - .newBuilderWithSource(Uri.parse(url)) + .newBuilderWithSource(uri) .setRequestPriority(Priority.HIGH) .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) .build(); From 0cee8de392749d784b12285abba44232f6ad546f Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 19:08:58 +0200 Subject: [PATCH 031/179] Implement groupSummary. --- CHANGELOG.md | 1 + README.md | 1 + .../modules/RNPushNotificationAttributes.java | 7 +++++++ .../modules/RNPushNotificationHelper.java | 13 ++++++++++--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de0532106..722db3fa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `shortcutId` for better badges management. +- (Android) Add `groupSummary` to allow grouping notifications. Based on [#1253](https://github.com/zo0r/react-native-push-notification/pull/1253) - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) diff --git a/README.md b/README.md index 7828c1b5b..4a4a90d14 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,7 @@ PushNotification.localNotification({ vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 tag: "some_tag", // (optional) add tag to message group: "group", // (optional) add group to message + groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false ongoing: false, // (optional) set whether this is an "ongoing" notification priority: "high", // (optional) set notification priority, default: high visibility: "private", // (optional) set notification visibility, default: private diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 4af08da2c..2231f1b46 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -31,6 +31,7 @@ public class RNPushNotificationAttributes { private static final String SOUND = "sound"; private static final String COLOR = "color"; private static final String GROUP = "group"; + private static final String GROUP_SUMMARY = "groupSummary"; private static final String USER_INTERACTION = "userInteraction"; private static final String PLAY_SOUND = "playSound"; private static final String VIBRATE = "vibrate"; @@ -61,6 +62,7 @@ public class RNPushNotificationAttributes { private final String sound; private final String color; private final String group; + private final boolean groupSummary; private final boolean userInteraction; private final boolean playSound; private final boolean vibrate; @@ -92,6 +94,7 @@ public RNPushNotificationAttributes(Bundle bundle) { sound = bundle.getString(SOUND); color = bundle.getString(COLOR); group = bundle.getString(GROUP); + groupSummary = bundle.getBoolean(GROUP_SUMMARY); userInteraction = bundle.getBoolean(USER_INTERACTION); playSound = bundle.getBoolean(PLAY_SOUND); vibrate = bundle.getBoolean(VIBRATE); @@ -125,6 +128,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { sound = jsonObject.has(SOUND) ? jsonObject.getString(SOUND) : null; color = jsonObject.has(COLOR) ? jsonObject.getString(COLOR) : null; group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null; + groupSummary = jsonObject.has(GROUP_SUMMARY) ? jsonObject.getBoolean(GROUP_SUMMARY) : false; userInteraction = jsonObject.has(USER_INTERACTION) ? jsonObject.getBoolean(USER_INTERACTION) : false; playSound = jsonObject.has(PLAY_SOUND) ? jsonObject.getBoolean(PLAY_SOUND) : true; vibrate = jsonObject.has(VIBRATE) ? jsonObject.getBoolean(VIBRATE) : true; @@ -215,6 +219,7 @@ public Bundle toBundle() { bundle.putString(SOUND, sound); bundle.putString(COLOR, color); bundle.putString(GROUP, group); + bundle.putBoolean(GROUP_SUMMARY, groupSummary); bundle.putBoolean(USER_INTERACTION, userInteraction); bundle.putBoolean(PLAY_SOUND, playSound); bundle.putBoolean(VIBRATE, vibrate); @@ -250,6 +255,7 @@ public JSONObject toJson() { jsonObject.put(SOUND, sound); jsonObject.put(COLOR, color); jsonObject.put(GROUP, group); + jsonObject.put(GROUP_SUMMARY, groupSummary); jsonObject.put(USER_INTERACTION, userInteraction); jsonObject.put(PLAY_SOUND, playSound); jsonObject.put(VIBRATE, vibrate); @@ -291,6 +297,7 @@ public String toString() { ", sound='" + sound + '\'' + ", color='" + color + '\'' + ", group='" + group + '\'' + + ", groupSummary='" + groupSummary + '\'' + ", userInteraction=" + userInteraction + ", playSound=" + playSound + ", vibrate=" + vibrate + diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 329d5ec72..9619a539d 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -291,13 +291,20 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB notification.setDefaults(Notification.DEFAULT_LIGHTS); } - String group = bundle.getString("group"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { // API 20 and higher + String group = bundle.getString("group"); - if (group != null) { - notification.setGroup(group); + if (group != null) { + notification.setGroup(group); + } + + if (bundle.containsKey("groupSummary") || bundle.getBoolean("groupSummary")) { + notification.setGroupSummary(bundle.getBoolean("groupSummary")); + } } String numberString = bundle.getString("number"); + if (numberString != null) { notification.setNumber(Integer.parseInt(numberString)); } From cb7b57569cc402a82c2dfd2ca5680492db7994ec Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 19:42:42 +0200 Subject: [PATCH 032/179] Apply #1185 --- README.md | 3 ++- example/NotifService.js | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4a4a90d14..93d4df225 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,8 @@ PushNotification.localNotification({ shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. + actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more + /* iOS only properties */ alertAction: "view", // (optional) default: view category: "", // (optional) default: empty string @@ -310,7 +312,6 @@ PushNotification.localNotification({ soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) repeatType: "day", // (optional) Repeating interval. Check 'Repeating Notifications' section for more info. - actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more }); ``` diff --git a/example/NotifService.js b/example/NotifService.js index de686b639..fbe9f62f3 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -9,8 +9,8 @@ export default class NotifService { NotificationHandler.attachNotification(onNotification); // Clear badge number at start - PushNotification.getApplicationIconBadgeNumber(function(number) { - if(number > 0) { + PushNotification.getApplicationIconBadgeNumber(function (number) { + if (number > 0) { PushNotification.setApplicationIconBadgeNumber(0); } }); @@ -33,6 +33,7 @@ export default class NotifService { tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message ongoing: false, // (optional) set whether this is an "ongoing" notification + actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more /* iOS only properties */ alertAction: 'view', // (optional) default: view @@ -45,7 +46,6 @@ export default class NotifService { playSound: !!soundName, // (optional) default: true soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) - actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more }); } From 3c79f9ace7c4b39af9207c009a7793895a003f51 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 20:12:23 +0200 Subject: [PATCH 033/179] Add showWhen. Clean up some code. --- README.md | 2 +- .../modules/RNPushNotificationAttributes.java | 7 ++ .../RNPushNotificationBootEventReceiver.java | 2 +- .../modules/RNPushNotificationHelper.java | 94 ++++++++++--------- .../modules/RNPushNotificationJsDelivery.java | 2 +- .../RNPushNotificationListenerService.java | 1 - .../RNPushNotificationPicturesAggregator.java | 5 +- .../modules/RNReceivedMessageHandler.java | 8 +- 8 files changed, 65 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 337ef9aea..0d6426c24 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Changelog is available from version 3.1.3 here: [Changelog](https://github.com/z `yarn add react-native-push-notification` -If you target iOS you also need to follow the [installation instructions for PushNotificationIOS](https://github.com/react-native-community/react-native-push-notification-ios) since this package depends on it. +**NOTE: If you target iOS you also need to follow the [installation instructions for PushNotificationIOS](https://github.com/react-native-community/react-native-push-notification-ios) since this package depends on it.** **NOTE: For Android, you will still have to manually update the AndroidManifest.xml (as below) in order to use Scheduled Notifications.** diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 2231f1b46..8df1c850f 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -18,6 +18,7 @@ public class RNPushNotificationAttributes { private static final String FIRE_DATE = "fireDate"; private static final String TITLE = "title"; private static final String TICKER = "ticker"; + private static final String SHOW_WHEN = "showWhen"; private static final String AUTO_CANCEL = "autoCancel"; private static final String LARGE_ICON = "largeIcon"; private static final String LARGE_ICON_URL = "largeIconUrl"; @@ -49,6 +50,7 @@ public class RNPushNotificationAttributes { private final double fireDate; private final String title; private final String ticker; + private final boolean showWhen; private final boolean autoCancel; private final String largeIcon; private final String largeIconUrl; @@ -81,6 +83,7 @@ public RNPushNotificationAttributes(Bundle bundle) { fireDate = bundle.getDouble(FIRE_DATE); title = bundle.getString(TITLE); ticker = bundle.getString(TICKER); + showWhen = bundle.getBoolean(SHOW_WHEN); autoCancel = bundle.getBoolean(AUTO_CANCEL); largeIcon = bundle.getString(LARGE_ICON); largeIconUrl = bundle.getString(LARGE_ICON_URL); @@ -115,6 +118,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { fireDate = jsonObject.has(FIRE_DATE) ? jsonObject.getDouble(FIRE_DATE) : 0.0; title = jsonObject.has(TITLE) ? jsonObject.getString(TITLE) : null; ticker = jsonObject.has(TICKER) ? jsonObject.getString(TICKER) : null; + showWhen = jsonObject.has(SHOW_WHEN) ? jsonObject.getBoolean(SHOW_WHEN) : true; autoCancel = jsonObject.has(AUTO_CANCEL) ? jsonObject.getBoolean(AUTO_CANCEL) : true; largeIcon = jsonObject.has(LARGE_ICON) ? jsonObject.getString(LARGE_ICON) : null; largeIconUrl = jsonObject.has(LARGE_ICON_URL) ? jsonObject.getString(LARGE_ICON_URL) : null; @@ -206,6 +210,7 @@ public Bundle toBundle() { bundle.putDouble(FIRE_DATE, fireDate); bundle.putString(TITLE, title); bundle.putString(TICKER, ticker); + bundle.putBoolean(SHOW_WHEN, showWhen); bundle.putBoolean(AUTO_CANCEL, autoCancel); bundle.putString(LARGE_ICON, largeIcon); bundle.putString(LARGE_ICON_URL, largeIconUrl); @@ -242,6 +247,7 @@ public JSONObject toJson() { jsonObject.put(FIRE_DATE, fireDate); jsonObject.put(TITLE, title); jsonObject.put(TICKER, ticker); + jsonObject.put(SHOW_WHEN, showWhen); jsonObject.put(AUTO_CANCEL, autoCancel); jsonObject.put(LARGE_ICON, largeIcon); jsonObject.put(LARGE_ICON_URL, largeIconUrl); @@ -284,6 +290,7 @@ public String toString() { ", fireDate=" + fireDate + ", title='" + title + '\'' + ", ticker='" + ticker + '\'' + + ", showWhen=" + showWhen + ", autoCancel=" + autoCancel + ", largeIcon='" + largeIcon + '\'' + ", largeIconUrl='" + largeIconUrl + '\'' + diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java index 82a575883..bae277585 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java @@ -20,7 +20,7 @@ public class RNPushNotificationBootEventReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver loading scheduled notifications"); - if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { + if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) { SharedPreferences sharedPreferences = context.getSharedPreferences(RNPushNotificationHelper.PREFERENCES_KEY, Context.MODE_PRIVATE); Set ids = sharedPreferences.getAll().keySet(); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index faa845b27..bd1bb44b0 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -23,6 +23,8 @@ import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; + +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import com.facebook.react.bridge.Arguments; @@ -39,7 +41,6 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.List; -import java.util.Set; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; import static com.dieam.reactnativepushnotification.modules.RNPushNotificationAttributes.fromJson; @@ -124,7 +125,7 @@ public void sendNotificationScheduled(Bundle bundle) { SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit(); editor.putString(id, notificationAttributes.toJson().toString()); - commit(editor); + editor.apply(); boolean isSaved = scheduledNotificationsPersistence.contains(id); if (!isSaved) { @@ -206,7 +207,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB final String priorityString = bundle.getString("priority"); if (priorityString != null) { - switch(priorityString.toLowerCase()) { + switch (priorityString.toLowerCase()) { case "max": priority = NotificationCompat.PRIORITY_MAX; break; @@ -227,34 +228,39 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB } } - int importance = NotificationManager.IMPORTANCE_HIGH; - final String importanceString = bundle.getString("importance"); - - if (importanceString != null) { - switch(importanceString.toLowerCase()) { - case "default": - importance = NotificationManager.IMPORTANCE_DEFAULT; - break; - case "max": - importance = NotificationManager.IMPORTANCE_MAX; - break; - case "high": - importance = NotificationManager.IMPORTANCE_HIGH; - break; - case "low": - importance = NotificationManager.IMPORTANCE_LOW; - break; - case "min": - importance = NotificationManager.IMPORTANCE_MIN; - break; - case "none": - importance = NotificationManager.IMPORTANCE_NONE; - break; - case "unspecified": - importance = NotificationManager.IMPORTANCE_UNSPECIFIED; - break; - default: - importance = NotificationManager.IMPORTANCE_HIGH; + int importance = 4; // Same as HIGH for lower version + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + importance = NotificationManager.IMPORTANCE_HIGH; + + final String importanceString = bundle.getString("importance"); + + if (importanceString != null) { + switch (importanceString.toLowerCase()) { + case "default": + importance = NotificationManager.IMPORTANCE_DEFAULT; + break; + case "max": + importance = NotificationManager.IMPORTANCE_MAX; + break; + case "high": + importance = NotificationManager.IMPORTANCE_HIGH; + break; + case "low": + importance = NotificationManager.IMPORTANCE_LOW; + break; + case "min": + importance = NotificationManager.IMPORTANCE_MIN; + break; + case "none": + importance = NotificationManager.IMPORTANCE_NONE; + break; + case "unspecified": + importance = NotificationManager.IMPORTANCE_UNSPECIFIED; + break; + default: + importance = NotificationManager.IMPORTANCE_HIGH; + } } } @@ -289,7 +295,9 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24 and higher // Restore showing timestamp on Android 7+ // Source: https://developer.android.com/reference/android/app/Notification.Builder.html#setShowWhen(boolean) - notification.setShowWhen(true); + boolean showWhen = bundle.getBoolean("showWhen", true); + + notification.setShowWhen(showWhen); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher @@ -537,7 +545,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (scheduledNotificationsPersistence.getString(notificationIdString, null) != null) { SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit(); editor.remove(notificationIdString); - commit(editor); + editor.apply(); } if (!(this.isApplicationInForeground(context) && bundle.getBoolean("ignoreInForeground"))) { @@ -603,7 +611,7 @@ private void scheduleNextNotificationIfRepeating(Bundle bundle) { nextEvent.set(Calendar.YEAR, nextEvent.get(Calendar.YEAR) + (nextMonth == 0 ? 1 : 0)); nextEvent.set(Calendar.MONTH, nextMonth); final int maxDay = nextEvent.getActualMaximum(Calendar.DAY_OF_MONTH); - nextEvent.set(Calendar.DAY_OF_MONTH, fireDay <= maxDay ? fireDay : maxDay); + nextEvent.set(Calendar.DAY_OF_MONTH, Math.min(fireDay, maxDay)); nextEvent.set(Calendar.HOUR_OF_DAY, fireHour); nextEvent.set(Calendar.MINUTE, fireMinute); nextEvent.set(Calendar.SECOND, 0); @@ -656,6 +664,7 @@ public void clearDeliveredNotifications(ReadableArray identifiers) { } } + @RequiresApi(api = Build.VERSION_CODES.M) public WritableArray getDeliveredNotifications() { NotificationManager notificationManager = notificationManager(); StatusBarNotification delivered[] = notificationManager.getActiveNotifications(); @@ -721,7 +730,7 @@ private void cancelScheduledNotification(String notificationIDString) { // remove it from local storage SharedPreferences.Editor editor = scheduledNotificationsPersistence.edit(); editor.remove(notificationIDString); - commit(editor); + editor.apply(); } else { Log.w(LOG_TAG, "Unable to find notification " + notificationIDString); } @@ -740,18 +749,15 @@ private NotificationManager notificationManager() { return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } - private static void commit(SharedPreferences.Editor editor) { - if (Build.VERSION.SDK_INT < 9) { - editor.commit(); - } else { - editor.apply(); - } - } - public void checkOrCreateDefaultChannel() { NotificationManager manager = notificationManager(); - int importance = NotificationManager.IMPORTANCE_HIGH; + int importance = 4; // Default value of HIGH for lower version + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + importance = NotificationManager.IMPORTANCE_HIGH; + } + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); // Instanciate a default channel with default sound. diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java index c6721d7fc..b223757fa 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java @@ -67,7 +67,7 @@ String convertJSON(Bundle bundle) { } // a Bundle is not a map, so we have to convert it explicitly - JSONObject convertJSONObject(Bundle bundle) throws JSONException { + private JSONObject convertJSONObject(Bundle bundle) throws JSONException { JSONObject json = new JSONObject(); Set keys = bundle.keySet(); for (String key : keys) { diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index df0c52d02..6be3baa83 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -7,7 +7,6 @@ import android.os.Looper; import android.util.Log; -import com.dieam.reactnativepushnotification.modules.RNReceivedMessageHandler; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.Arguments; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java index cbb6ddb7c..8f8d4b0ca 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java @@ -25,7 +25,6 @@ interface Callback { public void call(Bitmap largeIconImage, Bitmap bigPictureImage); } - final private int wait = 2; private AtomicInteger count = new AtomicInteger(0); private Bitmap largeIconImage; @@ -128,8 +127,8 @@ private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber private void finished() { synchronized(this.count) { int val = this.count.incrementAndGet(); - - if(val >= this.wait && this.callback != null) { + + if(val >= 2 && this.callback != null) { this.callback.call(this.largeIconImage, this.bigPictureImage); } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 04038bc07..10675f4f2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -15,10 +15,8 @@ import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.WritableMap; import org.json.JSONObject; @@ -132,7 +130,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); - Boolean isForeground = isApplicationInForeground(); + boolean isForeground = isApplicationInForeground(); RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); bundle.putBoolean("foreground", isForeground); @@ -144,9 +142,9 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl jsDelivery.notifyRemoteFetch(bundle); } - Log.v(LOG_TAG, "sendNotification: " + bundle); - if (config.getNotificationForeground() || !isForeground) { + Log.v(LOG_TAG, "sendNotification: " + bundle); + Application applicationContext = (Application) context.getApplicationContext(); RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); pushNotificationHelper.sendToNotificationCentre(bundle); From 8372c5fb7e997dd1b70180d95d1250c8a5b7bdea Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 28 May 2020 20:17:18 +0200 Subject: [PATCH 034/179] Add documentation for showWhen. --- CHANGELOG.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 722db3fa6..1c703fed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `shortcutId` for better badges management. +- (Android) Add `showWhen` to display "when" it was published, default: true. - (Android) Add `groupSummary` to allow grouping notifications. Based on [#1253](https://github.com/zo0r/react-native-push-notification/pull/1253) - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) diff --git a/README.md b/README.md index 0d6426c24..44485dcd0 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,7 @@ PushNotification.localNotification({ /* Android Only Properties */ id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID ticker: "My Notification Ticker", // (optional) + showWhen: true, // (optional) default: true autoCancel: true, // (optional) default: true largeIcon: "ic_launcher", // (optional) default: "ic_launcher" largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined From d1dd76c922f3420b430e866fa8407db3053f642e Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 30 May 2020 12:03:24 +0200 Subject: [PATCH 035/179] Cleanup Event listener. Initialize Fresco only when required and avoid crash if not initialized. --- android/.classpath | 6 ++++++ android/.project | 6 ++++++ android/.settings/org.eclipse.buildship.core.prefs | 2 +- .../modules/RNPushNotificationListenerService.java | 3 ++- .../RNPushNotificationPicturesAggregator.java | 10 +++++----- .../modules/RNReceivedMessageHandler.java | 3 ++- .../.settings/org.eclipse.buildship.core.prefs | 2 +- .../app/.settings/org.eclipse.buildship.core.prefs | 13 ++++++++++++- 8 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 android/.classpath diff --git a/android/.classpath b/android/.classpath new file mode 100644 index 000000000..eb19361b5 --- /dev/null +++ b/android/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/android/.project b/android/.project index 3964dd3f5..3865e0fa4 100644 --- a/android/.project +++ b/android/.project @@ -5,6 +5,11 @@ + + org.eclipse.jdt.core.javabuilder + + + org.eclipse.buildship.core.gradleprojectbuilder @@ -12,6 +17,7 @@ + org.eclipse.jdt.core.javanature org.eclipse.buildship.core.gradleprojectnature diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index c25633f0a..342e81ef5 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,7 +1,7 @@ arguments= auto.sync=false build.scans.enabled=false -connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3)) +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 gradle.user.home= diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index 6be3baa83..d51f6960c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -29,7 +29,7 @@ public void onNewToken(String token) { handler.post(new Runnable() { public void run() { // Construct and load our normal React JS code bundle - ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); + final ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); ReactContext context = mReactInstanceManager.getCurrentReactContext(); // If it's constructed, send a notification if (context != null) { @@ -39,6 +39,7 @@ public void run() { mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { public void onReactContextInitialized(ReactContext context) { handleNewToken((ReactApplicationContext) context, deviceToken); + mReactInstanceManager.removeReactInstanceEventListener(this); } }); if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java index 8f8d4b0ca..27c7389a8 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java @@ -30,13 +30,9 @@ interface Callback { private Bitmap largeIconImage; private Bitmap bigPictureImage; - private ImagePipeline imagePipeline; - private Callback callback; public RNPushNotificationPicturesAggregator(Callback callback) { - this.imagePipeline = Fresco.getImagePipeline(); - this.callback = callback; } @@ -119,7 +115,11 @@ private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) .build(); - DataSource> dataSource = this.imagePipeline.fetchDecodedImage(imageRequest, context); + if(!Fresco.hasBeenInitialized()) { + Fresco.initialize(context); + } + + DataSource> dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context); dataSource.subscribe(subscriber, CallerThreadExecutor.getInstance()); } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 10675f4f2..05be185b5 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -91,7 +91,7 @@ public void handleReceivedMessage(RemoteMessage message) { handler.post(new Runnable() { public void run() { // Construct and load our normal React JS code bundle - ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager(); + final ReactInstanceManager mReactInstanceManager = ((ReactApplication) mFirebaseMessagingService.getApplication()).getReactNativeHost().getReactInstanceManager(); ReactContext context = mReactInstanceManager.getCurrentReactContext(); // If it's constructed, send a notificationre if (context != null) { @@ -101,6 +101,7 @@ public void run() { mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { public void onReactContextInitialized(ReactContext context) { handleRemotePushNotification((ReactApplicationContext) context, bundle); + mReactInstanceManager.removeReactInstanceEventListener(this); } }); if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs index 342e81ef5..b9ef928ba 100644 --- a/example/android/.settings/org.eclipse.buildship.core.prefs +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -2,7 +2,7 @@ arguments= auto.sync=false build.scans.enabled=false connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) -connection.project.dir= +connection.project.dir=app eclipse.preferences.version=1 gradle.user.home= java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs index b1886adb4..c25633f0a 100644 --- a/example/android/app/.settings/org.eclipse.buildship.core.prefs +++ b/example/android/app/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ -connection.project.dir=.. +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3)) +connection.project.dir= eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true From c9aae3c41b181fe4d886593e523635520c23a0b5 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 31 May 2020 15:11:47 +0200 Subject: [PATCH 036/179] Refactor to preprare version 4.0.0. --- CHANGELOG.md | 15 +++ README.md | 90 +++++++++----- .../modules/RNPushNotification.java | 113 +++++++++++++++--- .../modules/RNPushNotificationAttributes.java | 7 ++ .../modules/RNPushNotificationConfig.java | 11 ++ .../modules/RNPushNotificationHelper.java | 81 +++++++++++-- .../modules/RNPushNotificationPublisher.java | 79 +++++++++++- ...RNPushNotificationRegistrationService.java | 22 ---- component/index.android.js | 39 ++++-- component/index.ios.js | 2 - example/NotifService.js | 9 +- example/NotificationHandler.js | 11 ++ .../android/app/src/main/AndroidManifest.xml | 2 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ example/ios/example/Info.plist | 6 + index.js | 82 ++++++++++--- 16 files changed, 464 insertions(+), 113 deletions(-) delete mode 100644 android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java create mode 100644 example/ios/example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c703fed7..f42cbeabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Breaking changes + +- Now local scheduled notifications trigger `onNotification`. +- `RNPushNotificationRegistrationService` has been remove, old reference in AndroidManifest must be removed. +- `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. +- `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. + ### Features +- (Android) `actions` accept an array of strings. +- (Android) `invokeApp` allow you to handle actions in background without invoking the application. +- (Android) `onAction` has been added to `.configure()` to handle action in background. +- (Android) `PushNotification.invokeApp(notification)` allow you to invoke the application when in background (notification for initial notification). +- (Android) `PushNotification.getChannels(callback)` allow you to get the list of channels. +- (Android) `PushNotification.channelExists(channel_id, callback)` allow you to check of a channel exists. +- (Android) `PushNotification.deleteChannel(channel_id)` allow you to delete a channel. - (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `shortcutId` for better badges management. @@ -20,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - (Android) Some options were ignored on scheduled/repeating notifications (allowWhileIdle, ignoreInForeground). +- (Android/iOS) popInitialInotification might be ignored in `.configure()` ## [3.5.2] - 2020-05-25 diff --git a/README.md b/README.md index 44485dcd0..e212c8ec5 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,9 @@ In your `android/app/src/main/AndroidManifest.xml` + + @@ -224,6 +227,14 @@ PushNotification.configure({ notification.finish(PushNotificationIOS.FetchResult.NoData); }, + // (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android) + onAction: function (notification) { + console.log("ACTION:", notification.action); + console.log("NOTIFICATION:", notification); + + // process the action + }, + // IOS ONLY (optional): default: all - Permissions to register. permissions: { alert: true, @@ -302,6 +313,7 @@ PushNotification.localNotification({ channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more + invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ alertAction: "view", // (optional) default: view @@ -349,13 +361,21 @@ This library doesn't include a full Channel Management at the moment. Channels a The pattern of `channel_id` is: ``` -rn-push-notification-channel-id(-soundname, default if playSound "-default")-(importance: default "4")-(vibration, default "300") +rn-push-notification-channel-id-(importance: default "4")(-soundname, default if playSound "-default")-(vibration, default "300") ``` -By default, 2 channels are created: +By default, 1 channel is created: + +- rn-push-notification-channel-id-4-default-300 (used for remote notification if none already exist). + +you can avoid the default creation by using this: + +```xml + +``` -- rn-push-notification-channel-id-default-4-300 (used for remote notification if none already exist). -- rn-push-notification-channel-id-4-300 (previously used for remote notification but without sounds). +**NOTE: Without channel, remote notifications don't work** In the notifications options, you can provide a custom channel id with `channelId: "your-custom-channel-id"`, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your `channelId` is different if you change these options. If you have created a custom channel in another way, it will apply options of the channel. @@ -387,6 +407,37 @@ If you want to use a different default channel for remote notification, refer to android:value="@string/default_notification_channel_id" /> ``` +### List channels + +You can list available channels with: + +```js +PushNotification.getChannels(function(channel_ids) { + console.log(channel_ids); // ['channel_id_1'] +}); + +``` + +### Channel exists + +You can check if a channel exists with: + +```js +PushNotification.channelExists(function(exists) { + console.log(exists); // true/false +}); + +``` + +### List channels + +You can list available channels with: + +```js +PushNotification.deleteChannel(channel_id); + +``` + ## Cancelling notifications ### 1) cancelLocalNotifications @@ -539,38 +590,11 @@ Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, (Android only) [Refer](https://github.com/zo0r/react-native-push-notification/issues/151) to this issue to see an example of a notification action. -Two things are required to setup notification actions. - -### 1) Specify notification actions for a notification - This is done by specifying an `actions` parameters while configuring the local notification. This is an array of strings where each string is a notification action that will be presented with the notification. -For e.g. `actions: '["Accept", "Reject"]' // Must be in string format` - -The array itself is specified in string format to circumvent some problems because of the way JSON arrays are handled by react-native android bridge. - -### 2) Specify handlers for the notification actions +For e.g. `actions: ['Accept', 'Reject']` -For each action specified in the `actions` field, we need to add a handler that is called when the user clicks on the action. This can be done in the `componentWillMount` of your main app file or in a separate file which is imported in your main app file. Notification actions handlers can be configured as below: - -``` -import PushNotificationAndroid from 'react-native-push-notification' - -(function() { - // Register all the valid actions for notifications here and add the action handler for each action - PushNotificationAndroid.registerNotificationActions(['Accept','Reject','Yes','No']); - DeviceEventEmitter.addListener('notificationActionReceived', function(action){ - console.log ('Notification action received: ' + action); - const info = JSON.parse(action.dataJSON); - if (info.action == 'Accept') { - // Do work pertaining to Accept action here - } else if (info.action == 'Reject') { - // Do work pertaining to Reject action here - } - // Add all the required actions handlers - }); -})(); -``` +When you handle actions in background (`invokeApp: false`), you can open the application and pass the initial notification by using use `PushNotification.invokeApp(notification)`. For iOS, you can use this [package](https://github.com/holmesal/react-native-ios-notification-actions) to add notification actions. 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 4ceb65d5c..84a1653be 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -22,6 +22,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; @@ -58,6 +59,8 @@ public RNPushNotification(ReactApplicationContext reactContext) { mJsDelivery = new RNPushNotificationJsDelivery(reactContext); mRNPushNotificationHelper.checkOrCreateDefaultChannel(); + + registerNotificationsReceiveNotificationActions(); } @Override @@ -92,30 +95,81 @@ public void onNewIntent(Intent intent) { } } - private void registerNotificationsReceiveNotificationActions(ReadableArray actions) { + private void registerNotificationsReceiveNotificationActions() { IntentFilter intentFilter = new IntentFilter(); - // Add filter for each actions. - for (int i = 0; i < actions.size(); i++) { - String action = actions.getString(i); - intentFilter.addAction(getReactApplicationContext().getPackageName() + "." + action); + + for(int i = 0; i < 10; i++) { + intentFilter.addAction(getReactApplicationContext().getPackageName() + ".ACTION_" + i); } + final RNPushNotification self = this; + getReactApplicationContext().registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getBundleExtra("notification"); - // Notify the action. - mJsDelivery.notifyNotificationAction(bundle); - // Dismiss the notification popup. NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); int notificationID = Integer.parseInt(bundle.getString("id")); - manager.cancel(notificationID); + + boolean autoCancel = bundle.getBoolean("autoCancel", true); + + if(autoCancel) { + if (bundle.containsKey("tag")) { + String tag = bundle.getString("tag"); + manager.cancel(tag, notificationID); + } else { + manager.cancel(notificationID); + } + } + + boolean invokeApp = bundle.getBoolean("invokeApp", true); + + // Notify the action. + if(invokeApp) { + self.invokeApp(bundle); + } else { + mJsDelivery.notifyNotificationAction(bundle); + } } }, intentFilter); } + private void invokeApp(Bundle bundle) { + ReactContext reactContext = getReactApplicationContext(); + String packageName = reactContext.getPackageName(); + Intent launchIntent = reactContext.getPackageManager().getLaunchIntentForPackage(packageName); + String className = launchIntent.getComponent().getClassName(); + + try { + Class activityClass = Class.forName(className); + Intent activityIntent = new Intent(reactContext, activityClass); + + if(bundle != null) { + activityIntent.putExtra("notification", bundle); + } + + activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + reactContext.startActivity(activityIntent); + } catch(Exception e) { + Log.e(LOG_TAG, "Class not found", e); + return; + } + } + + @ReactMethod + public void invokeApp(ReadableMap data) { + Bundle bundle = null; + + if (data != null) { + bundle = Arguments.toBundle(data); + } + + invokeApp(bundle); + } + @ReactMethod public void checkPermissions(Promise promise) { ReactContext reactContext = getReactApplicationContext(); @@ -227,13 +281,8 @@ public void cancelLocalNotifications(ReadableMap userInfo) { /** * Clear notification from the notification centre. */ - public void clearLocalNotification(int notificationID) { - mRNPushNotificationHelper.clearNotification(notificationID); - } - - @ReactMethod - public void registerNotificationActions(ReadableArray actions) { - registerNotificationsReceiveNotificationActions(actions); + public void clearLocalNotification(String tag, int notificationID) { + mRNPushNotificationHelper.clearNotification(tag, notificationID); } @ReactMethod @@ -279,4 +328,36 @@ public void run() { } }).start(); } + + @ReactMethod + /** + * List all channels id + */ + public void getChannels(Callback callback) { + WritableArray array = Arguments.fromList(mRNPushNotificationHelper.listChannels()); + + if(callback != null) { + callback.invoke(array); + } + } + + @ReactMethod + /** + * Check if channel exists with a given id + */ + public void channelExists(String channel_id, Callback callback) { + boolean exists = mRNPushNotificationHelper.channelExists(channel_id); + + if(callback != null) { + callback.invoke(exists); + } + } + + @ReactMethod + /** + * Delete channel with a given id + */ + public void deleteChannel(String channel_id) { + mRNPushNotificationHelper.deleteChannel(channel_id); + } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 8df1c850f..3bacacc96 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -38,6 +38,7 @@ public class RNPushNotificationAttributes { private static final String VIBRATE = "vibrate"; private static final String VIBRATION = "vibration"; private static final String ACTIONS = "actions"; + private static final String INVOKE_APP = "invokeApp"; private static final String TAG = "tag"; private static final String REPEAT_TYPE = "repeatType"; private static final String REPEAT_TIME = "repeatTime"; @@ -70,6 +71,7 @@ public class RNPushNotificationAttributes { private final boolean vibrate; private final double vibration; private final String actions; + private final boolean invokeApp; private final String tag; private final String repeatType; private final double repeatTime; @@ -103,6 +105,7 @@ public RNPushNotificationAttributes(Bundle bundle) { vibrate = bundle.getBoolean(VIBRATE); vibration = bundle.getDouble(VIBRATION); actions = bundle.getString(ACTIONS); + invokeApp = bundle.getBoolean(INVOKE_APP); tag = bundle.getString(TAG); repeatType = bundle.getString(REPEAT_TYPE); repeatTime = bundle.getDouble(REPEAT_TIME); @@ -138,6 +141,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { vibrate = jsonObject.has(VIBRATE) ? jsonObject.getBoolean(VIBRATE) : true; vibration = jsonObject.has(VIBRATION) ? jsonObject.getDouble(VIBRATION) : 1000; actions = jsonObject.has(ACTIONS) ? jsonObject.getString(ACTIONS) : null; + invokeApp = jsonObject.has(INVOKE_APP) ? jsonObject.getBoolean(INVOKE_APP) : true; tag = jsonObject.has(TAG) ? jsonObject.getString(TAG) : null; repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null; repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0; @@ -230,6 +234,7 @@ public Bundle toBundle() { bundle.putBoolean(VIBRATE, vibrate); bundle.putDouble(VIBRATION, vibration); bundle.putString(ACTIONS, actions); + bundle.putBoolean(INVOKE_APP, invokeApp); bundle.putString(TAG, tag); bundle.putString(REPEAT_TYPE, repeatType); bundle.putDouble(REPEAT_TIME, repeatTime); @@ -267,6 +272,7 @@ public JSONObject toJson() { jsonObject.put(VIBRATE, vibrate); jsonObject.put(VIBRATION, vibration); jsonObject.put(ACTIONS, actions); + jsonObject.put(INVOKE_APP, invokeApp); jsonObject.put(TAG, tag); jsonObject.put(REPEAT_TYPE, repeatType); jsonObject.put(REPEAT_TIME, repeatTime); @@ -310,6 +316,7 @@ public String toString() { ", vibrate=" + vibrate + ", vibration=" + vibration + ", actions='" + actions + '\'' + + ", invokeApp=" + invokeApp + ", tag='" + tag + '\'' + ", repeatType='" + repeatType + '\'' + ", repeatTime=" + repeatTime + diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index 9be0d7b67..cdd5be61e 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -8,6 +8,7 @@ import android.util.Log; class RNPushNotificationConfig { + private static final String KEY_CHANNEL_CREATE_DEFAULT = "com.dieam.reactnativepushnotification.channel_create_default"; private static final String KEY_CHANNEL_NAME = "com.dieam.reactnativepushnotification.notification_channel_name"; private static final String KEY_CHANNEL_DESCRIPTION = "com.dieam.reactnativepushnotification.notification_channel_description"; private static final String KEY_NOTIFICATION_FOREGROUND = "com.dieam.reactnativepushnotification.notification_foreground"; @@ -77,4 +78,14 @@ public boolean getNotificationForeground() { // Default return false; } + + public boolean getChannelCreateDefault() { + try { + return metadata.getBoolean(KEY_CHANNEL_CREATE_DEFAULT, true); + } catch (Exception e) { + Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_CREATE_DEFAULT + " in manifest. Falling back to default"); + } + // Default + return true; + } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index bd1bb44b0..1a3623039 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -8,6 +8,7 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -36,6 +37,7 @@ import org.json.JSONArray; import org.json.JSONException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -519,18 +521,24 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB continue; } - Intent actionIntent = new Intent(context, intentClass); + + Intent actionIntent = new Intent(packageName + ".ACTION_" + i); + actionIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - actionIntent.setAction(packageName + "." + action); // Add "action" for later identifying which button gets pressed. bundle.putString("action", action); actionIntent.putExtra("notification", bundle); actionIntent.setPackage(packageName); - PendingIntent pendingActionIntent = PendingIntent.getActivity(context, notificationID, actionIntent, + PendingIntent pendingActionIntent = PendingIntent.getBroadcast(context, notificationID, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT); - notification.addAction(icon, action, pendingActionIntent); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + notification.addAction(new NotificationCompat.Action.Builder(icon, action, pendingActionIntent).build()); + } else { + notification.addAction(icon, action, pendingActionIntent); + } } } @@ -648,11 +656,15 @@ public void clearNotifications() { notificationManager.cancelAll(); } - public void clearNotification(int notificationID) { + public void clearNotification(String tag, int notificationID) { Log.i(LOG_TAG, "Clearing notification: " + notificationID); NotificationManager notificationManager = notificationManager(); - notificationManager.cancel(notificationID); + if(tag != null) { + notificationManager.cancel(tag, notificationID); + } else { + notificationManager.cancel(notificationID); + } } public void clearDeliveredNotifications(ReadableArray identifiers) { @@ -690,6 +702,7 @@ public WritableArray getDeliveredNotifications() { return result; } + public void cancelAllScheduledNotifications() { Log.i(LOG_TAG, "Cancelling all notifications"); @@ -750,6 +763,10 @@ private NotificationManager notificationManager() { } public void checkOrCreateDefaultChannel() { + if(!this.config.getChannelCreateDefault()) { + return; + } + NotificationManager manager = notificationManager(); int importance = 4; // Default value of HIGH for lower version @@ -761,12 +778,54 @@ public void checkOrCreateDefaultChannel() { Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); // Instanciate a default channel with default sound. - String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-default-" + importance + "-" + DEFAULT_VIBRATION; + String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-default-" + DEFAULT_VIBRATION; checkOrCreateChannel(manager, channel_id_sound, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); + } + + public List listChannels() { + List channels = new ArrayList<>(); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return channels; + + NotificationManager manager = notificationManager(); + + if (manager == null) + return channels; + + List listChannels = manager.getNotificationChannels(); + + for(NotificationChannel channel : listChannels) { + channels.add(channel.getId()); + } + + return channels; + } + + public boolean channelExists(String channel_id) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return false; + + NotificationManager manager = notificationManager(); + + if (manager == null) + return false; + + NotificationChannel channel = manager.getNotificationChannel(channel_id); + + return channel != null; + } + + public void deleteChannel(String channel_id) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return; + + NotificationManager manager = notificationManager(); + + if (manager == null) + return; - // Instanciate a default channel without sound defined for backward compatibility. - String channel_id_no_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; - checkOrCreateChannel(manager, channel_id_no_sound, null, importance, new long[] {0, DEFAULT_VIBRATION}); + manager.deleteNotificationChannel(channel_id); } private void checkOrCreateChannel(NotificationManager manager, String channel_id, Uri soundUri, int importance, long[] vibratePattern) { @@ -800,7 +859,7 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id } } - private boolean isApplicationInForeground(Context context) { + public boolean isApplicationInForeground(Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List processInfos = activityManager.getRunningAppProcesses(); if (processInfos != null) { diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java index 8f75f91ba..481b8154e 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java @@ -1,26 +1,97 @@ package com.dieam.reactnativepushnotification.modules; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; +import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; + +import org.json.JSONObject; + +import java.util.List; +import java.util.Random; + import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; public class RNPushNotificationPublisher extends BroadcastReceiver { final static String NOTIFICATION_ID = "notificationId"; @Override - public void onReceive(Context context, Intent intent) { + public void onReceive(final Context context, Intent intent) { int id = intent.getIntExtra(NOTIFICATION_ID, 0); long currentTime = System.currentTimeMillis(); Log.i(LOG_TAG, "NotificationPublisher: Prepare To Publish: " + id + ", Now Time: " + currentTime); + final Bundle bundle = intent.getExtras(); + + Log.v(LOG_TAG, "onMessageReceived: " + bundle); + + // We need to run this on the main thread, as the React code assumes that is true. + // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: + // "Can't create handler inside thread that has not called Looper.prepare()" + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + public void run() { + // Construct and load our normal React JS code bundle + final ReactInstanceManager mReactInstanceManager = ((ReactApplication) context.getApplicationContext()).getReactNativeHost().getReactInstanceManager(); + ReactContext context = mReactInstanceManager.getCurrentReactContext(); + // If it's constructed, send a notification + if (context != null) { + handleLocalNotification((ReactApplicationContext) context, bundle); + } else { + // Otherwise wait for construction, then send the notification + mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { + public void onReactContextInitialized(ReactContext context) { + handleLocalNotification((ReactApplicationContext) context, bundle); + mReactInstanceManager.removeReactInstanceEventListener(this); + } + }); + if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + mReactInstanceManager.createReactContextInBackground(); + } + } + } + }); + } + + private void handleLocalNotification(ReactApplicationContext context, Bundle bundle) { + + // If notification ID is not provided by the user for push notification, generate one at random + if (bundle.getString("id") == null) { + Random randomNumberGenerator = new Random(System.currentTimeMillis()); + bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); + } + Application applicationContext = (Application) context.getApplicationContext(); + RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); + + boolean isForeground = pushNotificationHelper.isApplicationInForeground(applicationContext); + + RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); + bundle.putBoolean("foreground", isForeground); + bundle.putBoolean("userInteraction", false); + jsDelivery.notifyNotification(bundle); + + // If contentAvailable is set to true, then send out a remote fetch event + if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) { + jsDelivery.notifyRemoteFetch(bundle); + } + + Log.v(LOG_TAG, "sendNotification: " + bundle); - new RNPushNotificationHelper(applicationContext) - .sendToNotificationCentre(intent.getExtras()); + pushNotificationHelper.sendToNotificationCentre(bundle); } -} +} \ No newline at end of file diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java deleted file mode 100644 index 633ed9c8e..000000000 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationRegistrationService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.dieam.reactnativepushnotification.modules; - -import android.app.IntentService; -import android.content.Intent; -import android.util.Log; - -import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; - -public class RNPushNotificationRegistrationService extends IntentService { - private static final String TAG = "RNPushNotification"; - - public RNPushNotificationRegistrationService() { - super(TAG); - - Log.w(LOG_TAG, TAG + " RNPushNotificationRegistrationService is not needed anymore."); - } - - @Override - protected void onHandleIntent(Intent intent) { - Log.w(LOG_TAG, TAG + " RNPushNotificationRegistrationService is not needed anymore."); - } -} diff --git a/component/index.android.js b/component/index.android.js index 13a442ead..7414942ce 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -1,15 +1,13 @@ 'use strict'; -var { - NativeModules, - DeviceEventEmitter, -} = require('react-native'); +import { NativeModules, DeviceEventEmitter } from "react-native"; var RNPushNotification = NativeModules.RNPushNotification; var _notifHandlers = new Map(); var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived'; var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered'; +var NOTIF_ACTION_EVENT = 'notificationActionReceived'; var REMOTE_FETCH_EVENT = 'remoteFetch'; var NotificationsComponent = function() { @@ -38,8 +36,8 @@ NotificationsComponent.prototype.cancelLocalNotifications = function(details) { RNPushNotification.cancelLocalNotifications(details); }; -NotificationsComponent.prototype.clearLocalNotification = function(details) { - RNPushNotification.clearLocalNotification(details); +NotificationsComponent.prototype.clearLocalNotification = function(details, tag) { + RNPushNotification.clearLocalNotification(details, tag); }; NotificationsComponent.prototype.cancelAllLocalNotifications = function() { @@ -94,7 +92,17 @@ NotificationsComponent.prototype.addEventListener = function(type, handler) { } } ); - } + } else if (type === 'action') { + listener = DeviceEventEmitter.addListener( + NOTIF_ACTION_EVENT, + function(actionData) { + if (actionData && actionData.dataJSON) { + var action = JSON.parse(actionData.dataJSON) + handler(action); + } + } + ); + } _notifHandlers.set(type, listener); }; @@ -131,7 +139,22 @@ NotificationsComponent.prototype.abandonPermissions = function() { RNPushNotification.abandonPermissions(); } +NotificationsComponent.prototype.invokeApp = function(data) { + RNPushNotification.invokeApp(data); +} + +NotificationsComponent.prototype.getChannels = function(callback) { + RNPushNotification.getChannels(callback); +} + +NotificationsComponent.prototype.channelExists = function(channel_id, callback) { + RNPushNotification.channelExists(channel_id, callback); +} + +NotificationsComponent.prototype.deleteChannel = function(channel_id) { + RNPushNotification.deleteChannel(channel_id); +} + module.exports = { - state: false, component: new NotificationsComponent() }; diff --git a/component/index.ios.js b/component/index.ios.js index 400214be0..82eee6a92 100644 --- a/component/index.ios.js +++ b/component/index.ios.js @@ -1,9 +1,7 @@ "use strict"; -import { AppState } from "react-native"; import PushNotificationIOS from "@react-native-community/push-notification-ios"; module.exports = { - state: AppState, component: PushNotificationIOS }; diff --git a/example/NotifService.js b/example/NotifService.js index fbe9f62f3..d28fca39e 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -14,6 +14,10 @@ export default class NotifService { PushNotification.setApplicationIconBadgeNumber(0); } }); + + PushNotification.getChannels(function(channels) { + console.log(channels); + }); } localNotif(soundName) { @@ -33,7 +37,8 @@ export default class NotifService { tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message ongoing: false, // (optional) set whether this is an "ongoing" notification - actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more + actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more + invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ alertAction: 'view', // (optional) default: view @@ -68,6 +73,8 @@ export default class NotifService { tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message ongoing: false, // (optional) set whether this is an "ongoing" notification + actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more + invokeApp: false, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ alertAction: 'view', // (optional) default: view diff --git a/example/NotificationHandler.js b/example/NotificationHandler.js index d21992416..da029447f 100644 --- a/example/NotificationHandler.js +++ b/example/NotificationHandler.js @@ -17,6 +17,14 @@ class NotificationHandler { } } + onAction(notification) { + console.log ('Notification action received:'); + console.log(notification.action); + console.log(notification); + + PushNotification.invokeApp(notification); + } + attachRegister(handler) { this._onRegister = handler; } @@ -35,6 +43,9 @@ PushNotification.configure({ // (required) Called when a remote or local notification is opened or received onNotification: handler.onNotification.bind(handler), + // (optional) Called when Action is pressed (Android) + onAction: handler.onAction.bind(handler), + // IOS ONLY (optional): default: all - Permissions to register. permissions: { alert: true, diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 4af3a8b54..14b795649 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -44,6 +44,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/example/Info.plist b/example/ios/example/Info.plist index 20fb35c96..173ee5c0a 100644 --- a/example/ios/example/Info.plist +++ b/example/ios/example/Info.plist @@ -39,6 +39,12 @@ NSLocationWhenInUseUsageDescription + UIBackgroundModes + + fetch + processing + remote-notification + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/index.js b/index.js index cb52e1e47..b0550433a 100644 --- a/index.js +++ b/index.js @@ -4,9 +4,10 @@ 'use strict'; +import { AppState } from "react-native"; + var RNNotificationsComponent = require( './component' ); -var AppState = RNNotificationsComponent.state; var RNNotifications = RNNotificationsComponent.component; var Platform = require('react-native').Platform; @@ -16,6 +17,7 @@ var Notifications = { onRegister: false, onError: false, onNotification: false, + onAction: false, onRemoteFetch: false, isLoaded: false, idInitialNotification: null, @@ -47,6 +49,7 @@ Notifications.callNative = function(name, params) { * @param {Object} options * @param {function} options.onRegister - Fired when the user registers for remote notifications. * @param {function} options.onNotification - Fired when a remote notification is received. + * @param {function} options.onAction - Fired when a remote notification is received. * @param {function} options.onError - None * @param {Object} options.permissions - Permissions list * @param {Boolean} options.requestPermissions - Check permissions when register @@ -64,6 +67,10 @@ Notifications.configure = function(options) { this.onNotification = options.onNotification; } + if ( typeof options.onAction !== 'undefined' ) { + this.onAction = options.onAction; + } + if ( typeof options.permissions !== 'undefined' ) { this.permissions = options.permissions; } @@ -76,31 +83,41 @@ Notifications.configure = function(options) { this._onRegister = this._onRegister.bind(this); this._onNotification = this._onNotification.bind(this); this._onRemoteFetch = this._onRemoteFetch.bind(this); + this._onAction = this._onAction.bind(this); this.callNative( 'addEventListener', [ 'register', this._onRegister ] ); this.callNative( 'addEventListener', [ 'notification', this._onNotification ] ); this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] ); + this.callNative( 'addEventListener', [ 'action', this._onAction ] ); Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null this.isLoaded = true; } - if (options.popInitialNotification === undefined || options.popInitialNotification === true) { - this.popInitialNotification(function(firstNotification) { - if ( firstNotification !== null ) { - if(this.idInitialNotification === firstNotification.id) { - return; + const handlePopInitialNotification = function(state) { + if('active' !== state) { + return; + } + + if (options.popInitialNotification === undefined || options.popInitialNotification === true) { + this.popInitialNotification(function(firstNotification) { + if ( firstNotification !== null ) { + if(false === firstNotification.userInteraction || this.idInitialNotification === firstNotification.id) { + return; + } + + this.idInitialNotification = firstNotification.id; + this._onNotification(firstNotification, true); } - - this.idInitialNotification = firstNotification.id; - this._onNotification(firstNotification, true); - } - }.bind(this)); + }.bind(this)); + } } + AppState.addEventListener('change', handlePopInitialNotification.bind(this)); + handlePopInitialNotification(); + if ( options.requestPermissions !== false ) { this._requestPermissions(); } - }; /* Unregister */ @@ -108,6 +125,7 @@ Notifications.unregister = function() { this.callNative( 'removeEventListener', [ 'register', this._onRegister ] ) this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] ) this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] ) + this.callNative( 'removeEventListener', [ 'action', this._onAction ] ) Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null this.isLoaded = false; }; @@ -172,6 +190,10 @@ Notifications.localNotification = function(details) { details.shortcutId = '' + details.shortcutId; } } + + if(details && Array.isArray(details.actions)) { + details.actions = JSON.stringify(details.actions); + } this.handler.presentLocalNotification(details); } @@ -241,6 +263,10 @@ Notifications.localNotificationSchedule = function(details) { } } + if(details && Array.isArray(details.actions)) { + details.actions = JSON.stringify(details.actions); + } + details.fireDate = details.date.getTime(); delete details.date; // ignore iOS only repeatType @@ -267,6 +293,18 @@ Notifications._onRemoteFetch = function(notificationData) { } }; +Notifications._onAction = function(notification) { + if ( typeof notification.data === 'string' ) { + try { + notification.data = JSON.parse(notificationData.data); + } catch(e) { + /* void */ + } + } + + this.onAction(notification); +} + Notifications._onNotification = function(data, isFromBackground = null) { if ( isFromBackground === null ) { isFromBackground = ( @@ -388,10 +426,6 @@ Notifications.abandonPermissions = function() { return this.callNative('abandonPermissions', arguments); } -Notifications.registerNotificationActions = function() { - return this.callNative('registerNotificationActions', arguments) -} - Notifications.clearAllNotifications = function() { // Only available for Android return this.callNative('clearAllNotifications', arguments) @@ -409,4 +443,20 @@ Notifications.removeDeliveredNotifications = function() { return this.callNative('removeDeliveredNotifications', arguments); } +Notifications.invokeApp = function() { + return this.callNative('invokeApp', arguments); +}; + +Notifications.getChannels = function() { + return this.callNative('getChannels', arguments); +}; + +Notifications.channelExists = function() { + return this.callNative('channelExists', arguments); +}; + +Notifications.deleteChannel = function() { + return this.callNative('deleteChannel', arguments); +}; + module.exports = Notifications; From 9f4bac38c30b4c915df12247ad76d4485ffbb132 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 31 May 2020 15:20:39 +0200 Subject: [PATCH 037/179] Add reference of PR. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f42cbeabd..ccc470305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Breaking changes -- Now local scheduled notifications trigger `onNotification`. +- Now local scheduled notifications trigger `onNotification` before display [#574](https://github.com/zo0r/react-native-push-notification/pull/574). - `RNPushNotificationRegistrationService` has been remove, old reference in AndroidManifest must be removed. - `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. - `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. From 3e9df6f7051282aa3cfe7614eb79856a1126a22d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 31 May 2020 15:22:09 +0200 Subject: [PATCH 038/179] Fix typo. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc470305..0ec838dd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Breaking changes - Now local scheduled notifications trigger `onNotification` before display [#574](https://github.com/zo0r/react-native-push-notification/pull/574). -- `RNPushNotificationRegistrationService` has been remove, old reference in AndroidManifest must be removed. +- `RNPushNotificationRegistrationService` has been removed, old reference in AndroidManifest must be removed. - `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. - `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. From fc077c62e78b245bf0b7552deb92550c0fd61664 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 3 Jun 2020 11:00:24 +0200 Subject: [PATCH 039/179] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e212c8ec5..0bcfb8825 100644 --- a/README.md +++ b/README.md @@ -296,7 +296,7 @@ PushNotification.localNotification({ smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher" bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop subText: "This is a subText", // (optional) default: none - bigPictureUl: "https://www.example.tld/picture.jpg", // (optional) default: undefined + bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined color: "red", // (optional) default: system default vibrate: true, // (optional) default: true vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 From 4f685aa5a1b211bdf3d8c24178b30a9a262c7519 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 3 Jun 2020 20:20:16 +0200 Subject: [PATCH 040/179] Fix Actions when in killed state. --- CHANGELOG.md | 4 + README.md | 6 ++ .../modules/RNPushNotification.java | 68 +-------------- .../modules/RNPushNotificationActions.java | 86 +++++++++++++++++++ .../modules/RNPushNotificationHelper.java | 26 +++++- .../modules/RNPushNotificationJsDelivery.java | 6 +- example/NotificationHandler.js | 4 +- .../android/app/src/main/AndroidManifest.xml | 1 + 8 files changed, 128 insertions(+), 73 deletions(-) create mode 100644 android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec838dd8..9f0419de6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `RNPushNotificationRegistrationService` has been removed, old reference in AndroidManifest must be removed. - `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. - `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. +- Extra receiver must be added to manage actions. + ```xml + + ``` ### Features diff --git a/README.md b/README.md index 0bcfb8825..ff207947f 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ In your `android/app/src/main/AndroidManifest.xml` + @@ -596,6 +597,11 @@ For e.g. `actions: ['Accept', 'Reject']` When you handle actions in background (`invokeApp: false`), you can open the application and pass the initial notification by using use `PushNotification.invokeApp(notification)`. +Make sure you have the receiver in `AndroidManifest.xml`: +```xml + +``` + For iOS, you can use this [package](https://github.com/holmesal/react-native-ios-notification-actions) to add notification actions. ## Set application badge icon 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 84a1653be..ed586087b 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -59,8 +59,6 @@ public RNPushNotification(ReactApplicationContext reactContext) { mJsDelivery = new RNPushNotificationJsDelivery(reactContext); mRNPushNotificationHelper.checkOrCreateDefaultChannel(); - - registerNotificationsReceiveNotificationActions(); } @Override @@ -94,70 +92,6 @@ public void onNewIntent(Intent intent) { mJsDelivery.notifyNotification(bundle); } } - - private void registerNotificationsReceiveNotificationActions() { - IntentFilter intentFilter = new IntentFilter(); - - for(int i = 0; i < 10; i++) { - intentFilter.addAction(getReactApplicationContext().getPackageName() + ".ACTION_" + i); - } - - final RNPushNotification self = this; - - getReactApplicationContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - Bundle bundle = intent.getBundleExtra("notification"); - - // Dismiss the notification popup. - NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - int notificationID = Integer.parseInt(bundle.getString("id")); - - boolean autoCancel = bundle.getBoolean("autoCancel", true); - - if(autoCancel) { - if (bundle.containsKey("tag")) { - String tag = bundle.getString("tag"); - manager.cancel(tag, notificationID); - } else { - manager.cancel(notificationID); - } - } - - boolean invokeApp = bundle.getBoolean("invokeApp", true); - - // Notify the action. - if(invokeApp) { - self.invokeApp(bundle); - } else { - mJsDelivery.notifyNotificationAction(bundle); - } - } - }, intentFilter); - } - - private void invokeApp(Bundle bundle) { - ReactContext reactContext = getReactApplicationContext(); - String packageName = reactContext.getPackageName(); - Intent launchIntent = reactContext.getPackageManager().getLaunchIntentForPackage(packageName); - String className = launchIntent.getComponent().getClassName(); - - try { - Class activityClass = Class.forName(className); - Intent activityIntent = new Intent(reactContext, activityClass); - - if(bundle != null) { - activityIntent.putExtra("notification", bundle); - } - - activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - reactContext.startActivity(activityIntent); - } catch(Exception e) { - Log.e(LOG_TAG, "Class not found", e); - return; - } - } @ReactMethod public void invokeApp(ReadableMap data) { @@ -167,7 +101,7 @@ public void invokeApp(ReadableMap data) { bundle = Arguments.toBundle(data); } - invokeApp(bundle); + mRNPushNotificationHelper.invokeApp(bundle); } @ReactMethod diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java new file mode 100644 index 000000000..a2015f12c --- /dev/null +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java @@ -0,0 +1,86 @@ +package com.dieam.reactnativepushnotification.modules; + +import android.app.Application; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; + +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; + +public class RNPushNotificationActions extends BroadcastReceiver { + @Override + public void onReceive(final Context context, Intent intent) { + String intentActionPrefix = context.getPackageName() + ".ACTION_"; + + Log.i(LOG_TAG, "RNPushNotificationActions loading action"); + + final Bundle bundle = intent.getBundleExtra("notification"); + + // Dismiss the notification popup. + NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + int notificationID = Integer.parseInt(bundle.getString("id")); + + boolean autoCancel = bundle.getBoolean("autoCancel", true); + + if(autoCancel) { + if (bundle.containsKey("tag")) { + String tag = bundle.getString("tag"); + manager.cancel(tag, notificationID); + } else { + manager.cancel(notificationID); + } + } + + boolean invokeApp = bundle.getBoolean("invokeApp", true); + + // Notify the action. + if(invokeApp) { + RNPushNotificationHelper helper = new RNPushNotificationHelper((Application) context.getApplicationContext()); + + helper.invokeApp(bundle); + } else { + + // We need to run this on the main thread, as the React code assumes that is true. + // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: + // "Can't create handler inside thread that has not called Looper.prepare()" + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + public void run() { + // Construct and load our normal React JS code bundle + final ReactInstanceManager mReactInstanceManager = ((ReactApplication) context.getApplicationContext()).getReactNativeHost().getReactInstanceManager(); + ReactContext context = mReactInstanceManager.getCurrentReactContext(); + // If it's constructed, send a notification + if (context != null) { + RNPushNotificationJsDelivery mJsDelivery = new RNPushNotificationJsDelivery(context); + + mJsDelivery.notifyNotificationAction(bundle); + } else { + // Otherwise wait for construction, then send the notification + mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { + public void onReactContextInitialized(ReactContext context) { + RNPushNotificationJsDelivery mJsDelivery = new RNPushNotificationJsDelivery(context); + + mJsDelivery.notifyNotificationAction(bundle); + + mReactInstanceManager.removeReactInstanceEventListener(this); + } + }); + if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { + // Construct it in the background + mReactInstanceManager.createReactContextInBackground(); + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 1a3623039..3b037b758 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -8,7 +8,6 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -29,6 +28,7 @@ import androidx.core.app.NotificationCompat; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableArray; @@ -81,6 +81,28 @@ private AlarmManager getAlarmManager() { return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); } + public void invokeApp(Bundle bundle) { + String packageName = context.getPackageName(); + Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); + String className = launchIntent.getComponent().getClassName(); + + try { + Class activityClass = Class.forName(className); + Intent activityIntent = new Intent(context, activityClass); + + if(bundle != null) { + activityIntent.putExtra("notification", bundle); + } + + activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + context.startActivity(activityIntent); + } catch(Exception e) { + Log.e(LOG_TAG, "Class not found", e); + return; + } + } + private PendingIntent toScheduleNotificationIntent(Bundle bundle) { try { int notificationID = Integer.parseInt(bundle.getString("id")); @@ -522,7 +544,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB } - Intent actionIntent = new Intent(packageName + ".ACTION_" + i); + Intent actionIntent = new Intent(context, RNPushNotificationActions.class); actionIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java index b223757fa..350758e57 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationJsDelivery.java @@ -4,7 +4,7 @@ import android.os.Bundle; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -18,9 +18,9 @@ */ public class RNPushNotificationJsDelivery { - private ReactApplicationContext mReactContext; + private ReactContext mReactContext; - public RNPushNotificationJsDelivery(ReactApplicationContext reactContext) { + public RNPushNotificationJsDelivery(ReactContext reactContext) { mReactContext = reactContext; } diff --git a/example/NotificationHandler.js b/example/NotificationHandler.js index da029447f..df2d6d9b4 100644 --- a/example/NotificationHandler.js +++ b/example/NotificationHandler.js @@ -22,7 +22,9 @@ class NotificationHandler { console.log(notification.action); console.log(notification); - PushNotification.invokeApp(notification); + if(notification.action === 'Yes') { + PushNotification.invokeApp(notification); + } } attachRegister(handler) { diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 14b795649..ca312e8f9 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -29,6 +29,7 @@ + From 1db692b7cd49c84bc2e6b961dec515feaffdd5dc Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 3 Jun 2020 22:26:07 +0200 Subject: [PATCH 041/179] Fix bug with action, only last action was notified. --- .../modules/RNPushNotificationActions.java | 6 +++++- .../modules/RNPushNotificationHelper.java | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java index a2015f12c..612812561 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java @@ -21,7 +21,11 @@ public class RNPushNotificationActions extends BroadcastReceiver { public void onReceive(final Context context, Intent intent) { String intentActionPrefix = context.getPackageName() + ".ACTION_"; - Log.i(LOG_TAG, "RNPushNotificationActions loading action"); + Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver loading scheduled notifications"); + + if (null == intent.getAction() || !intent.getAction().startsWith(intentActionPrefix)) { + return; + } final Bundle bundle = intent.getBundleExtra("notification"); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 3b037b758..5ecc8adb3 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -545,6 +545,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Intent actionIntent = new Intent(context, RNPushNotificationActions.class); + actionIntent.setAction(packageName + ".ACTION_" + i); actionIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); From 8c4a4fc4050af3c70aa1ec991a8f5e8f9ed25e4c Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 4 Jun 2020 15:31:34 +0200 Subject: [PATCH 042/179] Fix iOS crash with iOS. --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index b0550433a..3bf51336c 100644 --- a/index.js +++ b/index.js @@ -87,7 +87,7 @@ Notifications.configure = function(options) { this.callNative( 'addEventListener', [ 'register', this._onRegister ] ); this.callNative( 'addEventListener', [ 'notification', this._onNotification ] ); this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] ); - this.callNative( 'addEventListener', [ 'action', this._onAction ] ); + Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'action', this._onAction ] ) : null Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null this.isLoaded = true; @@ -125,7 +125,7 @@ Notifications.unregister = function() { this.callNative( 'removeEventListener', [ 'register', this._onRegister ] ) this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] ) this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] ) - this.callNative( 'removeEventListener', [ 'action', this._onAction ] ) + Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'action', this._onAction ] ) : null Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'remoteFetch', this._onRemoteFetch ] ) : null this.isLoaded = false; }; From 3ecb5ec1273dc121835cf9e26c5d2339a1919935 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Fri, 5 Jun 2020 15:43:53 +0300 Subject: [PATCH 043/179] getScheduledLocalNotifications for iOS and android --- .../modules/RNPushNotification.java | 10 +- .../modules/RNPushNotificationHelper.java | 189 ++++++++++-------- component/index.android.js | 25 ++- index.js | 16 +- 4 files changed, 138 insertions(+), 102 deletions(-) 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 4ceb65d5c..f9d3e6805 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -250,7 +250,15 @@ public void removeAllDeliveredNotifications() { * Returns a list of all notifications currently in the Notification Center */ public void getDeliveredNotifications(Callback callback) { - callback.invoke(mRNPushNotificationHelper.getDeliveredNotifications()); + callback.invoke(mRNPushNotificationHelper.getDeliveredNotifications()); + } + + @ReactMethod + /** + * Returns a list of all currently scheduled notifications + */ + public void getScheduledLocalNotifications(Callback callback) { + callback.invoke(mRNPushNotificationHelper.getScheduledLocalNotifications()); } @ReactMethod diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 84bb493ee..2445284a5 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; + import androidx.core.app.NotificationCompat; import com.facebook.react.bridge.Arguments; @@ -40,7 +41,7 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.List; -import java.util.Set; +import java.util.Map; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; import static com.dieam.reactnativepushnotification.modules.RNPushNotificationAttributes.fromJson; @@ -143,14 +144,14 @@ public void sendNotificationScheduledCore(Bundle bundle) { // notification to the user PendingIntent pendingIntent = toScheduleNotificationIntent(bundle); - if(pendingIntent == null) { + if (pendingIntent == null) { return; } Log.d(LOG_TAG, String.format("Setting a notification with id %s at time %s", bundle.getString("id"), Long.toString(fireDate))); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if(allowWhileIdle && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (allowWhileIdle && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getAlarmManager().setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent); } else { getAlarmManager().setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent); @@ -195,7 +196,7 @@ public void sendToNotificationCentre(Bundle bundle) { final String priorityString = bundle.getString("priority"); if (priorityString != null) { - switch(priorityString.toLowerCase()) { + switch (priorityString.toLowerCase()) { case "max": priority = NotificationCompat.PRIORITY_MAX; break; @@ -217,35 +218,35 @@ public void sendToNotificationCentre(Bundle bundle) { } int importance = NotificationManager.IMPORTANCE_HIGH; - final String importanceString = bundle.getString("importance"); - - if (importanceString != null) { - switch(importanceString.toLowerCase()) { - case "default": - importance = NotificationManager.IMPORTANCE_DEFAULT; - break; - case "max": - importance = NotificationManager.IMPORTANCE_MAX; - break; - case "high": - importance = NotificationManager.IMPORTANCE_HIGH; - break; - case "low": - importance = NotificationManager.IMPORTANCE_LOW; - break; - case "min": - importance = NotificationManager.IMPORTANCE_MIN; - break; - case "none": - importance = NotificationManager.IMPORTANCE_NONE; - break; - case "unspecified": - importance = NotificationManager.IMPORTANCE_UNSPECIFIED; - break; - default: - importance = NotificationManager.IMPORTANCE_HIGH; - } - } + final String importanceString = bundle.getString("importance"); + + if (importanceString != null) { + switch (importanceString.toLowerCase()) { + case "default": + importance = NotificationManager.IMPORTANCE_DEFAULT; + break; + case "max": + importance = NotificationManager.IMPORTANCE_MAX; + break; + case "high": + importance = NotificationManager.IMPORTANCE_HIGH; + break; + case "low": + importance = NotificationManager.IMPORTANCE_LOW; + break; + case "min": + importance = NotificationManager.IMPORTANCE_MIN; + break; + case "none": + importance = NotificationManager.IMPORTANCE_NONE; + break; + case "unspecified": + importance = NotificationManager.IMPORTANCE_UNSPECIFIED; + break; + default: + importance = NotificationManager.IMPORTANCE_HIGH; + } + } channel_id = channel_id + "-" + importance; @@ -253,7 +254,7 @@ public void sendToNotificationCentre(Bundle bundle) { final String visibilityString = bundle.getString("visibility"); if (visibilityString != null) { - switch(visibilityString.toLowerCase()) { + switch (visibilityString.toLowerCase()) { case "private": visibility = NotificationCompat.VISIBILITY_PRIVATE; break; @@ -274,12 +275,12 @@ public void sendToNotificationCentre(Bundle bundle) { .setVisibility(visibility) .setPriority(priority) .setAutoCancel(bundle.getBoolean("autoCancel", true)); - + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher // Changing Default mode of notification notification.setDefaults(Notification.DEFAULT_LIGHTS); } - + String group = bundle.getString("group"); if (group != null) { @@ -350,9 +351,9 @@ public void sendToNotificationCentre(Bundle bundle) { if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - + String soundName = bundle.getString("soundName"); - + if (soundName != null) { if (!"default".equalsIgnoreCase(soundName)) { @@ -414,7 +415,7 @@ public void sendToNotificationCentre(Bundle bundle) { long vibration = bundle.containsKey("vibration") ? (long) bundle.getDouble("vibration") : DEFAULT_VIBRATION; if (vibration == 0) vibration = DEFAULT_VIBRATION; - + channel_id = channel_id + "-" + vibration; vibratePattern = new long[]{0, vibration}; @@ -480,7 +481,7 @@ public void sendToNotificationCentre(Bundle bundle) { if (!(this.isApplicationInForeground(context) && bundle.getBoolean("ignoreInForeground"))) { Notification info = notification.build(); info.defaults |= Notification.DEFAULT_LIGHTS; - + if (bundle.containsKey("tag")) { String tag = bundle.getString("tag"); notificationManager.notify(tag, notificationID, info); @@ -585,39 +586,59 @@ public void clearNotification(int notificationID) { } public void clearDeliveredNotifications(ReadableArray identifiers) { - NotificationManager notificationManager = notificationManager(); - for (int index = 0; index < identifiers.size(); index++) { - String id = identifiers.getString(index); - Log.i(LOG_TAG, "Removing notification with id " + id); - notificationManager.cancel(Integer.parseInt(id)); - } + NotificationManager notificationManager = notificationManager(); + for (int index = 0; index < identifiers.size(); index++) { + String id = identifiers.getString(index); + Log.i(LOG_TAG, "Removing notification with id " + id); + notificationManager.cancel(Integer.parseInt(id)); + } } public WritableArray getDeliveredNotifications() { - NotificationManager notificationManager = notificationManager(); - StatusBarNotification delivered[] = notificationManager.getActiveNotifications(); - Log.i(LOG_TAG, "Found " + delivered.length + " delivered notifications"); - WritableArray result = Arguments.createArray(); - /* - * stay consistent to the return structure in - * https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications - * but there is no such thing as a 'userInfo' - */ - for (StatusBarNotification notification : delivered) { - Notification original = notification.getNotification(); - Bundle extras = original.extras; - WritableMap notif = Arguments.createMap(); - notif.putString("identifier", "" + notification.getId()); - notif.putString("title", extras.getString(Notification.EXTRA_TITLE)); - notif.putString("body", extras.getString(Notification.EXTRA_TEXT)); - notif.putString("tag", notification.getTag()); - notif.putString("group", original.getGroup()); - result.pushMap(notif); - } - - return result; + NotificationManager notificationManager = notificationManager(); + StatusBarNotification delivered[] = notificationManager.getActiveNotifications(); + Log.i(LOG_TAG, "Found " + delivered.length + " delivered notifications"); + WritableArray result = Arguments.createArray(); + /* + * stay consistent to the return structure in + * https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications + * but there is no such thing as a 'userInfo' + */ + for (StatusBarNotification notification : delivered) { + Notification original = notification.getNotification(); + Bundle extras = original.extras; + WritableMap notif = Arguments.createMap(); + notif.putString("identifier", "" + notification.getId()); + notif.putString("title", extras.getString(Notification.EXTRA_TITLE)); + notif.putString("body", extras.getString(Notification.EXTRA_TEXT)); + notif.putString("tag", notification.getTag()); + notif.putString("group", original.getGroup()); + result.pushMap(notif); + } + + return result; } + + public WritableArray getScheduledLocalNotifications() { + WritableArray scheduled = Arguments.createArray(); + + Map scheduledNotifications = scheduledNotificationsPersistence.getAll(); + for (Map.Entry entry : scheduledNotifications.entrySet()) { + try { + RNPushNotificationAttributes notification = fromJson(entry.getValue().toString()); + WritableMap notificationMap = Arguments.makeNativeMap(notification.toBundle()); + + scheduled.pushMap(notificationMap); + } catch (JSONException e) { + Log.e(LOG_TAG, e.getMessage()); + } + } + + return scheduled; + + } + public void cancelAllScheduledNotifications() { Log.i(LOG_TAG, "Cancelling all notifications"); @@ -650,7 +671,7 @@ private void cancelScheduledNotification(String notificationIDString) { b.putString("id", notificationIDString); PendingIntent pendingIntent = toScheduleNotificationIntent(b); - if(pendingIntent != null) { + if (pendingIntent != null) { getAlarmManager().cancel(pendingIntent); } @@ -686,18 +707,18 @@ private static void commit(SharedPreferences.Editor editor) { } public void checkOrCreateDefaultChannel() { - NotificationManager manager = notificationManager(); - - int importance = NotificationManager.IMPORTANCE_HIGH; - Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - - // Instanciate a default channel with default sound. - String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-default-" + importance + "-" + DEFAULT_VIBRATION; - checkOrCreateChannel(manager, channel_id_sound, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); - - // Instanciate a default channel without sound defined for backward compatibility. - String channel_id_no_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; - checkOrCreateChannel(manager, channel_id_no_sound, null, importance, new long[] {0, DEFAULT_VIBRATION}); + NotificationManager manager = notificationManager(); + + int importance = NotificationManager.IMPORTANCE_HIGH; + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + // Instanciate a default channel with default sound. + String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-default-" + importance + "-" + DEFAULT_VIBRATION; + checkOrCreateChannel(manager, channel_id_sound, soundUri, importance, new long[]{0, DEFAULT_VIBRATION}); + + // Instanciate a default channel without sound defined for backward compatibility. + String channel_id_no_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-" + DEFAULT_VIBRATION; + checkOrCreateChannel(manager, channel_id_no_sound, null, importance, new long[]{0, DEFAULT_VIBRATION}); } private void checkOrCreateChannel(NotificationManager manager, String channel_id, Uri soundUri, int importance, long[] vibratePattern) { @@ -730,15 +751,15 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id manager.createNotificationChannel(channel); } } - + private boolean isApplicationInForeground(Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List processInfos = activityManager.getRunningAppProcesses(); if (processInfos != null) { for (RunningAppProcessInfo processInfo : processInfos) { if (processInfo.processName.equals(context.getPackageName()) - && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND - && processInfo.pkgList.length > 0) { + && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND + && processInfo.pkgList.length > 0) { return true; } } diff --git a/component/index.android.js b/component/index.android.js index 13a442ead..e0342e33f 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -1,18 +1,18 @@ 'use strict'; -var { +let { NativeModules, DeviceEventEmitter, } = require('react-native'); -var RNPushNotification = NativeModules.RNPushNotification; -var _notifHandlers = new Map(); +let RNPushNotification = NativeModules.RNPushNotification; +let _notifHandlers = new Map(); -var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived'; -var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered'; -var REMOTE_FETCH_EVENT = 'remoteFetch'; +let DEVICE_NOTIF_EVENT = 'remoteNotificationReceived'; +let NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered'; +let REMOTE_FETCH_EVENT = 'remoteFetch'; -var NotificationsComponent = function() { +let NotificationsComponent = function() { }; @@ -66,13 +66,13 @@ NotificationsComponent.prototype.checkPermissions = function(callback) { }; NotificationsComponent.prototype.addEventListener = function(type, handler) { - var listener; + let listener; if (type === 'notification') { listener = DeviceEventEmitter.addListener( DEVICE_NOTIF_EVENT, function(notifData) { if (notifData && notifData.dataJSON) { - var data = JSON.parse(notifData.dataJSON); + let data = JSON.parse(notifData.dataJSON); handler(data); } } @@ -89,7 +89,7 @@ NotificationsComponent.prototype.addEventListener = function(type, handler) { REMOTE_FETCH_EVENT, function(notifData) { if (notifData && notifData.dataJSON) { - var notificationData = JSON.parse(notifData.dataJSON) + let notificationData = JSON.parse(notifData.dataJSON) handler(notificationData); } } @@ -100,7 +100,7 @@ NotificationsComponent.prototype.addEventListener = function(type, handler) { }; NotificationsComponent.prototype.removeEventListener = function(type, handler) { - var listener = _notifHandlers.get(type); + let listener = _notifHandlers.get(type); if (!listener) { return; } @@ -123,6 +123,9 @@ NotificationsComponent.prototype.removeAllDeliveredNotifications = function() { NotificationsComponent.prototype.getDeliveredNotifications = function(callback) { RNPushNotification.getDeliveredNotifications(callback); } +NotificationsComponent.prototype.getScheduledLocalNotifications = function(callback) { + RNPushNotification.getScheduledLocalNotifications(callback); +} NotificationsComponent.prototype.removeDeliveredNotifications = function(identifiers) { RNPushNotification.removeDeliveredNotifications(identifiers); } diff --git a/index.js b/index.js index 3dd36a8f9..23f4224b9 100644 --- a/index.js +++ b/index.js @@ -4,14 +4,14 @@ 'use strict'; -var RNNotificationsComponent = require( './component' ); +let RNNotificationsComponent = require( './component' ); -var AppState = RNNotificationsComponent.state; -var RNNotifications = RNNotificationsComponent.component; +let AppState = RNNotificationsComponent.state; +let RNNotifications = RNNotificationsComponent.component; -var Platform = require('react-native').Platform; +let Platform = require('react-native').Platform; -var Notifications = { +let Notifications = { handler: RNNotifications, onRegister: false, onError: false, @@ -269,7 +269,7 @@ Notifications._onNotification = function(data, isFromBackground = null) { finish: (res) => data.finish(res) }); } else { - var notificationData = { + let notificationData = { foreground: ! isFromBackground, finish: () => {}, ...data @@ -385,6 +385,10 @@ Notifications.getDeliveredNotifications = function() { return this.callNative('getDeliveredNotifications', arguments); } +Notifications.getScheduledLocalNotifications = function() { + return this.callNative('getScheduledLocalNotifications', arguments); +} + Notifications.removeDeliveredNotifications = function() { return this.callNative('removeDeliveredNotifications', arguments); } From 50da5a502c06568aa22985bb8c735da355d3459c Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Fri, 5 Jun 2020 15:50:31 +0300 Subject: [PATCH 044/179] remove changes in whitespaces --- .../modules/RNPushNotificationHelper.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 830403e1d..59b4fab3b 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -692,8 +692,8 @@ public void clearNotification(String tag, int notificationID) { } public void clearDeliveredNotifications(ReadableArray identifiers) { - NotificationManager notificationManager = notificationManager(); - for (int index = 0; index < identifiers.size(); index++) { + NotificationManager notificationManager = notificationManager(); + for (int index = 0; index < identifiers.size(); index++) { String id = identifiers.getString(index); Log.i(LOG_TAG, "Removing notification with id " + id); notificationManager.cancel(Integer.parseInt(id)); @@ -702,26 +702,26 @@ public void clearDeliveredNotifications(ReadableArray identifiers) { @RequiresApi(api = Build.VERSION_CODES.M) public WritableArray getDeliveredNotifications() { - NotificationManager notificationManager = notificationManager(); - StatusBarNotification delivered[] = notificationManager.getActiveNotifications(); - Log.i(LOG_TAG, "Found " + delivered.length + " delivered notifications"); - WritableArray result = Arguments.createArray(); - /* - * stay consistent to the return structure in - * https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications - * but there is no such thing as a 'userInfo' - */ - for (StatusBarNotification notification : delivered) { - Notification original = notification.getNotification(); - Bundle extras = original.extras; - WritableMap notif = Arguments.createMap(); - notif.putString("identifier", "" + notification.getId()); - notif.putString("title", extras.getString(Notification.EXTRA_TITLE)); - notif.putString("body", extras.getString(Notification.EXTRA_TEXT)); - notif.putString("tag", notification.getTag()); - notif.putString("group", original.getGroup()); - result.pushMap(notif); - } + NotificationManager notificationManager = notificationManager(); + StatusBarNotification delivered[] = notificationManager.getActiveNotifications(); + Log.i(LOG_TAG, "Found " + delivered.length + " delivered notifications"); + WritableArray result = Arguments.createArray(); + /* + * stay consistent to the return structure in + * https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications + * but there is no such thing as a 'userInfo' + */ + for (StatusBarNotification notification : delivered) { + Notification original = notification.getNotification(); + Bundle extras = original.extras; + WritableMap notif = Arguments.createMap(); + notif.putString("identifier", "" + notification.getId()); + notif.putString("title", extras.getString(Notification.EXTRA_TITLE)); + notif.putString("body", extras.getString(Notification.EXTRA_TEXT)); + notif.putString("tag", notification.getTag()); + notif.putString("group", original.getGroup()); + result.pushMap(notif); + } return result; From 3822a9b8cf1c93bf7458e51ab1921062f1f5b00f Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Fri, 5 Jun 2020 15:51:35 +0300 Subject: [PATCH 045/179] whitespaces --- .../modules/RNPushNotificationHelper.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 59b4fab3b..eb821057a 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -694,10 +694,10 @@ public void clearNotification(String tag, int notificationID) { public void clearDeliveredNotifications(ReadableArray identifiers) { NotificationManager notificationManager = notificationManager(); for (int index = 0; index < identifiers.size(); index++) { - String id = identifiers.getString(index); - Log.i(LOG_TAG, "Removing notification with id " + id); - notificationManager.cancel(Integer.parseInt(id)); - } + String id = identifiers.getString(index); + Log.i(LOG_TAG, "Removing notification with id " + id); + notificationManager.cancel(Integer.parseInt(id)); + } } @RequiresApi(api = Build.VERSION_CODES.M) @@ -723,7 +723,7 @@ public WritableArray getDeliveredNotifications() { result.pushMap(notif); } - return result; + return result; } From a74d91984635a7c503136eb58a9f8a6549cca16b Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 13:21:01 +0300 Subject: [PATCH 046/179] format android getScheduledLocalNotifications return object to match iOS return object --- .../modules/RNPushNotificationHelper.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index eb821057a..eb6cc120b 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -28,7 +28,6 @@ import androidx.core.app.NotificationCompat; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableArray; @@ -37,6 +36,7 @@ import org.json.JSONArray; import org.json.JSONException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -731,10 +731,27 @@ public WritableArray getScheduledLocalNotifications() { WritableArray scheduled = Arguments.createArray(); Map scheduledNotifications = scheduledNotificationsPersistence.getAll(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"); + for (Map.Entry entry : scheduledNotifications.entrySet()) { try { RNPushNotificationAttributes notification = fromJson(entry.getValue().toString()); - WritableMap notificationMap = Arguments.makeNativeMap(notification.toBundle()); + WritableMap notificationMap = Arguments.createMap(); + + long fireDateTimestamp = (long) notification.getFireDate(); + Date date = new java.util.Date(fireDateTimestamp); + String fireDate = formatter.format(date); + + notificationMap.putString("alertTitle", notification.getTitle()); + notificationMap.putString("alertBody", notification.getMessage()); + notificationMap.putString("alertAction", notification.getActions()); + notificationMap.putString("applicationIconBadgeNumber", notification.getNumber()); + notificationMap.putString("fireDate", fireDate); + notificationMap.putString("id", notification.getId()); + notificationMap.putBoolean("remote", false); + notificationMap.putString("repeatInterval", notification.getRepeatType()); + notificationMap.putString("soundName", notification.getSound()); + scheduled.pushMap(notificationMap); } catch (JSONException e) { @@ -743,7 +760,6 @@ public WritableArray getScheduledLocalNotifications() { } return scheduled; - } public void cancelAllScheduledNotifications() { From 0e5ad3493cb0890d56fba5e5c9829dbe689ea16e Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 13:32:50 +0300 Subject: [PATCH 047/179] change naming of notification params returned on android, return date in unix timestamp as before --- .../modules/RNPushNotificationHelper.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index eb6cc120b..6b1d66e29 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -36,7 +36,6 @@ import org.json.JSONArray; import org.json.JSONException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -731,22 +730,16 @@ public WritableArray getScheduledLocalNotifications() { WritableArray scheduled = Arguments.createArray(); Map scheduledNotifications = scheduledNotificationsPersistence.getAll(); - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"); for (Map.Entry entry : scheduledNotifications.entrySet()) { try { RNPushNotificationAttributes notification = fromJson(entry.getValue().toString()); WritableMap notificationMap = Arguments.createMap(); - long fireDateTimestamp = (long) notification.getFireDate(); - Date date = new java.util.Date(fireDateTimestamp); - String fireDate = formatter.format(date); - - notificationMap.putString("alertTitle", notification.getTitle()); - notificationMap.putString("alertBody", notification.getMessage()); - notificationMap.putString("alertAction", notification.getActions()); - notificationMap.putString("applicationIconBadgeNumber", notification.getNumber()); - notificationMap.putString("fireDate", fireDate); + notificationMap.putString("title", notification.getTitle()); + notificationMap.putString("message", notification.getMessage()); + notificationMap.putString("number", notification.getNumber()); + notificationMap.putString("date", notification.getFireDate()); notificationMap.putString("id", notification.getId()); notificationMap.putBoolean("remote", false); notificationMap.putString("repeatInterval", notification.getRepeatType()); From e207fa8d626d40bb5c95e8b1128a25065729a94f Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 13:54:11 +0300 Subject: [PATCH 048/179] add missing getters for notification attributes --- .../modules/RNPushNotificationAttributes.java | 20 +++++++++++++++++++ .../modules/RNPushNotificationHelper.java | 3 +-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 3bacacc96..2ecf82581 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -330,6 +330,26 @@ public String getId() { return id; } + public String getSound() { + return sound; + } + + public String getMessage() { + return message; + } + + public String getTitle() { + return title; + } + + public String getNumber() { + return number; + } + + public String getRepeatType() { + return repeatType; + } + public double getFireDate() { return fireDate; } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 6b1d66e29..0d4cdb362 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -739,13 +739,12 @@ public WritableArray getScheduledLocalNotifications() { notificationMap.putString("title", notification.getTitle()); notificationMap.putString("message", notification.getMessage()); notificationMap.putString("number", notification.getNumber()); - notificationMap.putString("date", notification.getFireDate()); + notificationMap.putDouble("date", notification.getFireDate()); notificationMap.putString("id", notification.getId()); notificationMap.putBoolean("remote", false); notificationMap.putString("repeatInterval", notification.getRepeatType()); notificationMap.putString("soundName", notification.getSound()); - scheduled.pushMap(notificationMap); } catch (JSONException e) { Log.e(LOG_TAG, e.getMessage()); From b62b27b16de43a76e8dc298231b8db0dfb380123 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 14:36:16 +0300 Subject: [PATCH 049/179] map scheduled local notifications to united return object for both platforms --- index.js | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 2e897b649..d6d2cdf0b 100644 --- a/index.js +++ b/index.js @@ -439,8 +439,42 @@ Notifications.getDeliveredNotifications = function() { return this.callNative('getDeliveredNotifications', arguments); } -Notifications.getScheduledLocalNotifications = function() { - return this.callNative('getScheduledLocalNotifications', arguments); +Notifications.getScheduledLocalNotifications = function(callback) { + const mapNotifications = (notifications) => { + let mappedNotifications = []; + if(notifications?.length > 0) { + if(Platform.OS === 'ios'){ + mappedNotifications = notifications.map(notif => { + return ({ + soundName: notif.soundName, + repeatInterval: notif.repeatInterval, + remote: notif.remote, + id: notif.userInfo?.id, + date: notif.fireDate, + number: notif?.applicationIconBadgeNumber, + message: notif?.alertBody, + title: notif?.alertTitle, + }) + }) + } else if(Platform.OS === 'android') { + mappedNotifications = notifications.map(notif => { + return ({ + soundName: notif.soundName, + repeatInterval: notif.repeatInterval, + remote: notif.remote, + id: notif.id, + date: notif.date, + number: notif.number, + message: notif.message, + title: notif.title, + }) + }) + } + } + callback(mappedNotifications); + } + + return this.callNative('getScheduledLocalNotifications', [mapNotifications]); } Notifications.removeDeliveredNotifications = function() { From 7c0a381275c2ea1626a1ed95e71040515b6cc62c Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 15:07:55 +0300 Subject: [PATCH 050/179] format date for scheduled notifications object --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index d6d2cdf0b..e56716cbd 100644 --- a/index.js +++ b/index.js @@ -450,7 +450,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { repeatInterval: notif.repeatInterval, remote: notif.remote, id: notif.userInfo?.id, - date: notif.fireDate, + date: new Date(notif.fireDate), number: notif?.applicationIconBadgeNumber, message: notif?.alertBody, title: notif?.alertTitle, @@ -463,7 +463,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { repeatInterval: notif.repeatInterval, remote: notif.remote, id: notif.id, - date: notif.date, + date: new Date(notif.date), number: notif.number, message: notif.message, title: notif.title, From d904712d235373b05f9a37a172b8605dd257d9ea Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 15:08:12 +0300 Subject: [PATCH 051/179] bump @react-native-community/push-notification-ios to v1.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc11f1c34..71e9dafe3 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.2.0" + "@react-native-community/push-notification-ios": "^1.2.1" }, "peerDependencies": { "react-native": ">=0.33" From c4865aaf615704da65d7fc841fe975d439c36bb0 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 16:25:20 +0300 Subject: [PATCH 052/179] add example button to log scheduled notifications --- example/App.js | 7 +++++++ example/NotifService.js | 4 ++++ example/ios/Podfile.lock | 6 +++--- example/package.json | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/example/App.js b/example/App.js index 05840d965..a4c8458b0 100644 --- a/example/App.js +++ b/example/App.js @@ -105,6 +105,13 @@ export default class App extends Component { }}> Abandon Permissions + { + this.notif.getScheduledLocalNotifications(notifs => console.log(notifs)); + }}> + Console.Log Scheduled Local Notifications + diff --git a/example/NotifService.js b/example/NotifService.js index d28fca39e..ab9bac75d 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -109,4 +109,8 @@ export default class NotifService { abandonPermissions() { PushNotification.abandonPermissions(); } + + getScheduledLocalNotifications(callback) { + PushNotification.getScheduledLocalNotifications(callback); + } } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index cc1639da9..509394e20 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -292,7 +292,7 @@ PODS: - React-cxxreact (= 0.62.2) - React-jsi (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2) - - RNCPushNotificationIOS (1.1.1): + - RNCPushNotificationIOS (1.2.1): - React - Yoga (1.14.0) - YogaKit (1.18.1): @@ -453,10 +453,10 @@ SPEC CHECKSUMS: React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNCPushNotificationIOS: a0b6894f4ad9b93d9dac467fdf4d055660ac8a0d + RNCPushNotificationIOS: 5878fb73cb1a8a78c3a1a0834d969b01553836d0 Yoga: 3ebccbdd559724312790e7742142d062476b698e YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 56c2537f71f3f02200d6918c542a8e89a0b422fa -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.2 diff --git a/example/package.json b/example/package.json index b01e827fe..70f616c0b 100644 --- a/example/package.json +++ b/example/package.json @@ -7,7 +7,8 @@ "ios": "react-native run-ios", "start": "react-native start", "test": "jest", - "lint": "eslint ." + "lint": "eslint .", + "pod-install": "cd ios && pod install" }, "dependencies": { "@react-native-community/push-notification-ios": "^1.1.1", From ee9b9b7d183b189b649002345deeb2641d148bff Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 8 Jun 2020 16:34:59 +0300 Subject: [PATCH 053/179] add docs --- README.md | 26 +++++++++++++++++++ .../modules/RNPushNotificationHelper.java | 1 - index.js | 2 -- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ff207947f..978ac74a2 100644 --- a/README.md +++ b/README.md @@ -524,6 +524,32 @@ Removes the specified notifications from Notification Center | ----------- | ----- | -------- | ---------------------------------- | | identifiers | array | Yes | Array of notification identifiers. | +### 6) getScheduledLocalNotifications + +```javascript +PushNotificationIOS.getScheduledLocalNotifications(callback); +``` + +Provides you with a list of the app’s scheduled local notifications that are yet to be displayed + +**Parameters:** + +| Name | Type | Required | Description | +| -------- | -------- | -------- | ----------------------------------------------------------- | +| callback | function | Yes | Function which receive an array of delivered notifications. | + +Returns an array of local scheduled notification objects containing: + +| Name | Type | Description | +| -------- | -------- | -------- | ----------------------------------------------------------- | +| id | number | The identifier of this notification. | +| date | Date | The fire date of this notification. | +| title | string | The title of this notification. | +| message | string | The message body of this notification. | +| soundName | string | The sound name of this notification. | +| repeatInterval | number | The repeat interval of this notification. | +| number | number | App notification badge count number. | + ## Abandon Permissions `PushNotification.abandonPermissions()` Revokes the current token and unregister for all remote notifications received via APNS or FCM. diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 0d4cdb362..c8f3a57dd 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -741,7 +741,6 @@ public WritableArray getScheduledLocalNotifications() { notificationMap.putString("number", notification.getNumber()); notificationMap.putDouble("date", notification.getFireDate()); notificationMap.putString("id", notification.getId()); - notificationMap.putBoolean("remote", false); notificationMap.putString("repeatInterval", notification.getRepeatType()); notificationMap.putString("soundName", notification.getSound()); diff --git a/index.js b/index.js index e56716cbd..4aa8cf029 100644 --- a/index.js +++ b/index.js @@ -448,7 +448,6 @@ Notifications.getScheduledLocalNotifications = function(callback) { return ({ soundName: notif.soundName, repeatInterval: notif.repeatInterval, - remote: notif.remote, id: notif.userInfo?.id, date: new Date(notif.fireDate), number: notif?.applicationIconBadgeNumber, @@ -461,7 +460,6 @@ Notifications.getScheduledLocalNotifications = function(callback) { return ({ soundName: notif.soundName, repeatInterval: notif.repeatInterval, - remote: notif.remote, id: notif.id, date: new Date(notif.date), number: notif.number, From 1c7a1965799fce18668ae2f46fd215164b99c717 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Tue, 9 Jun 2020 10:08:57 +0300 Subject: [PATCH 054/179] "@react-native-community/push-notification-ios": "^1.2.2" --- example/ios/Podfile.lock | 4 ++-- example/package.json | 2 +- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 509394e20..b3adad45f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -292,7 +292,7 @@ PODS: - React-cxxreact (= 0.62.2) - React-jsi (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2) - - RNCPushNotificationIOS (1.2.1): + - RNCPushNotificationIOS (1.2.2): - React - Yoga (1.14.0) - YogaKit (1.18.1): @@ -453,7 +453,7 @@ SPEC CHECKSUMS: React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNCPushNotificationIOS: 5878fb73cb1a8a78c3a1a0834d969b01553836d0 + RNCPushNotificationIOS: 4c97a36dbec42dba411cc35e6dac25e34a805fde Yoga: 3ebccbdd559724312790e7742142d062476b698e YogaKit: f782866e155069a2cca2517aafea43200b01fd5a diff --git a/example/package.json b/example/package.json index 70f616c0b..606b5d146 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,7 @@ "pod-install": "cd ios && pod install" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.1.1", + "@react-native-community/push-notification-ios": "^1.2.2", "react": "16.11.0", "react-native": "0.62.2", "react-native-push-notification": "git+https://git@github.com/zo0r/react-native-push-notification.git" diff --git a/package.json b/package.json index 71e9dafe3..619625482 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.2.1" + "@react-native-community/push-notification-ios": "^1.2.2" }, "peerDependencies": { "react-native": ">=0.33" From 6bcc2a9785c4428979787db353777c17bab6737d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 9 Jun 2020 22:46:53 +0200 Subject: [PATCH 055/179] `userInfo` is now populated with id by default to allow operation based on `id` --- CHANGELOG.md | 2 ++ README.md | 43 ++++++++++----------------------- index.js | 67 +++++++++++++++++++++++++++++----------------------- 3 files changed, 53 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a36d1a42e..9d7581590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ```xml ``` +- (iOS) `userInfo` is now populated with id by default to allow operation based on `id`. ### Features @@ -34,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Add `groupSummary` to allow grouping notifications. Based on [#1253](https://github.com/zo0r/react-native-push-notification/pull/1253) - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) +- (Android/iOS) Add method getScheduledLocalNotifications()[#1466](https://github.com/zo0r/react-native-push-notification/pull/1466) ### Fixed diff --git a/README.md b/README.md index 978ac74a2..0e5e37208 100644 --- a/README.md +++ b/README.md @@ -413,10 +413,9 @@ If you want to use a different default channel for remote notification, refer to You can list available channels with: ```js -PushNotification.getChannels(function(channel_ids) { +PushNotification.getChannels(function (channel_ids) { console.log(channel_ids); // ['channel_id_1'] }); - ``` ### Channel exists @@ -424,10 +423,9 @@ PushNotification.getChannels(function(channel_ids) { You can check if a channel exists with: ```js -PushNotification.channelExists(function(exists) { +PushNotification.channelExists(function (exists) { console.log(exists); // true/false }); - ``` ### List channels @@ -436,19 +434,15 @@ You can list available channels with: ```js PushNotification.deleteChannel(channel_id); - ``` ## Cancelling notifications ### 1) cancelLocalNotifications -#### Android - The `id` parameter for `PushNotification.localNotification` is required for this operation. The id supplied will then be used for the cancel operation. ```javascript -// Android PushNotification.localNotification({ ... id: '123' @@ -457,19 +451,7 @@ PushNotification.localNotification({ PushNotification.cancelLocalNotifications({id: '123'}); ``` -#### IOS - -The `userInfo` parameter for `PushNotification.localNotification` is required for this operation and must contain an `id` parameter. The id supplied will then be used for the cancel operation. - -```javascript -// IOS -PushNotification.localNotification({ - ... - userInfo: { id: '123' } - ... -}); -PushNotification.cancelLocalNotifications({id: '123'}); -``` +**iOS: `userInfo` is populated `id` if not defined this allow the pervious method** ### 2) cancelAllLocalNotifications @@ -540,15 +522,15 @@ Provides you with a list of the app’s scheduled local notifications that are y Returns an array of local scheduled notification objects containing: -| Name | Type | Description | -| -------- | -------- | -------- | ----------------------------------------------------------- | -| id | number | The identifier of this notification. | -| date | Date | The fire date of this notification. | -| title | string | The title of this notification. | -| message | string | The message body of this notification. | -| soundName | string | The sound name of this notification. | +| Name | Type | Description | +| -------------- | ------ | ----------------------------------------- | +| id | number | The identifier of this notification. | +| date | Date | The fire date of this notification. | +| title | string | The title of this notification. | +| message | string | The message body of this notification. | +| soundName | string | The sound name of this notification. | | repeatInterval | number | The repeat interval of this notification. | -| number | number | App notification badge count number. | +| number | number | App notification badge count number. | ## Abandon Permissions @@ -621,9 +603,10 @@ This is done by specifying an `actions` parameters while configuring the local n For e.g. `actions: ['Accept', 'Reject']` -When you handle actions in background (`invokeApp: false`), you can open the application and pass the initial notification by using use `PushNotification.invokeApp(notification)`. +When you handle actions in background (`invokeApp: false`), you can open the application and pass the initial notification by using use `PushNotification.invokeApp(notification)`. Make sure you have the receiver in `AndroidManifest.xml`: + ```xml ``` diff --git a/index.js b/index.js index 4aa8cf029..37c51d1ef 100644 --- a/index.js +++ b/index.js @@ -139,7 +139,17 @@ Notifications.unregister = function() { * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert. */ Notifications.localNotification = function(details) { - if ( Platform.OS === 'ios' ) { + if (details && typeof details.id === 'number') { + if (isNaN(details.id)) { + console.warn('NaN value has been passed as id'); + delete details.id; + } + else { + details.id = '' + details.id; + } + } + + if (Platform.OS === 'ios') { // https://developer.apple.com/reference/uikit/uilocalnotification let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour @@ -148,6 +158,10 @@ Notifications.localNotification = function(details) { soundName = ''; // empty string results in no sound (and no vibration) } + if (details.userInfo) { + details.userInfo.id = details.userInfo.id || details.id; + } + // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle @@ -161,17 +175,7 @@ Notifications.localNotification = function(details) { userInfo: details.userInfo }); } else { - if(details && typeof details.id === 'number') { - if(isNaN(details.id)) { - console.warn('NaN value has been passed as id'); - delete details.id; - } - else { - details.id = '' + details.id; - } - } - - if(details && typeof details.number === 'number') { + if (details && typeof details.number === 'number') { if(isNaN(details.number)) { console.warn('NaN value has been passed as number'); delete details.number; @@ -181,7 +185,7 @@ Notifications.localNotification = function(details) { } } - if(details && typeof details.shortcutId === 'number') { + if (details && typeof details.shortcutId === 'number') { if(isNaN(details.shortcutId)) { console.warn('NaN value has been passed as shortcutId'); delete details.shortcutId; @@ -205,13 +209,27 @@ Notifications.localNotification = function(details) { * @param {Date} details.date - The date and time when the system should deliver the notification */ Notifications.localNotificationSchedule = function(details) { - if ( Platform.OS === 'ios' ) { + if (details && typeof details.id === 'number') { + if(isNaN(details.id)) { + console.warn('NaN value has been passed as id'); + delete details.id; + } + else { + details.id = '' + details.id; + } + } + + if (Platform.OS === 'ios') { let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour if (details.hasOwnProperty('playSound') && !details.playSound) { soundName = ''; // empty string results in no sound (and no vibration) } + if (details.userInfo) { + details.userInfo.id = details.userInfo.id || details.id; + } + const iosDetails = { fireDate: details.date.toISOString(), alertTitle: details.title, @@ -223,7 +241,7 @@ Notifications.localNotificationSchedule = function(details) { category: details.category, }; - if(details.number) { + if (details.number) { iosDetails.applicationIconBadgeNumber = parseInt(details.number, 10); } @@ -233,18 +251,8 @@ Notifications.localNotificationSchedule = function(details) { } this.handler.scheduleLocalNotification(iosDetails); } else { - if(details && typeof details.id === 'number') { - if(isNaN(details.id)) { - console.warn('NaN value has been passed as id'); - delete details.id; - } - else { - details.id = '' + details.id; - } - } - - if(details && typeof details.number === 'number') { - if(isNaN(details.number)) { + if (details && typeof details.number === 'number') { + if (isNaN(details.number)) { console.warn('NaN value has been passed as number'); delete details.number; } @@ -253,8 +261,8 @@ Notifications.localNotificationSchedule = function(details) { } } - if(details && typeof details.shortcutId === 'number') { - if(isNaN(details.shortcutId)) { + if (details && typeof details.shortcutId === 'number') { + if (isNaN(details.shortcutId)) { console.warn('NaN value has been passed as shortcutId'); delete details.shortcutId; } @@ -316,6 +324,7 @@ Notifications._onNotification = function(data, isFromBackground = null) { if ( this.onNotification !== false ) { if ( Platform.OS === 'ios' ) { this.onNotification({ + id: notif.userInfo?.id, foreground: ! isFromBackground, userInteraction: isFromBackground, message: data.getMessage(), From 5994754185ddcab2ea1a2532b378934713c85591 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas <46403446+lukebars@users.noreply.github.com> Date: Wed, 10 Jun 2020 12:36:42 +0300 Subject: [PATCH 056/179] Add notification id to iOS if userInfo doesn't exist --- index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.js b/index.js index 37c51d1ef..6f17de212 100644 --- a/index.js +++ b/index.js @@ -160,6 +160,8 @@ Notifications.localNotification = function(details) { if (details.userInfo) { details.userInfo.id = details.userInfo.id || details.id; + } else { + details.userInfo = {id: details.id}; } // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html @@ -228,6 +230,8 @@ Notifications.localNotificationSchedule = function(details) { if (details.userInfo) { details.userInfo.id = details.userInfo.id || details.id; + } else { + details.userInfo = {id: details.id}; } const iosDetails = { From c90fc6eb576ff64e128c31f839914772215b873d Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas <46403446+lukebars@users.noreply.github.com> Date: Wed, 10 Jun 2020 14:26:35 +0300 Subject: [PATCH 057/179] return a Promise in getScheduledLocalNotifications --- index.js | 74 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/index.js b/index.js index 6f17de212..e71873e7e 100644 --- a/index.js +++ b/index.js @@ -452,40 +452,46 @@ Notifications.getDeliveredNotifications = function() { return this.callNative('getDeliveredNotifications', arguments); } -Notifications.getScheduledLocalNotifications = function(callback) { - const mapNotifications = (notifications) => { - let mappedNotifications = []; - if(notifications?.length > 0) { - if(Platform.OS === 'ios'){ - mappedNotifications = notifications.map(notif => { - return ({ - soundName: notif.soundName, - repeatInterval: notif.repeatInterval, - id: notif.userInfo?.id, - date: new Date(notif.fireDate), - number: notif?.applicationIconBadgeNumber, - message: notif?.alertBody, - title: notif?.alertTitle, - }) - }) - } else if(Platform.OS === 'android') { - mappedNotifications = notifications.map(notif => { - return ({ - soundName: notif.soundName, - repeatInterval: notif.repeatInterval, - id: notif.id, - date: new Date(notif.date), - number: notif.number, - message: notif.message, - title: notif.title, - }) - }) - } - } - callback(mappedNotifications); - } - - return this.callNative('getScheduledLocalNotifications', [mapNotifications]); +Notifications.getScheduledLocalNotifications = function() { + return new Promise((resolve, reject) => { + const mapNotifications = (notifications) => { + let mappedNotifications = []; + if(notifications?.length > 0) { + if(Platform.OS === 'ios'){ + mappedNotifications = notifications.map(notif => { + console.tron.log(notif); + return ({ + soundName: notif.soundName, + repeatInterval: notif.repeatInterval, + id: notif.userInfo?.id, + date: new Date(notif.fireDate), + number: notif?.applicationIconBadgeNumber, + message: notif?.alertBody, + title: notif?.alertTitle, + }) + }) + } else if(Platform.OS === 'android') { + mappedNotifications = notifications.map(notif => { + return ({ + soundName: notif.soundName, + repeatInterval: notif.repeatInterval, + id: notif.id, + date: new Date(notif.date), + number: notif.number, + message: notif.message, + title: notif.title, + }) + }) + } + } + resolve(mappedNotifications); + } + try{ + this.callNative('getScheduledLocalNotifications', [mapNotifications]); + } catch(e) { + reject(e); + } + }) } Notifications.removeDeliveredNotifications = function() { From a5cdcdae33a5f6717f4f1b2ca5a37e35f29f968f Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 10 Jun 2020 14:30:34 +0300 Subject: [PATCH 058/179] updated example/App.js --- example/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/App.js b/example/App.js index a4c8458b0..d6bebc85c 100644 --- a/example/App.js +++ b/example/App.js @@ -108,7 +108,7 @@ export default class App extends Component { { - this.notif.getScheduledLocalNotifications(notifs => console.log(notifs)); + this.notif.getScheduledLocalNotifications().then(notifs => console.log(notifs)); }}> Console.Log Scheduled Local Notifications From cf278977de70e790285db5f8320501fcb0e5924f Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 10 Jun 2020 22:22:07 +0200 Subject: [PATCH 059/179] Fix typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e5e37208..4f272c872 100644 --- a/README.md +++ b/README.md @@ -451,7 +451,7 @@ PushNotification.localNotification({ PushNotification.cancelLocalNotifications({id: '123'}); ``` -**iOS: `userInfo` is populated `id` if not defined this allow the pervious method** +**iOS: `userInfo` is populated `id` if not defined this allow the previous method** ### 2) cancelAllLocalNotifications From afb5e7196fe5eb22fcd8197cb6fc81d0f7d0624c Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 15 Jun 2020 10:23:14 +0200 Subject: [PATCH 060/179] Fix notif reference undefined. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6f17de212..183a421f9 100644 --- a/index.js +++ b/index.js @@ -328,7 +328,7 @@ Notifications._onNotification = function(data, isFromBackground = null) { if ( this.onNotification !== false ) { if ( Platform.OS === 'ios' ) { this.onNotification({ - id: notif.userInfo?.id, + id: data?.userInfo?.id, foreground: ! isFromBackground, userInteraction: isFromBackground, message: data.getMessage(), From 174ea3cdbed207b00e8a06a43283a38070e77db3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 28 Jun 2020 18:40:34 +0200 Subject: [PATCH 061/179] Allow override the channel name and description in App. Add the detection of blocked channels. --- CHANGELOG.md | 3 ++ README.md | 13 ++++++- .../modules/RNPushNotification.java | 12 ++++++ .../modules/RNPushNotificationAttributes.java | 14 +++++++ .../modules/RNPushNotificationHelper.java | 39 ++++++++++++++++--- component/index.android.js | 4 ++ example/NotifService.js | 6 +-- .../org.eclipse.buildship.core.prefs | 2 +- .../org.eclipse.buildship.core.prefs | 2 +- index.js | 4 ++ 10 files changed, 88 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d7581590..6afe7dd16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) `PushNotification.invokeApp(notification)` allow you to invoke the application when in background (notification for initial notification). - (Android) `PushNotification.getChannels(callback)` allow you to get the list of channels. - (Android) `PushNotification.channelExists(channel_id, callback)` allow you to check of a channel exists. +- (Android) `PushNotification.channelBlocked(channel_id, callback)` allow you to check of a channel is blocked. Based on [#1249](https://github.com/zo0r/react-native-push-notification/pull/1249) - (Android) `PushNotification.deleteChannel(channel_id)` allow you to delete a channel. - (Android) Add `largeIconUrl` to load a largeIcon based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) - (Android) Add `bigPictureUrl` to load a picture based on Url. Based on [#1444](https://github.com/zo0r/react-native-push-notification/pull/1444) @@ -34,6 +35,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Add `showWhen` to display "when" it was published, default: true. - (Android) Add `groupSummary` to allow grouping notifications. Based on [#1253](https://github.com/zo0r/react-native-push-notification/pull/1253) - (Android) Add `channelId`, custom channel_id in android. Based on [#1159](https://github.com/zo0r/react-native-push-notification/pull/1159) +- (Android) Add `channelName`, custom channel_name in android. +- (Android) Add `channelDescription`, custom channel_description in android. - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) - (Android/iOS) Add method getScheduledLocalNotifications()[#1466](https://github.com/zo0r/react-native-push-notification/pull/1466) diff --git a/README.md b/README.md index 4f272c872..77e3cb716 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,7 @@ you can avoid the default creation by using this: In the notifications options, you can provide a custom channel id with `channelId: "your-custom-channel-id"`, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your `channelId` is different if you change these options. If you have created a custom channel in another way, it will apply options of the channel. Custom and generated channels can have custom name and description in the `AndroidManifest.xml`, only if the library is responsible of the creation of the channel. +You can also use `channelName` and `channelDescription` when you use to override the name or description. Once the channel is created, you won't be able to update them. ```xml listChannels() { @@ -852,6 +856,23 @@ public List listChannels() { return channels; } + public boolean channelBlocked(String channel_id) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return false; + + NotificationManager manager = notificationManager(); + + if (manager == null) + return false; + + NotificationChannel channel = manager.getNotificationChannel(channel_id); + + if(channel == null) + return false; + + return NotificationManager.IMPORTANCE_NONE == channel.getImportance(); + } + public boolean channelExists(String channel_id) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false; @@ -878,7 +899,7 @@ public void deleteChannel(String channel_id) { manager.deleteNotificationChannel(channel_id); } - private void checkOrCreateChannel(NotificationManager manager, String channel_id, Uri soundUri, int importance, long[] vibratePattern) { + private void checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return; if (manager == null) @@ -887,9 +908,17 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id NotificationChannel channel = manager.getNotificationChannel(channel_id); if (channel == null) { - channel = new NotificationChannel(channel_id, this.config.getChannelName(channel_id), importance); + if(channel_name == null) { + channel_name = this.config.getChannelName(channel_id); + } + + if(channel_description == null) { + channel_description = this.config.getChannelDescription(channel_id); + } + + channel = new NotificationChannel(channel_id, channel_name, importance); - channel.setDescription(this.config.getChannelDescription(channel_id)); + channel.setDescription(channel_description); channel.enableLights(true); channel.enableVibration(true); channel.setVibrationPattern(vibratePattern); diff --git a/component/index.android.js b/component/index.android.js index 6e16f50d3..b67d44cf4 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -154,6 +154,10 @@ NotificationsComponent.prototype.channelExists = function(channel_id, callback) RNPushNotification.channelExists(channel_id, callback); } +NotificationsComponent.prototype.channelBlocked = function(channel_id, callback) { + RNPushNotification.channelBlocked(channel_id, callback); +} + NotificationsComponent.prototype.deleteChannel = function(channel_id) { RNPushNotification.deleteChannel(channel_id); } diff --git a/example/NotifService.js b/example/NotifService.js index ab9bac75d..66c32b67e 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -14,7 +14,7 @@ export default class NotifService { PushNotification.setApplicationIconBadgeNumber(0); } }); - + PushNotification.getChannels(function(channels) { console.log(channels); }); @@ -37,7 +37,7 @@ export default class NotifService { tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message ongoing: false, // (optional) set whether this is an "ongoing" notification - actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more + actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ @@ -73,7 +73,7 @@ export default class NotifService { tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message ongoing: false, // (optional) set whether this is an "ongoing" notification - actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more + actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: false, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ diff --git a/example/android/.settings/org.eclipse.buildship.core.prefs b/example/android/.settings/org.eclipse.buildship.core.prefs index b9ef928ba..342e81ef5 100644 --- a/example/android/.settings/org.eclipse.buildship.core.prefs +++ b/example/android/.settings/org.eclipse.buildship.core.prefs @@ -2,7 +2,7 @@ arguments= auto.sync=false build.scans.enabled=false connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) -connection.project.dir=app +connection.project.dir= eclipse.preferences.version=1 gradle.user.home= java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs index c25633f0a..b3d49cd88 100644 --- a/example/android/app/.settings/org.eclipse.buildship.core.prefs +++ b/example/android/app/.settings/org.eclipse.buildship.core.prefs @@ -2,7 +2,7 @@ arguments= auto.sync=false build.scans.enabled=false connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3)) -connection.project.dir= +connection.project.dir=.. eclipse.preferences.version=1 gradle.user.home= java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home diff --git a/index.js b/index.js index 183a421f9..16000b1d0 100644 --- a/index.js +++ b/index.js @@ -504,6 +504,10 @@ Notifications.channelExists = function() { return this.callNative('channelExists', arguments); }; +Notifications.channelBlocked = function() { + return this.callNative('channelBlocked', arguments); +}; + Notifications.deleteChannel = function() { return this.callNative('deleteChannel', arguments); }; From 140273d3c7178aeec377bde67dd51bbfcca0fb9c Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 28 Jun 2020 18:56:36 +0200 Subject: [PATCH 062/179] Add `onRegistrationError`. --- CHANGELOG.md | 1 + README.md | 5 +++++ example/NotificationHandler.js | 8 ++++++++ example/ios/Podfile.lock | 2 +- index.js | 19 ++++++++++++++----- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6afe7dd16..7a2501269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - (Android) Add `channelName`, custom channel_name in android. - (Android) Add `channelDescription`, custom channel_description in android. - (iOS) Add fire date in notification response, NOTE: `push-notification-ios` in version `> 1.2.0` [#1345](https://github.com/zo0r/react-native-push-notification/pull/1345) +- (iOS) `onRegistrationError` has been added to `.configure()` to handle `registrationError` events. - (Android/iOS) Add method getScheduledLocalNotifications()[#1466](https://github.com/zo0r/react-native-push-notification/pull/1466) ### Fixed diff --git a/README.md b/README.md index 77e3cb716..944ecda6c 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,11 @@ PushNotification.configure({ // process the action }, + // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS) + onRegistrationError: function(err) { + console.error(err.message, err); + } + // IOS ONLY (optional): default: all - Permissions to register. permissions: { alert: true, diff --git a/example/NotificationHandler.js b/example/NotificationHandler.js index df2d6d9b4..040d3c0cf 100644 --- a/example/NotificationHandler.js +++ b/example/NotificationHandler.js @@ -27,6 +27,11 @@ class NotificationHandler { } } + // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS) + onRegistrationError(err) { + console.log(err); + } + attachRegister(handler) { this._onRegister = handler; } @@ -48,6 +53,9 @@ PushNotification.configure({ // (optional) Called when Action is pressed (Android) onAction: handler.onAction.bind(handler), + // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS) + onRegistrationError: handler.onRegistrationError.bind(handler), + // IOS ONLY (optional): default: all - Permissions to register. permissions: { alert: true, diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b3adad45f..3ebf68810 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -459,4 +459,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 56c2537f71f3f02200d6918c542a8e89a0b422fa -COCOAPODS: 1.9.2 +COCOAPODS: 1.9.1 diff --git a/index.js b/index.js index 16000b1d0..e71db401f 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ let Platform = require('react-native').Platform; var Notifications = { handler: RNNotifications, onRegister: false, - onError: false, + onRegistrationError: false, onNotification: false, onAction: false, onRemoteFetch: false, @@ -50,17 +50,17 @@ Notifications.callNative = function(name, params) { * @param {function} options.onRegister - Fired when the user registers for remote notifications. * @param {function} options.onNotification - Fired when a remote notification is received. * @param {function} options.onAction - Fired when a remote notification is received. - * @param {function} options.onError - None + * @param {function} options.onRegistrationError - Fired when the user fails to register for remote notifications. * @param {Object} options.permissions - Permissions list - * @param {Boolean} options.requestPermissions - Check permissions when register + * @param {Boolean} options.requestPermissions - Check permissions when register */ Notifications.configure = function(options) { if ( typeof options.onRegister !== 'undefined' ) { this.onRegister = options.onRegister; } - if ( typeof options.onError !== 'undefined' ) { - this.onError = options.onError; + if ( typeof options.onRegistrationError !== 'undefined' ) { + this.onRegistrationError = options.onRegistrationError; } if ( typeof options.onNotification !== 'undefined' ) { @@ -81,10 +81,12 @@ Notifications.configure = function(options) { if ( this.isLoaded === false ) { this._onRegister = this._onRegister.bind(this); + this._onRegistrationError = this._onRegistrationError.bind(this); this._onNotification = this._onNotification.bind(this); this._onRemoteFetch = this._onRemoteFetch.bind(this); this._onAction = this._onAction.bind(this); this.callNative( 'addEventListener', [ 'register', this._onRegister ] ); + this.callNative( 'addEventListener', [ 'registrationError', this._onRegistrationError ] ); this.callNative( 'addEventListener', [ 'notification', this._onNotification ] ); this.callNative( 'addEventListener', [ 'localNotification', this._onNotification ] ); Platform.OS === 'android' ? this.callNative( 'addEventListener', [ 'action', this._onAction ] ) : null @@ -123,6 +125,7 @@ Notifications.configure = function(options) { /* Unregister */ Notifications.unregister = function() { this.callNative( 'removeEventListener', [ 'register', this._onRegister ] ) + this.callNative( 'removeEventListener', [ 'registrationError', this._onRegistrationError ] ) this.callNative( 'removeEventListener', [ 'notification', this._onNotification ] ) this.callNative( 'removeEventListener', [ 'localNotification', this._onNotification ] ) Platform.OS === 'android' ? this.callNative( 'removeEventListener', [ 'action', this._onAction ] ) : null @@ -299,6 +302,12 @@ Notifications._onRegister = function(token) { } }; +Notifications._onRegistrationError = function(err) { + if ( this.onRegistrationError !== false ) { + this.onRegistrationError(err); + } +}; + Notifications._onRemoteFetch = function(notificationData) { if ( this.onRemoteFetch !== false ) { this.onRemoteFetch(notificationData) From 0bfc74b0ccea13e195bc15012ad1ffc528a1a4b3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 30 Jun 2020 21:45:22 +0200 Subject: [PATCH 063/179] Remove WAKE_LOCK from documentation. #1494 --- CHANGELOG.md | 1 + README.md | 2 -- example/android/app/src/main/AndroidManifest.xml | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2501269..4bc171cb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- (Android) WAKE_LOCK permission removed from documentation. [#1494](https://github.com/zo0r/react-native-push-notification/issues/1494) - (Android) Some options were ignored on scheduled/repeating notifications (allowWhileIdle, ignoreInForeground). - (Android/iOS) popInitialInotification might be ignored in `.configure()` diff --git a/README.md b/README.md index 944ecda6c..7ae31e318 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,6 @@ In your `android/app/src/main/AndroidManifest.xml` ```xml ..... - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index ca312e8f9..47fdd7631 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -7,8 +7,6 @@ - - Date: Wed, 1 Jul 2020 10:15:07 +0200 Subject: [PATCH 064/179] replaced java.util.Random with java.security.SecureRandom in RNPushNotification.java --- .../modules/RNPushNotification.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 4ceb65d5c..79df4f649 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -26,9 +26,9 @@ import com.facebook.react.bridge.WritableMap; import java.io.IOException; +import java.security.SecureRandom; import java.util.HashMap; import java.util.Map; -import java.util.Random; import android.util.Log; @@ -42,7 +42,7 @@ public class RNPushNotification extends ReactContextBaseJavaModule implements Ac public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag private RNPushNotificationHelper mRNPushNotificationHelper; - private final Random mRandomNumberGenerator = new Random(System.currentTimeMillis()); + private final SecureRandom mRandomNumberGenerator = new SecureRandom(); private RNPushNotificationJsDelivery mJsDelivery; public RNPushNotification(ReactApplicationContext reactContext) { @@ -60,6 +60,8 @@ public RNPushNotification(ReactApplicationContext reactContext) { mRNPushNotificationHelper.checkOrCreateDefaultChannel(); } + + @Override public String getName() { return "RNPushNotification"; From 9aa88d68fcd5bb0421e9b08a1d05b42887903a93 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 1 Jul 2020 18:28:16 +0200 Subject: [PATCH 065/179] Create FUNDING.yml --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..29e999ea9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [Dallas62] +custom: [https://www.buymeacoffee.com/Dallas62] From da34ac1f8d31e1bbf757255f941b70854c4a2d40 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 1 Jul 2020 18:29:25 +0200 Subject: [PATCH 066/179] Fix custom link --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 29e999ea9..105898580 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,2 @@ github: [Dallas62] -custom: [https://www.buymeacoffee.com/Dallas62] +custom: ["https://www.buymeacoffee.com/Dallas62"] From f8b57103dd6aee042428347c6a926ade67030cfe Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 2 Jul 2020 22:03:39 +0200 Subject: [PATCH 067/179] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc171cb0..d9af1c98d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- (Android) Replace java.util.Random with java.security.SecureRandom [#1497](https://github.com/zo0r/react-native-push-notification/pull/1497) - (Android) WAKE_LOCK permission removed from documentation. [#1494](https://github.com/zo0r/react-native-push-notification/issues/1494) - (Android) Some options were ignored on scheduled/repeating notifications (allowWhileIdle, ignoreInForeground). - (Android/iOS) popInitialInotification might be ignored in `.configure()` From 08c996fe725a758779924d87311ebd6b0b612354 Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Mon, 6 Jul 2020 13:20:51 +0800 Subject: [PATCH 068/179] Add createChannel helper and @ReactMethod for pre-creating custom Android channels --- .../modules/RNPushNotification.java | 12 +++ .../modules/RNPushNotificationHelper.java | 74 ++++++++++++------- component/index.android.js | 4 + index.js | 4 + 4 files changed, 69 insertions(+), 25 deletions(-) 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 c268cd452..e64835ad4 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -297,6 +297,18 @@ public void channelExists(String channel_id, Callback callback) { } } + @ReactMethod + /** + * Creates a channel if it does not already exist. Returns whether the channel was created. + */ + public void createChannel(ReadableMap channelInfo, Callback callback) { + boolean created = mRNPushNotificationHelper.createChannel(channelInfo); + + if(callback != null) { + callback.invoke(created); + } + } + @ReactMethod /** * Check if channel is blocked with a given id diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..540c2ade2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -428,31 +428,13 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Uri soundUri = null; if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { - soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - String soundName = bundle.getString("soundName"); - - if (soundName != null) { - if (!"default".equalsIgnoreCase(soundName)) { - - // sound name can be full filename, or just the resource name. - // So the strings 'my_sound.mp3' AND 'my_sound' are accepted - // The reason is to make the iOS and android javascript interfaces compatible - - int resId; - if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) { - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } else { - soundName = soundName.substring(0, soundName.lastIndexOf('.')); - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } - - soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); - } - } else { + if (soundName == null) { soundName = "default"; } + soundUri = getSoundUri(soundName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher channel_id = channel_id + "-" + soundName; } @@ -676,6 +658,27 @@ private void scheduleNextNotificationIfRepeating(Bundle bundle) { } } + private Uri getSoundUri(String soundName) { + if (soundName == null || "default".equalsIgnoreCase(soundName)) { + return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + } else { + + // sound name can be full filename, or just the resource name. + // So the strings 'my_sound.mp3' AND 'my_sound' are accepted + // The reason is to make the iOS and android javascript interfaces compatible + + int resId; + if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) { + resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); + } else { + soundName = soundName.substring(0, soundName.lastIndexOf('.')); + resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); + } + + return Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); + } + } + public void clearNotifications() { Log.i(LOG_TAG, "Clearing alerts from the notification centre"); @@ -899,11 +902,11 @@ public void deleteChannel(String channel_id) { manager.deleteNotificationChannel(channel_id); } - private void checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) { + private boolean checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) - return; + return false; if (manager == null) - return; + return false; NotificationChannel channel = manager.getNotificationChannel(channel_id); @@ -920,7 +923,7 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id channel.setDescription(channel_description); channel.enableLights(true); - channel.enableVibration(true); + channel.enableVibration(vibratePattern != null); channel.setVibrationPattern(vibratePattern); if (soundUri != null) { @@ -935,7 +938,28 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id } manager.createNotificationChannel(channel); + return true; } + return false; + } + + public boolean createChannel(ReadableMap channelInfo) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return false; + + String channelId = channelInfo.getString("channelId"); + String channelName = channelInfo.getString("channelName"); + String channelDesc = channelInfo.hasKey("channelDesc") ? channelInfo.getString("channelDesc") : null; + String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; + int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; + boolean vibrate = channelInfo.hasKey("importance") && channelInfo.getBoolean("vibrate"); + long[] vibratePattern = vibrate ? new long[] { DEFAULT_VIBRATION } : null; + + NotificationManager manager = notificationManager(); + + Uri soundUri = getSoundUri(soundName); + + return checkOrCreateChannel(manager, channelId, channelName, channelDesc, soundUri, importance, vibratePattern); } public boolean isApplicationInForeground(Context context) { diff --git a/component/index.android.js b/component/index.android.js index b67d44cf4..819acab9b 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -154,6 +154,10 @@ NotificationsComponent.prototype.channelExists = function(channel_id, callback) RNPushNotification.channelExists(channel_id, callback); } +NotificationsComponent.prototype.createChannel = function(channelInfo, callback) { + RNPushNotification.createChannel(channelInfo, callback); +} + NotificationsComponent.prototype.channelBlocked = function(channel_id, callback) { RNPushNotification.channelBlocked(channel_id, callback); } diff --git a/index.js b/index.js index e71db401f..b1186f02e 100644 --- a/index.js +++ b/index.js @@ -513,6 +513,10 @@ Notifications.channelExists = function() { return this.callNative('channelExists', arguments); }; +Notifications.createChannel = function() { + return this.callNative('createChannel', arguments); +}; + Notifications.channelBlocked = function() { return this.callNative('channelBlocked', arguments); }; From a4f93c69ed33272e3114ec5f358e404152900fb4 Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Mon, 6 Jul 2020 17:11:20 +0800 Subject: [PATCH 069/179] Add message_id to intent extras for local notification integration with react-native-firebase/messaging onNotificationOpenedApp --- .../modules/RNPushNotificationHelper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..94b7d09fc 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -425,6 +425,12 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB bundle.putBoolean("userInteraction", true); intent.putExtra("notification", bundle); + // Add message_id to intent so react-native-firebase/messaging can identify it + String messageId = bundle.getString("messageId"); + if (messageId != null) { + intent.putExtra("message_id", messageId); + } + Uri soundUri = null; if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { @@ -557,6 +563,9 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB bundle.putString("action", action); actionIntent.putExtra("notification", bundle); actionIntent.setPackage(packageName); + if (messageId != null) { + intent.putExtra("message_id", messageId); + } PendingIntent pendingActionIntent = PendingIntent.getBroadcast(context, notificationID, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT); From ad5f98e7a8781d3589d828bec54c637b66827bee Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Mon, 6 Jul 2020 17:13:01 +0800 Subject: [PATCH 070/179] Support empty strings for Android icons to match default background firebase push notifications --- .../modules/RNPushNotificationHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..ca879e89e 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -348,13 +348,13 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB } // Small icon - int smallIconResId; + int smallIconResId = 0; String smallIcon = bundle.getString("smallIcon"); if (smallIcon != null) { smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); - } else { + } else if (!smallIcon.isEmpty()) { smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); } @@ -370,13 +370,13 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB // Large icon if(largeIconBitmap == null) { - int largeIconResId; + int largeIconResId = 0; String largeIcon = bundle.getString("largeIcon"); if (largeIcon != null) { largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); - } else { + } else if (!largeIcon.isEmpty()) { largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); } From f19d05d827b22645f90be1ce160a7a8a93399199 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 6 Jul 2020 11:21:39 +0200 Subject: [PATCH 071/179] Use SecureRandom and remove `onNotification` call for Scheduled notifications when there is no user interation. --- CHANGELOG.md | 1 - .../modules/RNPushNotificationPublisher.java | 56 ++----------------- .../modules/RNReceivedMessageHandler.java | 4 +- 3 files changed, 6 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9af1c98d..3798f4c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Breaking changes -- Now local scheduled notifications trigger `onNotification` before display [#574](https://github.com/zo0r/react-native-push-notification/pull/574). - `RNPushNotificationRegistrationService` has been removed, old reference in AndroidManifest must be removed. - `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. - `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java index 481b8154e..cb3c6d33f 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java @@ -1,26 +1,14 @@ package com.dieam.reactnativepushnotification.modules; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.util.Log; -import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; - -import org.json.JSONObject; - import java.util.List; -import java.util.Random; +import java.security.SecureRandom; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; @@ -38,40 +26,14 @@ public void onReceive(final Context context, Intent intent) { Log.v(LOG_TAG, "onMessageReceived: " + bundle); - // We need to run this on the main thread, as the React code assumes that is true. - // Namely, DevServerHelper constructs a Handler() without a Looper, which triggers: - // "Can't create handler inside thread that has not called Looper.prepare()" - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - public void run() { - // Construct and load our normal React JS code bundle - final ReactInstanceManager mReactInstanceManager = ((ReactApplication) context.getApplicationContext()).getReactNativeHost().getReactInstanceManager(); - ReactContext context = mReactInstanceManager.getCurrentReactContext(); - // If it's constructed, send a notification - if (context != null) { - handleLocalNotification((ReactApplicationContext) context, bundle); - } else { - // Otherwise wait for construction, then send the notification - mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() { - public void onReactContextInitialized(ReactContext context) { - handleLocalNotification((ReactApplicationContext) context, bundle); - mReactInstanceManager.removeReactInstanceEventListener(this); - } - }); - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - // Construct it in the background - mReactInstanceManager.createReactContextInBackground(); - } - } - } - }); + handleLocalNotification(context, bundle); } - private void handleLocalNotification(ReactApplicationContext context, Bundle bundle) { + private void handleLocalNotification(Context context, Bundle bundle) { // If notification ID is not provided by the user for push notification, generate one at random if (bundle.getString("id") == null) { - Random randomNumberGenerator = new Random(System.currentTimeMillis()); + SecureRandom randomNumberGenerator = new SecureRandom(); bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); } @@ -80,16 +42,6 @@ private void handleLocalNotification(ReactApplicationContext context, Bundle bun boolean isForeground = pushNotificationHelper.isApplicationInForeground(applicationContext); - RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); - bundle.putBoolean("foreground", isForeground); - bundle.putBoolean("userInteraction", false); - jsDelivery.notifyNotification(bundle); - - // If contentAvailable is set to true, then send out a remote fetch event - if (bundle.getString("contentAvailable", "false").equalsIgnoreCase("true")) { - jsDelivery.notifyRemoteFetch(bundle); - } - Log.v(LOG_TAG, "sendNotification: " + bundle); pushNotificationHelper.sendToNotificationCentre(bundle); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 05be185b5..13402c1c5 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -22,7 +22,7 @@ import java.util.Map; import java.util.List; -import java.util.Random; +import java.security.SecureRandom; import static android.content.Context.ACTIVITY_SERVICE; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; @@ -125,7 +125,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl // If notification ID is not provided by the user for push notification, generate one at random if (bundle.getString("id") == null) { - Random randomNumberGenerator = new Random(System.currentTimeMillis()); + SecureRandom randomNumberGenerator = new SecureRandom(); bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); } From faf24405207d80abf505060c591adc3be09bc91d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 6 Jul 2020 11:28:27 +0200 Subject: [PATCH 072/179] Release v4.0.0. --- CHANGELOG.md | 9 +++++++++ README.md | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3798f4c3e..2a267b11e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Breaking changes +### Features + +### Fixed + + +## [4.4.0] 2020-07-06 + +### Breaking changes + - `RNPushNotificationRegistrationService` has been removed, old reference in AndroidManifest must be removed. - `Notifications.registerNotificationActions()` has been removed and is not required for `actions`. - `DeviceEventEmitter.addListener('notificationActionReceived', callback)` is replaced by `onAction`. diff --git a/README.md b/README.md index 7ae31e318..0857abf0b 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,14 @@ React Native Local and Remote Notifications for iOS and Android + +## 🎉 Version 4.0.0 is live ! 🎉 + +Check out for changes in the CHANGELOG: + +[Changelog](https://github.com/zo0r/react-native-push-notification/blob/master/CHANGELOG.md) + + ## Supported React Native Versions | Component Version | RN Versions | README | From 86af98dd2126f20cffeb8af5eb2c5a9cf9e47074 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 6 Jul 2020 11:32:17 +0200 Subject: [PATCH 073/179] Bump package.json to 4.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 619625482..1a35e0136 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "3.5.2", + "version": "4.0.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 2816253ba64a97a30378afb89c477f4cface6990 Mon Sep 17 00:00:00 2001 From: Brian Rubio Date: Mon, 6 Jul 2020 19:21:09 -0500 Subject: [PATCH 074/179] Update CHANGELOG.md Fixed version from 4.4.0 to 4.0.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a267b11e..394d594df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed -## [4.4.0] 2020-07-06 +## [4.0.0] 2020-07-06 ### Breaking changes From a5d564ecda4c6c3f8f34643a301a9a7a391764ff Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Tue, 7 Jul 2020 16:13:01 +0800 Subject: [PATCH 075/179] Fix code getting `createChannel` `vibrate` parameter --- .../modules/RNPushNotificationHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 540c2ade2..43dade5dd 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -952,7 +952,7 @@ public boolean createChannel(ReadableMap channelInfo) { String channelDesc = channelInfo.hasKey("channelDesc") ? channelInfo.getString("channelDesc") : null; String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; - boolean vibrate = channelInfo.hasKey("importance") && channelInfo.getBoolean("vibrate"); + boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); long[] vibratePattern = vibrate ? new long[] { DEFAULT_VIBRATION } : null; NotificationManager manager = notificationManager(); From 57ce9951915203aa3220d52a2145d8afbdb78d2b Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Tue, 7 Jul 2020 16:13:27 +0800 Subject: [PATCH 076/179] Update docs for `createChannel` --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ae31e318..e29c80349 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,23 @@ In the location notification json specify the full file name: ## Channel Management (Android) -This library doesn't include a full Channel Management at the moment. Channels are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. +To use custom channels, create them at startup and pass the matching `channelId` through to `PushNotification.localNotification` + +```javascript + PushNotification.createChannel( + { + channelId: "custom-channel-id", // (required) + channelName: "Custom channel", // (required) + channelDesc: "A custom channel to categorise your custom notifications", // (optional) default: undefined. + soundName: "default", // (optional) See `soundName` parameter of `localNotification` function + importance: 4, // (optional) default: 4. Int value of the Android notification importance + vibrate: true, // (optional) default: true. Creates the default vibration patten if true. + }, + (created: any) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + ); +``` + +Channels with ids that do not exist are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. The pattern of `channel_id` is: From f876f011b62a98bbde51bc7b452bfa3a55aea87d Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Tue, 7 Jul 2020 16:28:17 +0800 Subject: [PATCH 077/179] Add docs for `messageId` parameter --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7ae31e318..22af8f14d 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,7 @@ PushNotification.localNotification({ ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. + messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module. actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true From ec05c04b4dea473b648c7f620605bcad2b929994 Mon Sep 17 00:00:00 2001 From: Aranda Morrison Date: Tue, 7 Jul 2020 16:42:19 +0800 Subject: [PATCH 078/179] Add docs for icon strings --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ae31e318..c7800f2a0 100644 --- a/README.md +++ b/README.md @@ -295,9 +295,9 @@ PushNotification.localNotification({ ticker: "My Notification Ticker", // (optional) showWhen: true, // (optional) default: true autoCancel: true, // (optional) default: true - largeIcon: "ic_launcher", // (optional) default: "ic_launcher" + largeIcon: "ic_launcher", // (optional) default: "ic_launcher". Use "" for no large icon. largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined - smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher" + smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher". Use "" for default small icon. bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop subText: "This is a subText", // (optional) default: none bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined From 74e9b8bf443f952d00604ce5153ac132d490b1a0 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas <46403446+lukebars@users.noreply.github.com> Date: Wed, 8 Jul 2020 17:12:14 +0300 Subject: [PATCH 079/179] add data to android notification when scheduling --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index e71db401f..3583018a0 100644 --- a/index.js +++ b/index.js @@ -190,6 +190,10 @@ Notifications.localNotification = function(details) { } } + if(!details.data && details.userInfo){ + details.data = details.userInfo; + } + if (details && typeof details.shortcutId === 'number') { if(isNaN(details.shortcutId)) { console.warn('NaN value has been passed as shortcutId'); @@ -277,6 +281,10 @@ Notifications.localNotificationSchedule = function(details) { details.shortcutId = '' + details.shortcutId; } } + + if(!details.data && details.userInfo){ + details.data = details.userInfo; + } if(details && Array.isArray(details.actions)) { details.actions = JSON.stringify(details.actions); From 454af8cbba7081029db192ad1c83725e5e4d3bdb Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 8 Jul 2020 17:21:39 +0300 Subject: [PATCH 080/179] "@react-native-community/push-notification-ios": "^1.3.0" --- example/ios/Podfile.lock | 6 +++--- example/package.json | 2 +- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b3adad45f..2f44b3dad 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -292,7 +292,7 @@ PODS: - React-cxxreact (= 0.62.2) - React-jsi (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2) - - RNCPushNotificationIOS (1.2.2): + - RNCPushNotificationIOS (1.3.0): - React - Yoga (1.14.0) - YogaKit (1.18.1): @@ -453,10 +453,10 @@ SPEC CHECKSUMS: React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNCPushNotificationIOS: 4c97a36dbec42dba411cc35e6dac25e34a805fde + RNCPushNotificationIOS: d5fd66aed4e03c6491ca0c6111a03d4f6455ff6c Yoga: 3ebccbdd559724312790e7742142d062476b698e YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 56c2537f71f3f02200d6918c542a8e89a0b422fa -COCOAPODS: 1.9.2 +COCOAPODS: 1.9.3 diff --git a/example/package.json b/example/package.json index 606b5d146..091ea7bee 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,7 @@ "pod-install": "cd ios && pod install" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.2.2", + "@react-native-community/push-notification-ios": "^1.3.0", "react": "16.11.0", "react-native": "0.62.2", "react-native-push-notification": "git+https://git@github.com/zo0r/react-native-push-notification.git" diff --git a/package.json b/package.json index 619625482..05b97a682 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.2.2" + "@react-native-community/push-notification-ios": "^1.3.0" }, "peerDependencies": { "react-native": ">=0.33" From 579ffb898acef1068306dadd1e17dfc84fcce197 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 8 Jul 2020 17:22:21 +0300 Subject: [PATCH 081/179] reflecting userInfo working on both platforms in documentation and example --- README.md | 2 +- example/NotifService.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0e5e37208..9735c4205 100644 --- a/README.md +++ b/README.md @@ -319,9 +319,9 @@ PushNotification.localNotification({ /* iOS only properties */ alertAction: "view", // (optional) default: view category: "", // (optional) default: empty string - userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) /* iOS and Android properties */ + userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) title: "My Notification Title", // (optional) message: "My Notification Message", // (required) playSound: false, // (optional) default: true diff --git a/example/NotifService.js b/example/NotifService.js index ab9bac75d..22b5f1c69 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -79,9 +79,9 @@ export default class NotifService { /* iOS only properties */ alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string - userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) - + /* iOS and Android properties */ + userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) title: 'Scheduled Notification', // (optional) message: 'My Notification Message', // (required) playSound: !!soundName, // (optional) default: true From 3e191058cfedd0ed694203602abed0b36842e325 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 8 Jul 2020 17:25:34 +0300 Subject: [PATCH 082/179] revert changes --- example/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/App.js b/example/App.js index d6bebc85c..a4c8458b0 100644 --- a/example/App.js +++ b/example/App.js @@ -108,7 +108,7 @@ export default class App extends Component { { - this.notif.getScheduledLocalNotifications().then(notifs => console.log(notifs)); + this.notif.getScheduledLocalNotifications(notifs => console.log(notifs)); }}> Console.Log Scheduled Local Notifications From 85952df014650b79d6aecc69b6f0b479d15a30d3 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 8 Jul 2020 17:31:34 +0300 Subject: [PATCH 083/179] populate userInfo with id on both platforms --- index.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 3583018a0..bf8159c01 100644 --- a/index.js +++ b/index.js @@ -152,6 +152,12 @@ Notifications.localNotification = function(details) { } } + if (details.userInfo) { + details.userInfo.id = details.userInfo.id || details.id; + } else { + details.userInfo = {id: details.id}; + } + if (Platform.OS === 'ios') { // https://developer.apple.com/reference/uikit/uilocalnotification @@ -161,12 +167,6 @@ Notifications.localNotification = function(details) { soundName = ''; // empty string results in no sound (and no vibration) } - if (details.userInfo) { - details.userInfo.id = details.userInfo.id || details.id; - } else { - details.userInfo = {id: details.id}; - } - // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle @@ -228,6 +228,12 @@ Notifications.localNotificationSchedule = function(details) { } } + if (details.userInfo) { + details.userInfo.id = details.userInfo.id || details.id; + } else { + details.userInfo = {id: details.id}; + } + if (Platform.OS === 'ios') { let soundName = details.soundName ? details.soundName : 'default'; // play sound (and vibrate) as default behaviour @@ -235,12 +241,6 @@ Notifications.localNotificationSchedule = function(details) { soundName = ''; // empty string results in no sound (and no vibration) } - if (details.userInfo) { - details.userInfo.id = details.userInfo.id || details.id; - } else { - details.userInfo = {id: details.id}; - } - const iosDetails = { fireDate: details.date.toISOString(), alertTitle: details.title, From 22d8c752fb247cc1248cf516910bc0c7537426a1 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Wed, 8 Jul 2020 17:42:51 +0300 Subject: [PATCH 084/179] return notification id in onNotification method on iOS --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bf8159c01..b8c18dfe0 100644 --- a/index.js +++ b/index.js @@ -344,12 +344,13 @@ Notifications._onNotification = function(data, isFromBackground = null) { if ( this.onNotification !== false ) { if ( Platform.OS === 'ios' ) { + const notifData = data.getData(); this.onNotification({ - id: data?.userInfo?.id, + id: notifData?.id, foreground: ! isFromBackground, userInteraction: isFromBackground, message: data.getMessage(), - data: data.getData(), + data: notifData, badge: data.getBadgeCount(), alert: data.getAlert(), sound: data.getSound(), From 3b103622e86a8251dd543cd51b2c536282d4e585 Mon Sep 17 00:00:00 2001 From: arek Date: Thu, 9 Jul 2020 20:12:30 +0200 Subject: [PATCH 085/179] [ANDROID] Add support for setOnlyAlertOnce property --- README.md | 3 ++- .../modules/RNPushNotificationHelper.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0857abf0b..33d9d1bdf 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,8 @@ PushNotification.localNotification({ ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. - + onlyAlertOnce: false, //(optional) alert will open only once with sound and notify, default: false + actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..ff969764d 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -314,7 +314,8 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB .setTicker(bundle.getString("ticker")) .setVisibility(visibility) .setPriority(priority) - .setAutoCancel(bundle.getBoolean("autoCancel", true)); + .setAutoCancel(bundle.getBoolean("autoCancel", true)) + .setOnlyAlertOnce(bundle.getBoolean("onlyAlertOnce", false)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24 and higher // Restore showing timestamp on Android 7+ From b1f6474b428c587c7ef0c4d324ee3d7c082d6dfa Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 15 Jul 2020 10:31:48 +0200 Subject: [PATCH 086/179] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0857abf0b..015dde2db 100644 --- a/README.md +++ b/README.md @@ -619,7 +619,7 @@ Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, ## Notification Actions -(Android only) [Refer](https://github.com/zo0r/react-native-push-notification/issues/151) to this issue to see an example of a notification action. +(Android Only) This is done by specifying an `actions` parameters while configuring the local notification. This is an array of strings where each string is a notification action that will be presented with the notification. From 8f3f5c7a08050ef7998d0cb1cb82f54463d355a3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 16 Jul 2020 16:02:12 +0200 Subject: [PATCH 087/179] Update code from recent PR for scheduled notifications --- CHANGELOG.md | 4 ++++ .../modules/RNPushNotificationAttributes.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a267b11e..92ebdf083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features +- Add function `createChannel` for custom Android channel support [#1509](https://github.com/zo0r/react-native-push-notification/pull/1509) +- Add Android `messageId` to enable integration with `react-native-firebase/messaging` [#1510](https://github.com/zo0r/react-native-push-notification/pull/1510) +- Add support for `onlyAlertOnce` property [#1519](https://github.com/zo0r/react-native-push-notification/pull/1519) + ### Fixed diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 119a49bd7..113cb2428 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -35,6 +35,7 @@ public class RNPushNotificationAttributes { private static final String COLOR = "color"; private static final String GROUP = "group"; private static final String GROUP_SUMMARY = "groupSummary"; + private static final String MESSAGE_ID = "messageId"; private static final String USER_INTERACTION = "userInteraction"; private static final String PLAY_SOUND = "playSound"; private static final String VIBRATE = "vibrate"; @@ -44,6 +45,7 @@ public class RNPushNotificationAttributes { private static final String TAG = "tag"; private static final String REPEAT_TYPE = "repeatType"; private static final String REPEAT_TIME = "repeatTime"; + private static final String ONLY_ALERT_ONCE = "onlyAlertOnce"; private static final String ONGOING = "ongoing"; private static final String ALLOW_WHILE_IDLE = "allowWhileIdle"; private static final String IGNORE_IN_FOREGROUND = "ignoreInForeground"; @@ -70,6 +72,7 @@ public class RNPushNotificationAttributes { private final String color; private final String group; private final boolean groupSummary; + private final String messageId; private final boolean userInteraction; private final boolean playSound; private final boolean vibrate; @@ -79,6 +82,7 @@ public class RNPushNotificationAttributes { private final String tag; private final String repeatType; private final double repeatTime; + private final boolean onlyAlertOnce; private final boolean ongoing; private final boolean allowWhileIdle; private final boolean ignoreInForeground; @@ -106,6 +110,7 @@ public RNPushNotificationAttributes(Bundle bundle) { color = bundle.getString(COLOR); group = bundle.getString(GROUP); groupSummary = bundle.getBoolean(GROUP_SUMMARY); + messageId = bundle.getString(MESSAGE_ID); userInteraction = bundle.getBoolean(USER_INTERACTION); playSound = bundle.getBoolean(PLAY_SOUND); vibrate = bundle.getBoolean(VIBRATE); @@ -115,6 +120,7 @@ public RNPushNotificationAttributes(Bundle bundle) { tag = bundle.getString(TAG); repeatType = bundle.getString(REPEAT_TYPE); repeatTime = bundle.getDouble(REPEAT_TIME); + onlyAlertOnce = bundle.getBoolean(ONLY_ALERT_ONCE); ongoing = bundle.getBoolean(ONGOING); allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE); ignoreInForeground = bundle.getBoolean(IGNORE_IN_FOREGROUND); @@ -144,6 +150,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { color = jsonObject.has(COLOR) ? jsonObject.getString(COLOR) : null; group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null; groupSummary = jsonObject.has(GROUP_SUMMARY) ? jsonObject.getBoolean(GROUP_SUMMARY) : false; + messageId = jsonObject.has(MESSAGE_ID) ? jsonObject.getString(MESSAGE_ID) : null; userInteraction = jsonObject.has(USER_INTERACTION) ? jsonObject.getBoolean(USER_INTERACTION) : false; playSound = jsonObject.has(PLAY_SOUND) ? jsonObject.getBoolean(PLAY_SOUND) : true; vibrate = jsonObject.has(VIBRATE) ? jsonObject.getBoolean(VIBRATE) : true; @@ -153,6 +160,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { tag = jsonObject.has(TAG) ? jsonObject.getString(TAG) : null; repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null; repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0; + onlyAlertOnce = jsonObject.has(ONLY_ALERT_ONCE) ? jsonObject.getBoolean(ONLY_ALERT_ONCE) : false; ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false; allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; ignoreInForeground = jsonObject.has(IGNORE_IN_FOREGROUND) ? jsonObject.getBoolean(IGNORE_IN_FOREGROUND) : false; @@ -239,6 +247,7 @@ public Bundle toBundle() { bundle.putString(COLOR, color); bundle.putString(GROUP, group); bundle.putBoolean(GROUP_SUMMARY, groupSummary); + bundle.putString(MESSAGE_ID, messageId); bundle.putBoolean(USER_INTERACTION, userInteraction); bundle.putBoolean(PLAY_SOUND, playSound); bundle.putBoolean(VIBRATE, vibrate); @@ -248,6 +257,7 @@ public Bundle toBundle() { bundle.putString(TAG, tag); bundle.putString(REPEAT_TYPE, repeatType); bundle.putDouble(REPEAT_TIME, repeatTime); + bundle.putBoolean(ONLY_ALERT_ONCE, onlyAlertOnce); bundle.putBoolean(ONGOING, ongoing); bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle); bundle.putBoolean(IGNORE_IN_FOREGROUND, ignoreInForeground); @@ -279,6 +289,7 @@ public JSONObject toJson() { jsonObject.put(COLOR, color); jsonObject.put(GROUP, group); jsonObject.put(GROUP_SUMMARY, groupSummary); + jsonObject.put(MESSAGE_ID, messageId); jsonObject.put(USER_INTERACTION, userInteraction); jsonObject.put(PLAY_SOUND, playSound); jsonObject.put(VIBRATE, vibrate); @@ -288,6 +299,7 @@ public JSONObject toJson() { jsonObject.put(TAG, tag); jsonObject.put(REPEAT_TYPE, repeatType); jsonObject.put(REPEAT_TIME, repeatTime); + jsonObject.put(ONLY_ALERT_ONCE, onlyAlertOnce); jsonObject.put(ONGOING, ongoing); jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle); jsonObject.put(IGNORE_IN_FOREGROUND, ignoreInForeground); @@ -325,6 +337,7 @@ public String toString() { ", color='" + color + '\'' + ", group='" + group + '\'' + ", groupSummary='" + groupSummary + '\'' + + ", messageId='" + messageId + '\'' + ", userInteraction=" + userInteraction + ", playSound=" + playSound + ", vibrate=" + vibrate + @@ -334,6 +347,7 @@ public String toString() { ", tag='" + tag + '\'' + ", repeatType='" + repeatType + '\'' + ", repeatTime=" + repeatTime + + ", onlyAlertOnce=" + onlyAlertOnce + ", ongoing=" + ongoing + ", allowWhileIdle=" + allowWhileIdle + ", ignoreInForeground=" + ignoreInForeground + From 354e61905780338986c2e897370118bcd44bfc8b Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Thu, 16 Jul 2020 17:15:40 +0200 Subject: [PATCH 088/179] Rename `channelDesc` to `channelDescription`. --- README.md | 2 +- .../modules/RNPushNotificationHelper.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d84295c8e..e9e8bb5e5 100644 --- a/README.md +++ b/README.md @@ -376,7 +376,7 @@ To use custom channels, create them at startup and pass the matching `channelId` { channelId: "custom-channel-id", // (required) channelName: "Custom channel", // (required) - channelDesc: "A custom channel to categorise your custom notifications", // (optional) default: undefined. + channelDescription: "A custom channel to categorise your custom notifications", // (optional) default: undefined. soundName: "default", // (optional) See `soundName` parameter of `localNotification` function importance: 4, // (optional) default: 4. Int value of the Android notification importance vibrate: true, // (optional) default: true. Creates the default vibration patten if true. diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 13a067867..cd3469bbc 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -958,7 +958,7 @@ public boolean createChannel(ReadableMap channelInfo) { String channelId = channelInfo.getString("channelId"); String channelName = channelInfo.getString("channelName"); - String channelDesc = channelInfo.hasKey("channelDesc") ? channelInfo.getString("channelDesc") : null; + String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : null; String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); @@ -968,7 +968,7 @@ public boolean createChannel(ReadableMap channelInfo) { Uri soundUri = getSoundUri(soundName); - return checkOrCreateChannel(manager, channelId, channelName, channelDesc, soundUri, importance, vibratePattern); + return checkOrCreateChannel(manager, channelId, channelName, channelDescription, soundUri, importance, vibratePattern); } public boolean isApplicationInForeground(Context context) { From 5efb44d74354507042512c5894826f2cf93b63fa Mon Sep 17 00:00:00 2001 From: student-t Date: Sat, 18 Jul 2020 06:36:02 +1000 Subject: [PATCH 089/179] Fixed a syntax error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 067040d7a..607fc0209 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ PushNotification.configure({ // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS) onRegistrationError: function(err) { console.error(err.message, err); - } + }, // IOS ONLY (optional): default: all - Permissions to register. permissions: { From 9e8480328c02d84ec1dfa829dd17e01b5a9b70b3 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Tue, 21 Jul 2020 10:42:48 +0300 Subject: [PATCH 090/179] align onNotification on both platforms --- README.md | 4 ++-- example/NotifService.js | 12 ++++++------ example/ios/Podfile.lock | 4 ++-- example/package.json | 2 +- index.js | 29 ++++++++--------------------- package.json | 2 +- 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index a79e981d7..3bc4cade5 100644 --- a/README.md +++ b/README.md @@ -299,7 +299,6 @@ EXAMPLE: ```javascript PushNotification.localNotification({ /* Android Only Properties */ - id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID ticker: "My Notification Ticker", // (optional) showWhen: true, // (optional) default: true autoCancel: true, // (optional) default: true @@ -332,9 +331,10 @@ PushNotification.localNotification({ category: "", // (optional) default: empty string /* iOS and Android properties */ - userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) + id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID title: "My Notification Title", // (optional) message: "My Notification Message", // (required) + userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) playSound: false, // (optional) default: true soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) diff --git a/example/NotifService.js b/example/NotifService.js index c1f3f92b1..eb8259704 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -24,7 +24,6 @@ export default class NotifService { this.lastId++; PushNotification.localNotification({ /* Android Only Properties */ - id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID ticker: 'My Notification Ticker', // (optional) autoCancel: true, // (optional) default: true largeIcon: 'ic_launcher', // (optional) default: "ic_launcher" @@ -39,15 +38,16 @@ export default class NotifService { ongoing: false, // (optional) set whether this is an "ongoing" notification actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true - + /* iOS only properties */ alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string - userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) - + /* iOS and Android properties */ + id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID title: 'Local Notification', // (optional) message: 'My Notification Message', // (required) + userInfo: { screen: 'home' }, // (optional) default: {} (using null throws a JSON value '' error) playSound: !!soundName, // (optional) default: true soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) @@ -60,7 +60,6 @@ export default class NotifService { date: new Date(Date.now() + 30 * 1000), // in 30 secs /* Android Only Properties */ - id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID ticker: 'My Notification Ticker', // (optional) autoCancel: true, // (optional) default: true largeIcon: 'ic_launcher', // (optional) default: "ic_launcher" @@ -81,9 +80,10 @@ export default class NotifService { category: '', // (optional) default: empty string /* iOS and Android properties */ - userInfo: {}, // (optional) default: {} (using null throws a JSON value '' error) + id: this.lastId, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID title: 'Scheduled Notification', // (optional) message: 'My Notification Message', // (required) + userInfo: { sceen: "home" }, // (optional) default: {} (using null throws a JSON value '' error) playSound: !!soundName, // (optional) default: true number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 2f44b3dad..1ef8335cd 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -292,7 +292,7 @@ PODS: - React-cxxreact (= 0.62.2) - React-jsi (= 0.62.2) - ReactCommon/callinvoker (= 0.62.2) - - RNCPushNotificationIOS (1.3.0): + - RNCPushNotificationIOS (1.4.0): - React - Yoga (1.14.0) - YogaKit (1.18.1): @@ -453,7 +453,7 @@ SPEC CHECKSUMS: React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNCPushNotificationIOS: d5fd66aed4e03c6491ca0c6111a03d4f6455ff6c + RNCPushNotificationIOS: dc1c0c6aa18a128df123598149f42e848d26a4ac Yoga: 3ebccbdd559724312790e7742142d062476b698e YogaKit: f782866e155069a2cca2517aafea43200b01fd5a diff --git a/example/package.json b/example/package.json index 091ea7bee..ca8632cae 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,7 @@ "pod-install": "cd ios && pod install" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.3.0", + "@react-native-community/push-notification-ios": "^1.4.0", "react": "16.11.0", "react-native": "0.62.2", "react-native-push-notification": "git+https://git@github.com/zo0r/react-native-push-notification.git" diff --git a/index.js b/index.js index b8c18dfe0..1388711b4 100644 --- a/index.js +++ b/index.js @@ -190,10 +190,6 @@ Notifications.localNotification = function(details) { } } - if(!details.data && details.userInfo){ - details.data = details.userInfo; - } - if (details && typeof details.shortcutId === 'number') { if(isNaN(details.shortcutId)) { console.warn('NaN value has been passed as shortcutId'); @@ -281,10 +277,6 @@ Notifications.localNotificationSchedule = function(details) { details.shortcutId = '' + details.shortcutId; } } - - if(!details.data && details.userInfo){ - details.data = details.userInfo; - } if(details && Array.isArray(details.actions)) { details.actions = JSON.stringify(details.actions); @@ -352,25 +344,20 @@ Notifications._onNotification = function(data, isFromBackground = null) { message: data.getMessage(), data: notifData, badge: data.getBadgeCount(), - alert: data.getAlert(), - sound: data.getSound(), - fireDate: data._fireDate, + title: data.getTitle(), + soundName: data.getSound(), + fireDate: Date.parse(data._fireDate), finish: (res) => data.finish(res) }); } else { var notificationData = { foreground: ! isFromBackground, finish: () => {}, - ...data + ...data, + data: data?.userInfo, }; - - if ( typeof notificationData.data === 'string' ) { - try { - notificationData.data = JSON.parse(notificationData.data); - } catch(e) { - /* void */ - } - } + delete notificationData.userInfo; + delete notificationData.notificationId; this.onNotification(notificationData); } @@ -480,7 +467,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { soundName: notif.soundName, repeatInterval: notif.repeatInterval, id: notif.userInfo?.id, - date: new Date(notif.fireDate), + date: new Date(notif.fireDate), number: notif?.applicationIconBadgeNumber, message: notif?.alertBody, title: notif?.alertTitle, diff --git a/package.json b/package.json index 7b4afe9c3..ad4c56cbd 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.3.0" + "@react-native-community/push-notification-ios": "^1.4.0" }, "peerDependencies": { "react-native": ">=0.33" From 2c120389ecca0e03dc2801d04208c0c91b59b98b Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 09:18:28 +0200 Subject: [PATCH 091/179] [Android] Allow to change default notification channel name after it's creation #1549 #1549 --- .../modules/RNPushNotificationHelper.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index cd3469bbc..db36c5b72 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -919,15 +919,17 @@ private boolean checkOrCreateChannel(NotificationManager manager, String channel NotificationChannel channel = manager.getNotificationChannel(channel_id); - if (channel == null) { - if(channel_name == null) { - channel_name = this.config.getChannelName(channel_id); - } + if(channel_name == null) { + channel_name = this.config.getChannelName(channel_id); + } - if(channel_description == null) { - channel_description = this.config.getChannelDescription(channel_id); - } + if(channel_description == null) { + channel_description = this.config.getChannelDescription(channel_id); + } + if (channel == null || channel.getName() != channel_name || channel.getDescription() != channel_description) { + // If channel doesn't exist create a new one. + // If channel name or description is updated then update the existing channel. channel = new NotificationChannel(channel_id, channel_name, importance); channel.setDescription(channel_description); From 7a3866e43a7f50b07d674ac829dc3c9b15d70510 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 09:19:49 +0200 Subject: [PATCH 092/179] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ebdf083..dd5a89289 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Features -- Add function `createChannel` for custom Android channel support [#1509](https://github.com/zo0r/react-native-push-notification/pull/1509) -- Add Android `messageId` to enable integration with `react-native-firebase/messaging` [#1510](https://github.com/zo0r/react-native-push-notification/pull/1510) -- Add support for `onlyAlertOnce` property [#1519](https://github.com/zo0r/react-native-push-notification/pull/1519) +- (Android) Add function `createChannel` for custom Android channel support [#1509](https://github.com/zo0r/react-native-push-notification/pull/1509) +- (Android) Add Android `messageId` to enable integration with `react-native-firebase/messaging` [#1510](https://github.com/zo0r/react-native-push-notification/pull/1510) +- (Android) Add support for `onlyAlertOnce` property [#1519](https://github.com/zo0r/react-native-push-notification/pull/1519) +- (Android) Allow to change default notification channel name after it's creation [#1549](https://github.com/zo0r/react-native-push-notification/pull/1549) ### Fixed From 471d3bb0ed58e8ab48c4f66fc46ba93f2fd281aa Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 09:44:42 +0200 Subject: [PATCH 093/179] Add tests for channel update. #1549 --- README.md | 2 +- .../modules/RNPushNotificationHelper.java | 2 +- example/App.js | 7 +++++++ example/NotifService.js | 16 ++++++++++++++++ example/android/app/src/main/AndroidManifest.xml | 7 ------- example/package.json | 2 +- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e9e8bb5e5..c89b4c17c 100644 --- a/README.md +++ b/README.md @@ -381,7 +381,7 @@ To use custom channels, create them at startup and pass the matching `channelId` importance: 4, // (optional) default: 4. Int value of the Android notification importance vibrate: true, // (optional) default: true. Creates the default vibration patten if true. }, - (created: any) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + (created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. ); ``` diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index db36c5b72..fdd6d4b3d 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -927,7 +927,7 @@ private boolean checkOrCreateChannel(NotificationManager manager, String channel channel_description = this.config.getChannelDescription(channel_id); } - if (channel == null || channel.getName() != channel_name || channel.getDescription() != channel_description) { + if (channel == null || !channel.getName().equals(channel_name) || !channel.getDescription().equals(channel_description)) { // If channel doesn't exist create a new one. // If channel name or description is updated then update the existing channel. channel = new NotificationChannel(channel_id, channel_name, importance); diff --git a/example/App.js b/example/App.js index a4c8458b0..accf9e4ed 100644 --- a/example/App.js +++ b/example/App.js @@ -112,6 +112,13 @@ export default class App extends Component { }}> Console.Log Scheduled Local Notifications + { + this.notif.createOrUpdateChannel(); + }}> + Create or update a channel + diff --git a/example/NotifService.js b/example/NotifService.js index 66c32b67e..9d4b9b1a7 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -4,6 +4,7 @@ import NotificationHandler from './NotificationHandler'; export default class NotifService { constructor(onRegister, onNotification) { this.lastId = 0; + this.lastChannelCounter = 0; NotificationHandler.attachRegister(onRegister); NotificationHandler.attachNotification(onNotification); @@ -20,6 +21,21 @@ export default class NotifService { }); } + createOrUpdateChannel() { + this.lastChannelCounter++; + PushNotification.createChannel( + { + channelId: "custom-channel-id", // (required) + channelName: `Custom channel - Counter: ${this.lastChannelCounter}`, // (required) + channelDescription: `A custom channel to categorise your custom notifications. Updated at: ${Date.now()}`, // (optional) default: undefined. + soundName: "default", // (optional) See `soundName` parameter of `localNotification` function + importance: 4, // (optional) default: 4. Int value of the Android notification importance + vibrate: true, // (optional) default: true. Creates the default vibration patten if true. + }, + (created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + ); + } + localNotif(soundName) { this.lastId++; PushNotification.localNotification({ diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 47fdd7631..584fa4be9 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -53,13 +53,6 @@ android:value="Super channel description"/> - - - - - diff --git a/example/package.json b/example/package.json index 606b5d146..c4f4d7583 100644 --- a/example/package.json +++ b/example/package.json @@ -14,7 +14,7 @@ "@react-native-community/push-notification-ios": "^1.2.2", "react": "16.11.0", "react-native": "0.62.2", - "react-native-push-notification": "git+https://git@github.com/zo0r/react-native-push-notification.git" + "react-native-push-notification": "zo0r/react-native-push-notification#dev" }, "devDependencies": { "@babel/core": "^7.9.0", From 30b89c863fb2305e8bdbdef43e17513bace9689a Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 13:58:16 +0200 Subject: [PATCH 094/179] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 607fc0209..a5779b3fa 100644 --- a/README.md +++ b/README.md @@ -214,10 +214,13 @@ public class MainApplication extends Application implements ReactApplication { ## Usage +**DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App` ** + ```javascript import PushNotificationIOS from "@react-native-community/push-notification-ios"; var PushNotification = require("react-native-push-notification"); +// Must be outside of any component LifeCycle. PushNotification.configure({ // (optional) Called when Token is generated (iOS and Android) onRegister: function (token) { From 9c34ed675d1748417a78ed7d97ea9b84aa2b9d5f Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 14:00:43 +0200 Subject: [PATCH 095/179] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5779b3fa..6a5425158 100644 --- a/README.md +++ b/README.md @@ -214,13 +214,13 @@ public class MainApplication extends Application implements ReactApplication { ## Usage -**DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App` ** +**DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App`** ```javascript import PushNotificationIOS from "@react-native-community/push-notification-ios"; var PushNotification = require("react-native-push-notification"); -// Must be outside of any component LifeCycle. +// Must be outside of any component LifeCycle (such as `componentDidMount`). PushNotification.configure({ // (optional) Called when Token is generated (iOS and Android) onRegister: function (token) { From 9ae2ce53676f0329c4e75e613493def37653c4d0 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 22 Jul 2020 16:40:08 +0200 Subject: [PATCH 096/179] Fix case of small/large icon null. --- .../modules/RNPushNotificationHelper.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index fdd6d4b3d..304111aaa 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -352,10 +352,10 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB String smallIcon = bundle.getString("smallIcon"); - if (smallIcon != null) { - smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); - } else if (!smallIcon.isEmpty()) { - smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); + if (smallIcon != null && !smallIcon.isEmpty()) { + smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); + } else if(smallIcon == null) { + smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); } if (smallIconResId == 0) { @@ -374,10 +374,10 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB String largeIcon = bundle.getString("largeIcon"); - if (largeIcon != null) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); - } else if (!largeIcon.isEmpty()) { - largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); + if (largeIcon != null && !largeIcon.isEmpty()) { + largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); + } else if(largeIcon == null) { + largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); } // Before Lolipop there was no large icon for notifications. From 9cc416751ceea69c3c1396b07a0756fcd2d1e754 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 27 Jul 2020 14:07:01 +0300 Subject: [PATCH 097/179] keep notification data from fcm while populating data userInfo --- index.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 1388711b4..249d26f56 100644 --- a/index.js +++ b/index.js @@ -354,7 +354,19 @@ Notifications._onNotification = function(data, isFromBackground = null) { foreground: ! isFromBackground, finish: () => {}, ...data, - data: data?.userInfo, + }; + + if ( typeof notificationData.data === 'string' ) { + try { + notificationData.data = JSON.parse(notificationData.data); + } catch(e) { + /* void */ + } + } + + notificationData.data = { + ...(notificationData.data ? notificationData.data : {}), + ...(notificationData.data ? notificationData.userInfo : {}) }; delete notificationData.userInfo; delete notificationData.notificationId; From d547687e47311291d5e903102064260048624983 Mon Sep 17 00:00:00 2001 From: Lukas Baranauskas Date: Mon, 27 Jul 2020 14:13:17 +0300 Subject: [PATCH 098/179] make sure data/userInfo is an object before spreading --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 249d26f56..59cfa7633 100644 --- a/index.js +++ b/index.js @@ -365,8 +365,8 @@ Notifications._onNotification = function(data, isFromBackground = null) { } notificationData.data = { - ...(notificationData.data ? notificationData.data : {}), - ...(notificationData.data ? notificationData.userInfo : {}) + ...(typeof notificationData.data === 'object' ? notificationData.data : {}), + ...(typeof notificationData.userInfo === 'object' ? notificationData.userInfo : {}) }; delete notificationData.userInfo; delete notificationData.notificationId; From 7589c4a382c1d4773616f4d1998f0e32329cbdfb Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 27 Jul 2020 22:14:54 +0200 Subject: [PATCH 099/179] Apply changes to popInitialNotification. --- index.js | 98 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/index.js b/index.js index 59cfa7633..49292b2f8 100644 --- a/index.js +++ b/index.js @@ -326,7 +326,11 @@ Notifications._onAction = function(notification) { this.onAction(notification); } -Notifications._onNotification = function(data, isFromBackground = null) { +Notifications._transformNotificationObject = function(data, isFromBackground = null) { + if(!data) { + return; + } + if ( isFromBackground === null ) { isFromBackground = ( data.foreground === false || @@ -334,45 +338,59 @@ Notifications._onNotification = function(data, isFromBackground = null) { ); } - if ( this.onNotification !== false ) { - if ( Platform.OS === 'ios' ) { - const notifData = data.getData(); - this.onNotification({ - id: notifData?.id, - foreground: ! isFromBackground, - userInteraction: isFromBackground, - message: data.getMessage(), - data: notifData, - badge: data.getBadgeCount(), - title: data.getTitle(), - soundName: data.getSound(), - fireDate: Date.parse(data._fireDate), - finish: (res) => data.finish(res) - }); - } else { - var notificationData = { - foreground: ! isFromBackground, - finish: () => {}, - ...data, - }; - - if ( typeof notificationData.data === 'string' ) { - try { - notificationData.data = JSON.parse(notificationData.data); - } catch(e) { - /* void */ - } + let _notification; + + if ( Platform.OS === 'ios' ) { + const notifData = data.getData(); + + _notification = { + id: notifData?.id, + foreground: !isFromBackground, + userInteraction: isFromBackground, + message: data.getMessage(), + data: notifData, + badge: data.getBadgeCount(), + title: data.getTitle(), + soundName: data.getSound(), + fireDate: Date.parse(data._fireDate), + finish: (res) => data.finish(res) + }; + } else { + _notification = { + foreground: ! isFromBackground, + finish: () => {}, + ...data, + }; + + if ( typeof _notification.data === 'string' ) { + try { + _notification.data = JSON.parse(_notification.data); + } catch(e) { + /* void */ } + } + + _notification.data = { + ...(typeof _notification.userInfo === 'object' ? _notification.userInfo : {}), + ...(typeof _notification.data === 'object' ? _notification.data : {}), + }; + + delete _notification.userInfo; + delete _notification.notificationId; + } - notificationData.data = { - ...(typeof notificationData.data === 'object' ? notificationData.data : {}), - ...(typeof notificationData.userInfo === 'object' ? notificationData.userInfo : {}) - }; - delete notificationData.userInfo; - delete notificationData.notificationId; + return _notification; +} + +Notifications._onNotification = function(data, initialNotification = false) { + if ( this.onNotification !== false ) { + let notification = data; - this.onNotification(notificationData); + if(!initialNotification) { + notification = this._transformNotificationObject(data); } + + this.onNotification(notification); } }; @@ -442,8 +460,10 @@ Notifications.getApplicationIconBadgeNumber = function() { }; Notifications.popInitialNotification = function(handler) { - this.callNative('getInitialNotification').then(function(result){ - handler(result); + this.callNative('getInitialNotification').then((result) => { + handler( + this._transformNotificationObject(result, true) + ); }); }; @@ -479,7 +499,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { soundName: notif.soundName, repeatInterval: notif.repeatInterval, id: notif.userInfo?.id, - date: new Date(notif.fireDate), + date: new Date(notif.fireDate), number: notif?.applicationIconBadgeNumber, message: notif?.alertBody, title: notif?.alertTitle, From 271461ee5039de11ce24d07285ff470d622f88ae Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 27 Jul 2020 22:40:19 +0200 Subject: [PATCH 100/179] fix popInitialNotification and null pointer Fix a case where popInitialNotification is not triggered. Fix a null pointer exception. --- index.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 49292b2f8..dd1d42107 100644 --- a/index.js +++ b/index.js @@ -95,27 +95,30 @@ Notifications.configure = function(options) { this.isLoaded = true; } - const handlePopInitialNotification = function(state) { + const handlePopInitialNotification = (state) => { if('active' !== state) { return; } if (options.popInitialNotification === undefined || options.popInitialNotification === true) { this.popInitialNotification(function(firstNotification) { - if ( firstNotification !== null ) { - if(false === firstNotification.userInteraction || this.idInitialNotification === firstNotification.id) { - return; - } - - this.idInitialNotification = firstNotification.id; - this._onNotification(firstNotification, true); + if (!firstNotification) { + return; } + + if(false === firstNotification.userInteraction || this.idInitialNotification === firstNotification.id) { + return; + } + + this.idInitialNotification = firstNotification.id; + this._onNotification(firstNotification, true); }.bind(this)); } } AppState.addEventListener('change', handlePopInitialNotification.bind(this)); - handlePopInitialNotification(); + + handlePopInitialNotification(AppState.currentState); if ( options.requestPermissions !== false ) { this._requestPermissions(); @@ -499,7 +502,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { soundName: notif.soundName, repeatInterval: notif.repeatInterval, id: notif.userInfo?.id, - date: new Date(notif.fireDate), + date: new Date(notif.fireDate), number: notif?.applicationIconBadgeNumber, message: notif?.alertBody, title: notif?.alertTitle, From 762f4c09cf68557d375d462f72cc758e5df229e6 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Fri, 31 Jul 2020 16:49:05 +0200 Subject: [PATCH 101/179] Fix behaviour of popInitialNotification and onNotification. Fix foreground value. --- .../modules/RNPushNotification.java | 2 -- .../modules/RNPushNotificationHelper.java | 5 +++-- .../modules/RNPushNotificationPublisher.java | 2 +- index.js | 11 ++++++----- 4 files changed, 10 insertions(+), 10 deletions(-) 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 c268cd452..10d5835ef 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -89,8 +89,6 @@ private Bundle getBundleFromIntent(Intent intent) { public void onNewIntent(Intent intent) { Bundle bundle = this.getBundleFromIntent(intent); if (bundle != null) { - bundle.putBoolean("foreground", false); - intent.putExtra("notification", bundle); mJsDelivery.notifyNotification(bundle); } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..22c2622b1 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -422,6 +422,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Intent intent = new Intent(context, intentClass); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + bundle.putBoolean("foreground", this.isApplicationInForeground()); bundle.putBoolean("userInteraction", true); intent.putExtra("notification", bundle); @@ -583,7 +584,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB editor.apply(); } - if (!(this.isApplicationInForeground(context) && bundle.getBoolean("ignoreInForeground"))) { + if (!(this.isApplicationInForeground() && bundle.getBoolean("ignoreInForeground"))) { Notification info = notification.build(); info.defaults |= Notification.DEFAULT_LIGHTS; @@ -938,7 +939,7 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id } } - public boolean isApplicationInForeground(Context context) { + public boolean isApplicationInForeground() { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List processInfos = activityManager.getRunningAppProcesses(); if (processInfos != null) { diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java index cb3c6d33f..613e23eee 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java @@ -40,7 +40,7 @@ private void handleLocalNotification(Context context, Bundle bundle) { Application applicationContext = (Application) context.getApplicationContext(); RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); - boolean isForeground = pushNotificationHelper.isApplicationInForeground(applicationContext); + boolean isForeground = pushNotificationHelper.isApplicationInForeground(); Log.v(LOG_TAG, "sendNotification: " + bundle); diff --git a/index.js b/index.js index dd1d42107..46e1c6fcc 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ var Notifications = { onAction: false, onRemoteFetch: false, isLoaded: false, - idInitialNotification: null, + isPopInitialNotification: false, isPermissionsRequestPending: false, @@ -102,15 +102,16 @@ Notifications.configure = function(options) { if (options.popInitialNotification === undefined || options.popInitialNotification === true) { this.popInitialNotification(function(firstNotification) { - if (!firstNotification) { + if(this.isPopInitialNotification) { return; } - - if(false === firstNotification.userInteraction || this.idInitialNotification === firstNotification.id) { + + this.isPopInitialNotification = true; + + if (!firstNotification || false === firstNotification.userInteraction) { return; } - this.idInitialNotification = firstNotification.id; this._onNotification(firstNotification, true); }.bind(this)); } From 1f978554a3a6347bdcf80af180e4d70f50d80489 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 3 Aug 2020 20:47:13 +0200 Subject: [PATCH 102/179] Release version 5.0.0. --- .gitignore | 2 ++ CHANGELOG.md | 10 ++++++-- README.md | 23 +++++++++++++++---- .../modules/RNPushNotificationAttributes.java | 5 ---- example/App.js | 7 ++++++ example/NotifService.js | 4 ++++ index.js | 7 +++++- package.json | 2 +- 8 files changed, 46 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index adec98609..0a2cc57b7 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ android/src/main/gen #Debug only google-services.json + +.vscode/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d7d6d33..f05211a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,17 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Breaking changes +- (Android/iOS) Unify returned values between iOS and Android [#1516](https://github.com/zo0r/react-native-push-notification/pull/1516). +- (Android/iOS) `.popInitialNotification(callback)` now return the same format as `onNotification()`. +- (Android) `popInitialNotification` in `configure()` now trigger only once on app startup, same as iOS. +- (Android) `notification.foreground` now return the good value, before the value was `false` most of the time. + ### Features - (Android) Add function `createChannel` for custom Android channel support [#1509](https://github.com/zo0r/react-native-push-notification/pull/1509) @@ -18,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- (Android) `popInitialNotification` in `configure()` now trigger only once and do not trigger twice `onNotification()` when user press the notification, more details: [#1516](https://github.com/zo0r/react-native-push-notification/pull/1516). +- (Android) `notification.foreground` now return the good value, before the value was `false` most of the time. ## [4.0.0] 2020-07-06 diff --git a/README.md b/README.md index 16f6f4631..3463dc56c 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,17 @@ React Native Local and Remote Notifications for iOS and Android -## 🎉 Version 4.0.0 is live ! 🎉 +## 🎉 Version 5.0.0 is live ! 🎉 Check out for changes in the CHANGELOG: [Changelog](https://github.com/zo0r/react-native-push-notification/blob/master/CHANGELOG.md) +# Supporting the project + +Maintaining this project takes time. To help allocate time, you can Buy Me a Coffee :wink: + +Buy Me A Coffee ## Supported React Native Versions @@ -357,6 +362,18 @@ PushNotification.localNotificationSchedule({ }); ``` +## Get the initial notification + +`PushNotification.popInitialNotification(callback)` + +EXAMPLE: + +```javascript +PushNotification.popInitialNotification((notification) => { + console.log('Initial Notification', notification); +}); +``` + ## Custom sounds In android, add your custom sound file to `[project_root]/android/app/src/main/res/raw` @@ -660,10 +677,6 @@ Works natively in iOS. Uses the [ShortcutBadger](https://github.com/leolin310148/ShortcutBadger) on Android, and as such will not work on all Android devices. -## Sending Notification Data From Server - -Same parameters as `PushNotification.localNotification()` - ## Android Only Methods `PushNotification.subscribeToTopic(topic: string)` Subscribe to a topic (works only with Firebase) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 113cb2428..d2e960da9 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -36,7 +36,6 @@ public class RNPushNotificationAttributes { private static final String GROUP = "group"; private static final String GROUP_SUMMARY = "groupSummary"; private static final String MESSAGE_ID = "messageId"; - private static final String USER_INTERACTION = "userInteraction"; private static final String PLAY_SOUND = "playSound"; private static final String VIBRATE = "vibrate"; private static final String VIBRATION = "vibration"; @@ -111,7 +110,6 @@ public RNPushNotificationAttributes(Bundle bundle) { group = bundle.getString(GROUP); groupSummary = bundle.getBoolean(GROUP_SUMMARY); messageId = bundle.getString(MESSAGE_ID); - userInteraction = bundle.getBoolean(USER_INTERACTION); playSound = bundle.getBoolean(PLAY_SOUND); vibrate = bundle.getBoolean(VIBRATE); vibration = bundle.getDouble(VIBRATION); @@ -151,7 +149,6 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null; groupSummary = jsonObject.has(GROUP_SUMMARY) ? jsonObject.getBoolean(GROUP_SUMMARY) : false; messageId = jsonObject.has(MESSAGE_ID) ? jsonObject.getString(MESSAGE_ID) : null; - userInteraction = jsonObject.has(USER_INTERACTION) ? jsonObject.getBoolean(USER_INTERACTION) : false; playSound = jsonObject.has(PLAY_SOUND) ? jsonObject.getBoolean(PLAY_SOUND) : true; vibrate = jsonObject.has(VIBRATE) ? jsonObject.getBoolean(VIBRATE) : true; vibration = jsonObject.has(VIBRATION) ? jsonObject.getDouble(VIBRATION) : 1000; @@ -248,7 +245,6 @@ public Bundle toBundle() { bundle.putString(GROUP, group); bundle.putBoolean(GROUP_SUMMARY, groupSummary); bundle.putString(MESSAGE_ID, messageId); - bundle.putBoolean(USER_INTERACTION, userInteraction); bundle.putBoolean(PLAY_SOUND, playSound); bundle.putBoolean(VIBRATE, vibrate); bundle.putDouble(VIBRATION, vibration); @@ -290,7 +286,6 @@ public JSONObject toJson() { jsonObject.put(GROUP, group); jsonObject.put(GROUP_SUMMARY, groupSummary); jsonObject.put(MESSAGE_ID, messageId); - jsonObject.put(USER_INTERACTION, userInteraction); jsonObject.put(PLAY_SOUND, playSound); jsonObject.put(VIBRATE, vibrate); jsonObject.put(VIBRATION, vibration); diff --git a/example/App.js b/example/App.js index accf9e4ed..5d2f03973 100644 --- a/example/App.js +++ b/example/App.js @@ -119,6 +119,13 @@ export default class App extends Component { }}> Create or update a channel + { + this.notif.popInitialNotification(); + }}> + popInitialNotification + diff --git a/example/NotifService.js b/example/NotifService.js index 30f918b66..86ea55eec 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -36,6 +36,10 @@ export default class NotifService { ); } + popInitialNotification() { + PushNotification.popInitialNotification((notification) => console.log('InitialNotication:', notification)); + } + localNotif(soundName) { this.lastId++; PushNotification.localNotification({ diff --git a/index.js b/index.js index f72a8b5a2..072dc55ff 100644 --- a/index.js +++ b/index.js @@ -359,9 +359,14 @@ Notifications._transformNotificationObject = function(data, isFromBackground = n fireDate: Date.parse(data._fireDate), finish: (res) => data.finish(res) }; + + if(isNaN(_notification.fireDate)) { + delete _notification.fireDate; + } + } else { _notification = { - foreground: ! isFromBackground, + foreground: !isFromBackground, finish: () => {}, ...data, }; diff --git a/package.json b/package.json index ad4c56cbd..60258e8b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "4.0.0", + "version": "5.0.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 883d062716aacc55a4edd1c68078db6f206c91de Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 3 Aug 2020 20:54:22 +0200 Subject: [PATCH 103/179] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f05211a3a..8a013b8bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [5.0.0] 2020-08-03 ### Breaking changes From bd9aa19788bb9b5b27a075b2cc5a75a56a939d87 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 4 Aug 2020 07:47:42 +0200 Subject: [PATCH 104/179] Fix #1578. --- CHANGELOG.md | 15 +++++++++++++++ .../modules/RNPushNotificationAttributes.java | 2 -- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a013b8bf..f2a6f43a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## Unreleased + +### Breaking changes + +### Features + +### Fixed + + +## [5.0.1] 2020-08-04 + +### Fixed + +- (Android) Fix change that make gradle build fail. + ## [5.0.0] 2020-08-03 ### Breaking changes diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index d2e960da9..377d7caa7 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -72,7 +72,6 @@ public class RNPushNotificationAttributes { private final String group; private final boolean groupSummary; private final String messageId; - private final boolean userInteraction; private final boolean playSound; private final boolean vibrate; private final double vibration; @@ -333,7 +332,6 @@ public String toString() { ", group='" + group + '\'' + ", groupSummary='" + groupSummary + '\'' + ", messageId='" + messageId + '\'' + - ", userInteraction=" + userInteraction + ", playSound=" + playSound + ", vibrate=" + vibrate + ", vibration=" + vibration + From 9b90d4dd886b6b047daca8a982d410a05b9a01c7 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 4 Aug 2020 07:48:15 +0200 Subject: [PATCH 105/179] Add issue details on Changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2a6f43a4..155d57295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed -- (Android) Fix change that make gradle build fail. +- (Android) Fix change that make gradle build fail [#1578](https://github.com/zo0r/react-native-push-notification/pull/1578). ## [5.0.0] 2020-08-03 From 2ae30a181ba632d6cc227ef79a0fb08c5adbd505 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 4 Aug 2020 07:49:55 +0200 Subject: [PATCH 106/179] Bump version 5.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60258e8b1..50daa7be1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "5.0.0", + "version": "5.0.1", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 78405740f3aba8d2bffc6c02651b80fb0f18704d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 4 Aug 2020 07:53:49 +0200 Subject: [PATCH 107/179] Change README version format. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f9ec385a..3be767b66 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ React Native Local and Remote Notifications for iOS and Android -## 🎉 Version 5.0.0 is live ! 🎉 +## 🎉 Version 5.x is live ! 🎉 Check out for changes in the CHANGELOG: From 85214aec26f44ff8af6678fc5b372f2eb0361787 Mon Sep 17 00:00:00 2001 From: Vikrant Negi Date: Tue, 4 Aug 2020 13:11:48 +0530 Subject: [PATCH 108/179] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3be767b66..d38478227 100644 --- a/README.md +++ b/README.md @@ -489,9 +489,9 @@ PushNotification.channelBlocked(channel_id, function (blocked) { }); ``` -### List channels +### Delete channel -You can list available channels with: +You can delete a channel with: ```js PushNotification.deleteChannel(channel_id); From 2db1e05d9eb2a621a4d2b2b7058a3e0438ab07c3 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 5 Aug 2020 16:37:59 +0200 Subject: [PATCH 109/179] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d38478227..1bc3eca96 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,6 @@ PushNotification.localNotification({ priority: "high", // (optional) set notification priority, default: high visibility: "private", // (optional) set notification visibility, default: private importance: "high", // (optional) set notification importance, default: high - allowWhileIdle: false, // (optional) set notification to work while on doze, default: false ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. @@ -364,6 +363,7 @@ PushNotification.localNotificationSchedule({ //... You can use all the options from localNotifications message: "My Notification Message", // (required) date: new Date(Date.now() + 60 * 1000), // in 60 secs + allowWhileIdle: false, // (optional) set notification to work while on doze, default: false }); ``` From e89f75c0ca46a52dfb4e87f4aa05221b5d03b4f0 Mon Sep 17 00:00:00 2001 From: James Relyea Date: Mon, 10 Aug 2020 15:07:50 -0400 Subject: [PATCH 110/179] Add support for specifying a delegate/parent FirebaseMessagingService to support using multiple providers. --- .../RNPushNotificationListenerService.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java index d51f6960c..ca78c0363 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationListenerService.java @@ -18,18 +18,31 @@ public class RNPushNotificationListenerService extends FirebaseMessagingService { - private RNReceivedMessageHandler mMessageReceivedHandler = new RNReceivedMessageHandler(this); + private RNReceivedMessageHandler mMessageReceivedHandler; + private FirebaseMessagingService mFirebaseServiceDelegate; + + public RNPushNotificationListenerService() { + super(); + this.mMessageReceivedHandler = new RNReceivedMessageHandler(this); + } + + public RNPushNotificationListenerService(FirebaseMessagingService delegate) { + super(); + this.mFirebaseServiceDelegate = delegate; + this.mMessageReceivedHandler = new RNReceivedMessageHandler(delegate); + } @Override public void onNewToken(String token) { final String deviceToken = token; + final FirebaseMessagingService serviceRef = (this.mFirebaseServiceDelegate == null) ? this : this.mFirebaseServiceDelegate; Log.d(LOG_TAG, "Refreshed token: " + deviceToken); Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { public void run() { // Construct and load our normal React JS code bundle - final ReactInstanceManager mReactInstanceManager = ((ReactApplication) getApplication()).getReactNativeHost().getReactInstanceManager(); + final ReactInstanceManager mReactInstanceManager = ((ReactApplication)serviceRef.getApplication()).getReactNativeHost().getReactInstanceManager(); ReactContext context = mReactInstanceManager.getCurrentReactContext(); // If it's constructed, send a notification if (context != null) { From eb538f28a93c17b54a5ba6aee3ff0b3342673e0a Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 12 Aug 2020 10:33:02 +0200 Subject: [PATCH 111/179] Update CHANGELOG. --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + CHANGELOG.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0a912dff1..1b8aec628 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -50,4 +50,5 @@ Describe what you expected to happen: diff --git a/CHANGELOG.md b/CHANGELOG.md index 155d57295..935542b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Features +- Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589) + ### Fixed From c283ac4dfcfbb7b673458f6c7bc63366e7930cc9 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 12 Aug 2020 11:20:47 +0200 Subject: [PATCH 112/179] Fix a bug where user interaction is not set. --- .../modules/RNPushNotification.java | 5 +++++ .../modules/RNPushNotificationPublisher.java | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) 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 41d739423..744ff4ab2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -82,6 +82,11 @@ private Bundle getBundleFromIntent(Intent intent) { } else if (intent.hasExtra("google.message_id")) { bundle = intent.getExtras(); } + + if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("user_interaction")) { + bundle.putBoolean("user_interaction", true); + } + return bundle; } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java index 613e23eee..c779f5fb2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPublisher.java @@ -39,8 +39,6 @@ private void handleLocalNotification(Context context, Bundle bundle) { Application applicationContext = (Application) context.getApplicationContext(); RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); - - boolean isForeground = pushNotificationHelper.isApplicationInForeground(); Log.v(LOG_TAG, "sendNotification: " + bundle); From c391403aaafcbcd5818c5fb8e82615079d0d2a11 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 12 Aug 2020 11:23:47 +0200 Subject: [PATCH 113/179] Wrong name of parameter and CHANGELOG. --- CHANGELOG.md | 4 +++- .../modules/RNPushNotification.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 935542b0a..160936dda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,12 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Features -- Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589) +- (Android) Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589) ### Fixed +- (Android) Fix a bug where `userInteraction` is not set, notification when app in background pressed by user. + ## [5.0.1] 2020-08-04 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 744ff4ab2..a70b76ea5 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -83,8 +83,8 @@ private Bundle getBundleFromIntent(Intent intent) { bundle = intent.getExtras(); } - if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("user_interaction")) { - bundle.putBoolean("user_interaction", true); + if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("userInteraction")) { + bundle.putBoolean("userInteraction", true); } return bundle; From ee6a62e4c94053038b1cbfb8ec4b4ce43f120a43 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sun, 16 Aug 2020 14:16:34 +0200 Subject: [PATCH 114/179] Implement features for #1588. --- CHANGELOG.md | 1 + README.md | 8 +++++-- .../modules/RNPushNotificationAttributes.java | 21 +++++++++++++++++++ .../modules/RNPushNotificationHelper.java | 14 +++++++++++++ example/NotifService.js | 10 +++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 160936dda..d8b190dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Features - (Android) Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589) +- (Android) Add support of `when`, `usesChronometer` and `timeoutAfter`. ### Fixed diff --git a/README.md b/README.md index 1bc3eca96..82a14c3ad 100644 --- a/README.md +++ b/README.md @@ -329,8 +329,12 @@ PushNotification.localNotification({ ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. - onlyAlertOnce: false, //(optional) alert will open only once with sound and notify, default: false - + onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false + + when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null. + usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false. + timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null + messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module. actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 377d7caa7..e0f084ba2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -44,6 +44,9 @@ public class RNPushNotificationAttributes { private static final String TAG = "tag"; private static final String REPEAT_TYPE = "repeatType"; private static final String REPEAT_TIME = "repeatTime"; + private static final String WHEN = "when"; + private static final String USES_CHRONOMETER = "usesChronometer"; + private static final String TIMEOUT_AFTER = "timeoutAfter"; private static final String ONLY_ALERT_ONCE = "onlyAlertOnce"; private static final String ONGOING = "ongoing"; private static final String ALLOW_WHILE_IDLE = "allowWhileIdle"; @@ -80,6 +83,9 @@ public class RNPushNotificationAttributes { private final String tag; private final String repeatType; private final double repeatTime; + private final double when; + private final boolean usesChronometer; + private final double timeoutAfter; private final boolean onlyAlertOnce; private final boolean ongoing; private final boolean allowWhileIdle; @@ -117,6 +123,9 @@ public RNPushNotificationAttributes(Bundle bundle) { tag = bundle.getString(TAG); repeatType = bundle.getString(REPEAT_TYPE); repeatTime = bundle.getDouble(REPEAT_TIME); + when = bundle.getDouble(WHEN); + usesChronometer = bundle.getBoolean(USES_CHRONOMETER); + timeoutAfter = bundle.getDouble(TIMEOUT_AFTER); onlyAlertOnce = bundle.getBoolean(ONLY_ALERT_ONCE); ongoing = bundle.getBoolean(ONGOING); allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE); @@ -156,6 +165,9 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { tag = jsonObject.has(TAG) ? jsonObject.getString(TAG) : null; repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null; repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0; + when = jsonObject.has(WHEN) ? jsonObject.getDouble(WHEN) : null; + usesChronometer = jsonObject.has(USES_CHRONOMETER) ? jsonObject.getBoolean(USES_CHRONOMETER) : false; + timeoutAfter = jsonObject.has(TIMEOUT_AFTER) ? jsonObject.getDouble(TIMEOUT_AFTER) : null; onlyAlertOnce = jsonObject.has(ONLY_ALERT_ONCE) ? jsonObject.getBoolean(ONLY_ALERT_ONCE) : false; ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false; allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; @@ -252,6 +264,9 @@ public Bundle toBundle() { bundle.putString(TAG, tag); bundle.putString(REPEAT_TYPE, repeatType); bundle.putDouble(REPEAT_TIME, repeatTime); + bundle.putDouble(WHEN, when); + bundle.putBoolean(USES_CHRONOMETER, usesChronometer); + bundle.putDouble(TIMEOUT_AFTER, timeoutAfter); bundle.putBoolean(ONLY_ALERT_ONCE, onlyAlertOnce); bundle.putBoolean(ONGOING, ongoing); bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle); @@ -293,6 +308,9 @@ public JSONObject toJson() { jsonObject.put(TAG, tag); jsonObject.put(REPEAT_TYPE, repeatType); jsonObject.put(REPEAT_TIME, repeatTime); + jsonObject.put(WHEN, when); + jsonObject.put(USES_CHRONOMETER, usesChronometer); + jsonObject.put(TIMEOUT_AFTER, timeoutAfter); jsonObject.put(ONLY_ALERT_ONCE, onlyAlertOnce); jsonObject.put(ONGOING, ongoing); jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle); @@ -340,6 +358,9 @@ public String toString() { ", tag='" + tag + '\'' + ", repeatType='" + repeatType + '\'' + ", repeatTime=" + repeatTime + + ", when=" + when + + ", usesChronometer=" + usesChronometer + + ", timeoutAfter=" + timeoutAfter + ", onlyAlertOnce=" + onlyAlertOnce + ", ongoing=" + ongoing + ", allowWhileIdle=" + allowWhileIdle + diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index be38de0ee..4e3c8040c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -498,8 +498,22 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (shortcutId != null) { notification.setShortcutId(shortcutId); } + + Long timeoutAfter = (long) bundle.getDouble("timeoutAfter"); + + if (timeoutAfter != null) { + notification.setTimeoutAfter(timeoutAfter); + } + } + + Long when = (long) bundle.getDouble("when"); + + if (when != null) { + notification.setWhen(when); } + notification.setUsesChronometer(bundle.getBoolean("usesChronometer", false)); + // Override channel_id if there is one provided String customChannelId = bundle.getString("channelId"); diff --git a/example/NotifService.js b/example/NotifService.js index 86ea55eec..2cdc9989c 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -55,10 +55,15 @@ export default class NotifService { vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message + groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false ongoing: false, // (optional) set whether this is an "ongoing" notification actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true + when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null. + usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false. + timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null + /* iOS only properties */ alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string @@ -91,10 +96,15 @@ export default class NotifService { vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message + groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false ongoing: false, // (optional) set whether this is an "ongoing" notification actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: false, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true + when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null. + usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false. + timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null + /* iOS only properties */ alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string From 4c81b7684d194358fd92cc575cc043b69713539e Mon Sep 17 00:00:00 2001 From: Javi Date: Tue, 25 Aug 2020 21:46:25 +0200 Subject: [PATCH 115/179] Add help about local notifications problems --- trouble-shooting.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/trouble-shooting.md b/trouble-shooting.md index 52a764e51..4071efbea 100644 --- a/trouble-shooting.md +++ b/trouble-shooting.md @@ -7,6 +7,31 @@ Known bugs and issues: * (Android) Tapping an alert in the notification centre will sometimes not result in `onNotification` being called [issue 281](https://github.com/zo0r/react-native-push-notification/issues/281) * (Android) Not all local notification features are supported yet (PRs welcome) * (iOS) The OS can penalise your app for not calling the completion handler and will stop (or delay) sending notifications to your app. This will be supported from RN-0.38 [PR 227](https://github.com/zo0r/react-native-push-notification/pull/277) + * (Android and iOS) Don't use a string to get the date for schedule a local notification, it only works with remote debugger enabled, [explanation](https://stackoverflow.com/a/41881765/8519917). + + + ```javascript + // It doesn't works with the javascript engine used by React Native + const date = new Date("10-10-2020 12:30"); + ``` + A good practice to get valid date could be: + + ```javascript + // Get date to schedule a local notification today at 12:30:00 + const hour = 12; + const minute = 30; + const second = 0; + + const now = new Date(); + const date = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate(), + hour, + minute, + second + ); + ``` # Android tips From 3d769ad2f661432dbeaed27f031ab13bd07985d4 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 31 Aug 2020 19:06:40 +0200 Subject: [PATCH 116/179] Bump version to 5.1.0. --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8b190dca..68f8a46b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Features +### Fixed + + +## [5.1.0] 2020-08-31 + +### Features + - (Android) Add support for specifying a delegate FirebaseMessagingService [#1589](https://github.com/zo0r/react-native-push-notification/pull/1589) - (Android) Add support of `when`, `usesChronometer` and `timeoutAfter`. diff --git a/package.json b/package.json index 50daa7be1..c6a7bc55d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "5.0.1", + "version": "5.1.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 7bcbed41681afca9b1a8655f1c74cb901df9c6ad Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 2 Sep 2020 10:53:13 +0200 Subject: [PATCH 117/179] Regroup notification data inside `data` property. --- CHANGELOG.md | 2 ++ .../modules/RNPushNotification.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68f8a46b1..f23d943b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +- (Android) Fix a bug where notification data are not inside `data` property after been pressed by user. When sending notification + data and app in background. + ### Features ### Fixed 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 a70b76ea5..94bff6958 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -80,7 +80,9 @@ private Bundle getBundleFromIntent(Intent intent) { if (intent.hasExtra("notification")) { bundle = intent.getBundleExtra("notification"); } else if (intent.hasExtra("google.message_id")) { - bundle = intent.getExtras(); + bundle = new Bundle(); + + bundle.putBundle("data", intent.getExtras()); } if(null != bundle && !bundle.getBoolean("foreground", false) && !bundle.containsKey("userInteraction")) { From addd6f563372d5059400ad9ab1623352419c1f46 Mon Sep 17 00:00:00 2001 From: Steven Conaway Date: Fri, 4 Sep 2020 11:32:13 -0700 Subject: [PATCH 118/179] Add explanation to DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App` --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 82a14c3ad..47b4ccd80 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,8 @@ public class MainApplication extends Application implements ReactApplication { ## Usage **DO NOT USE `.configure()` INSIDE A COMPONENT, EVEN `App`** +> If you do, notification handlers will not fire, because they are not loaded. Instead, use `.configure()` in the app's first file, usually `index.js`. + ```javascript import PushNotificationIOS from "@react-native-community/push-notification-ios"; From bedc8f646aab67d594f291449fbfa24e07b64fe8 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 12 Sep 2020 22:39:35 +0200 Subject: [PATCH 119/179] Upgrade iOS library. --- CHANGELOG.md | 2 ++ index.js | 2 +- package.json | 4 +--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f23d943b8..a3066200c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,14 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +- `@react-native-community/push-notification-ios` is now a `peerDependency`, please make sure that you installed this library with NPM or YARN. - (Android) Fix a bug where notification data are not inside `data` property after been pressed by user. When sending notification + data and app in background. ### Features ### Fixed +- (iOS) upgrade `@react-native-community/push-notification-ios`, fixe the value of `userInteraction` [@react-native-community/push-notification-ios#122](https://github.com/react-native-community/push-notification-ios/pull/122). ## [5.1.0] 2020-08-31 diff --git a/index.js b/index.js index 072dc55ff..96a73bb92 100644 --- a/index.js +++ b/index.js @@ -350,7 +350,7 @@ Notifications._transformNotificationObject = function(data, isFromBackground = n _notification = { id: notifData?.id, foreground: !isFromBackground, - userInteraction: isFromBackground, + userInteraction: notifData?.userInteraction === 1 || false, message: data.getMessage(), data: notifData, badge: data.getBadgeCount(), diff --git a/package.json b/package.json index c6a7bc55d..0b94900a1 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,8 @@ "type": "git", "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, - "dependencies": { - "@react-native-community/push-notification-ios": "^1.4.0" - }, "peerDependencies": { + "@react-native-community/push-notification-ios": "^1.5.0", "react-native": ">=0.33" }, "author": "zo0r ", From c1880e71b95093013af82c008db566e987ce6752 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 14 Sep 2020 09:08:50 +0200 Subject: [PATCH 120/179] Fix #1641 --- CHANGELOG.md | 5 +++++ .../modules/RNPushNotificationAttributes.java | 4 ++-- .../modules/RNPushNotificationHelper.java | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68f8a46b1..3444398f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed +## [5.1.1] 2020-09-14 + +### Fixed + +- (Android) Fatal Exception: java.lang.NullPointerException [#1641](https://github.com/zo0r/react-native-push-notification/issues/1641) ## [5.1.0] 2020-08-31 diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index e0f084ba2..9017789f0 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -165,9 +165,9 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { tag = jsonObject.has(TAG) ? jsonObject.getString(TAG) : null; repeatType = jsonObject.has(REPEAT_TYPE) ? jsonObject.getString(REPEAT_TYPE) : null; repeatTime = jsonObject.has(REPEAT_TIME) ? jsonObject.getDouble(REPEAT_TIME) : 0.0; - when = jsonObject.has(WHEN) ? jsonObject.getDouble(WHEN) : null; + when = jsonObject.has(WHEN) ? jsonObject.getDouble(WHEN) : -1; usesChronometer = jsonObject.has(USES_CHRONOMETER) ? jsonObject.getBoolean(USES_CHRONOMETER) : false; - timeoutAfter = jsonObject.has(TIMEOUT_AFTER) ? jsonObject.getDouble(TIMEOUT_AFTER) : null; + timeoutAfter = jsonObject.has(TIMEOUT_AFTER) ? jsonObject.getDouble(TIMEOUT_AFTER) : -1; onlyAlertOnce = jsonObject.has(ONLY_ALERT_ONCE) ? jsonObject.getBoolean(ONLY_ALERT_ONCE) : false; ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false; allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 4e3c8040c..8b77c96c9 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -501,14 +501,14 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Long timeoutAfter = (long) bundle.getDouble("timeoutAfter"); - if (timeoutAfter != null) { + if (timeoutAfter != null && timeoutAfter >= 0) { notification.setTimeoutAfter(timeoutAfter); } } Long when = (long) bundle.getDouble("when"); - if (when != null) { + if (when != null && when >= 0) { notification.setWhen(when); } From a99269c6c09de726dec2cc3c5121d695dc247d2d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 15 Sep 2020 18:15:57 +0200 Subject: [PATCH 121/179] Upgrade to 5.1.1. --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3444398f2..ba1c58c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed -## [5.1.1] 2020-09-14 +## [5.1.1] 2020-09-15 ### Fixed diff --git a/package.json b/package.json index c6a7bc55d..466357612 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "5.1.0", + "version": "5.1.1", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From b69f67b48adb10d75ec72956adb3fd043fd36662 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 19 Sep 2020 16:22:06 +0200 Subject: [PATCH 122/179] Prepare next release --- CHANGELOG.md | 31 ++++- README.md | 63 ++--------- .../modules/RNPushNotification.java | 4 - .../modules/RNPushNotificationAttributes.java | 14 --- .../RNPushNotificationBootEventReceiver.java | 46 ++++---- .../modules/RNPushNotificationConfig.java | 25 ----- .../modules/RNPushNotificationHelper.java | 106 +++--------------- .../modules/RNReceivedMessageHandler.java | 105 +++++++++-------- example/NotifService.js | 31 ++++- .../android/app/src/main/AndroidManifest.xml | 8 +- example/ios/Podfile.lock | 2 +- example/ios/example/AppDelegate.m | 29 +++-- index.js | 8 ++ 13 files changed, 195 insertions(+), 277 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3066200c..e1cea3ed2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,37 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +- (Android) Channel Management: In order to limit the scope of responsability of this library, developers are now responsible of the creation of the channels. You can find the documentation at https://github.com/zo0r/react-native-push-notification#channel-management-android. These changes are also made to allow improvements in the future of the library. Here the list of impacts: + - You must create your channels before triggering a notification. + - These entries in `AndroidManifest` are deprecated: + ```xml + + + + ``` + - Followings options changed on Android in `localNotification` and `localNotificationSchedule`: + - `channelId` becomes mandatory (warning if not provided) + - `channelName` is deprecated + - `channelDescription` is deprecated + - `importance` is deprecated + - These changes help to avoid an issue [#1649](https://github.com/zo0r/react-native-push-notification/issues/1649) +- (Android) Remove check for the intent `BOOT_COMPLETED`, this should allow more intent action such as `QUICKBOOT_POWERON`. It's recommended to update `AndroidManifest`, the `RNPushNotificationBootEventReceiver` to: + ```xml + + + + + + + + ``` - `@react-native-community/push-notification-ios` is now a `peerDependency`, please make sure that you installed this library with NPM or YARN. - (Android) Fix a bug where notification data are not inside `data` property after been pressed by user. When sending notification + data and app in background. - -### Features +- (Android) Add more fields from the firebase notification part. (Thanks to @fattomhk with this PR [#1626](https://github.com/zo0r/react-native-push-notification/pull/1626)) + - `notificationPriority` + - `image` + - `tag` + - `visibility` ### Fixed diff --git a/README.md b/README.md index 82a14c3ad..fa33431f3 100644 --- a/README.md +++ b/README.md @@ -89,17 +89,9 @@ In your `android/app/src/main/AndroidManifest.xml` - - - - - @@ -109,6 +101,8 @@ In your `android/app/src/main/AndroidManifest.xml` + + @@ -307,6 +301,7 @@ EXAMPLE: ```javascript PushNotification.localNotification({ /* Android Only Properties */ + channelId: "your-channel-id", // (required) channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. ticker: "My Notification Ticker", // (optional) showWhen: true, // (optional) default: true autoCancel: true, // (optional) default: true @@ -325,10 +320,8 @@ PushNotification.localNotification({ ongoing: false, // (optional) set whether this is an "ongoing" notification priority: "high", // (optional) set notification priority, default: high visibility: "private", // (optional) set notification visibility, default: private - importance: "high", // (optional) set notification importance, default: high ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined - channelId: "your-custom-channel-id", // (optional) custom channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel. onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null. @@ -337,7 +330,7 @@ PushNotification.localNotification({ messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module. - actions: '["Yes", "No"]', // (Android only) See the doc for notification actions to know more + actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ @@ -395,14 +388,14 @@ In the location notification json specify the full file name: ## Channel Management (Android) -To use custom channels, create them at startup and pass the matching `channelId` through to `PushNotification.localNotification` +To use channels, create them at startup and pass the matching `channelId` through to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. ```javascript PushNotification.createChannel( { - channelId: "custom-channel-id", // (required) - channelName: "Custom channel", // (required) - channelDescription: "A custom channel to categorise your custom notifications", // (optional) default: undefined. + channelId: "channel-id", // (required) + channelName: "My channel", // (required) + channelDescription: "A channel to categorise your notifications", // (optional) default: undefined. soundName: "default", // (optional) See `soundName` parameter of `localNotification` function importance: 4, // (optional) default: 4. Int value of the Android notification importance vibrate: true, // (optional) default: true. Creates the default vibration patten if true. @@ -411,47 +404,9 @@ To use custom channels, create them at startup and pass the matching `channelId` ); ``` -Channels with ids that do not exist are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. - -The pattern of `channel_id` is: - -``` -rn-push-notification-channel-id-(importance: default "4")(-soundname, default if playSound "-default")-(vibration, default "300") -``` - -By default, 1 channel is created: - -- rn-push-notification-channel-id-4-default-300 (used for remote notification if none already exist). - -you can avoid the default creation by using this: - -```xml - -``` - **NOTE: Without channel, remote notifications don't work** -In the notifications options, you can provide a custom channel id with `channelId: "your-custom-channel-id"`, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your `channelId` is different if you change these options. If you have created a custom channel in another way, it will apply options of the channel. - -Custom and generated channels can have custom name and description in the `AndroidManifest.xml`, only if the library is responsible of the creation of the channel. -You can also use `channelName` and `channelDescription` when you use to override the name or description. Once the channel is created, you won't be able to update them. - -```xml - - -``` - -For example: - -```xml - - -``` +In the notifications options, you must provide a channel id with `channelId: "your-channel-id"`, if the channel doesn't exist the notification might not e triggered. Once the channel is created, the channel cannot be update. Make sure your `channelId` is different if you change these options. If you have created a channel in another way, it will apply options of the channel. If you want to use a different default channel for remote notification, refer to the documentation of Firebase: 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 94bff6958..f0d4eed87 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -57,12 +57,8 @@ public RNPushNotification(ReactApplicationContext reactContext) { mRNPushNotificationHelper = new RNPushNotificationHelper(applicationContext); // This is used to delivery callbacks to JS mJsDelivery = new RNPushNotificationJsDelivery(reactContext); - - mRNPushNotificationHelper.checkOrCreateDefaultChannel(); } - - @Override public String getName() { return "RNPushNotification"; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index e0f084ba2..80331960d 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -28,8 +28,6 @@ public class RNPushNotificationAttributes { private static final String BIG_PICTURE_URL = "bigPictureUrl"; private static final String SHORTCUT_ID = "shortcutId"; private static final String CHANNEL_ID = "channelId"; - private static final String CHANNEL_NAME = "channelName"; - private static final String CHANNEL_DESCRIPTION = "channelDescription"; private static final String NUMBER = "number"; private static final String SOUND = "sound"; private static final String COLOR = "color"; @@ -68,8 +66,6 @@ public class RNPushNotificationAttributes { private final String shortcutId; private final String number; private final String channelId; - private final String channelName; - private final String channelDescription; private final String sound; private final String color; private final String group; @@ -108,8 +104,6 @@ public RNPushNotificationAttributes(Bundle bundle) { shortcutId = bundle.getString(SHORTCUT_ID); number = bundle.getString(NUMBER); channelId = bundle.getString(CHANNEL_ID); - channelName = bundle.getString(CHANNEL_NAME); - channelDescription = bundle.getString(CHANNEL_DESCRIPTION); sound = bundle.getString(SOUND); color = bundle.getString(COLOR); group = bundle.getString(GROUP); @@ -150,8 +144,6 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { shortcutId = jsonObject.has(SHORTCUT_ID) ? jsonObject.getString(SHORTCUT_ID) : null; number = jsonObject.has(NUMBER) ? jsonObject.getString(NUMBER) : null; channelId = jsonObject.has(CHANNEL_ID) ? jsonObject.getString(CHANNEL_ID) : null; - channelName = jsonObject.has(CHANNEL_NAME) ? jsonObject.getString(CHANNEL_NAME) : null; - channelDescription = jsonObject.has(CHANNEL_DESCRIPTION) ? jsonObject.getString(CHANNEL_DESCRIPTION) : null; sound = jsonObject.has(SOUND) ? jsonObject.getString(SOUND) : null; color = jsonObject.has(COLOR) ? jsonObject.getString(COLOR) : null; group = jsonObject.has(GROUP) ? jsonObject.getString(GROUP) : null; @@ -249,8 +241,6 @@ public Bundle toBundle() { bundle.putString(SHORTCUT_ID, shortcutId); bundle.putString(NUMBER, number); bundle.putString(CHANNEL_ID, channelId); - bundle.putString(CHANNEL_NAME, channelName); - bundle.putString(CHANNEL_DESCRIPTION, channelDescription); bundle.putString(SOUND, sound); bundle.putString(COLOR, color); bundle.putString(GROUP, group); @@ -293,8 +283,6 @@ public JSONObject toJson() { jsonObject.put(SHORTCUT_ID, shortcutId); jsonObject.put(NUMBER, number); jsonObject.put(CHANNEL_ID, channelId); - jsonObject.put(CHANNEL_NAME, channelName); - jsonObject.put(CHANNEL_DESCRIPTION, channelDescription); jsonObject.put(SOUND, sound); jsonObject.put(COLOR, color); jsonObject.put(GROUP, group); @@ -343,8 +331,6 @@ public String toString() { ", shortcutId='" + shortcutId + '\'' + ", number='" + number + '\'' + ", channelId='" + channelId + '\'' + - ", channelName='" + channelId + '\'' + - ", channelDescription='" + channelDescription + '\'' + ", sound='" + sound + '\'' + ", color='" + color + '\'' + ", group='" + group + '\'' + diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java index bae277585..6552a87ec 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationBootEventReceiver.java @@ -20,32 +20,30 @@ public class RNPushNotificationBootEventReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver loading scheduled notifications"); - if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) { - SharedPreferences sharedPreferences = context.getSharedPreferences(RNPushNotificationHelper.PREFERENCES_KEY, Context.MODE_PRIVATE); - Set ids = sharedPreferences.getAll().keySet(); - - Application applicationContext = (Application) context.getApplicationContext(); - RNPushNotificationHelper rnPushNotificationHelper = new RNPushNotificationHelper(applicationContext); - - for (String id : ids) { - try { - String notificationAttributesJson = sharedPreferences.getString(id, null); - if (notificationAttributesJson != null) { - RNPushNotificationAttributes notificationAttributes = RNPushNotificationAttributes.fromJson(notificationAttributesJson); - - if (notificationAttributes.getFireDate() < System.currentTimeMillis()) { - Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Showing notification for " + - notificationAttributes.getId()); - rnPushNotificationHelper.sendToNotificationCentre(notificationAttributes.toBundle()); - } else { - Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Scheduling notification for " + - notificationAttributes.getId()); - rnPushNotificationHelper.sendNotificationScheduledCore(notificationAttributes.toBundle()); - } + SharedPreferences sharedPreferences = context.getSharedPreferences(RNPushNotificationHelper.PREFERENCES_KEY, Context.MODE_PRIVATE); + Set ids = sharedPreferences.getAll().keySet(); + + Application applicationContext = (Application) context.getApplicationContext(); + RNPushNotificationHelper rnPushNotificationHelper = new RNPushNotificationHelper(applicationContext); + + for (String id : ids) { + try { + String notificationAttributesJson = sharedPreferences.getString(id, null); + if (notificationAttributesJson != null) { + RNPushNotificationAttributes notificationAttributes = RNPushNotificationAttributes.fromJson(notificationAttributesJson); + + if (notificationAttributes.getFireDate() < System.currentTimeMillis()) { + Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Showing notification for " + + notificationAttributes.getId()); + rnPushNotificationHelper.sendToNotificationCentre(notificationAttributes.toBundle()); + } else { + Log.i(LOG_TAG, "RNPushNotificationBootEventReceiver: Scheduling notification for " + + notificationAttributes.getId()); + rnPushNotificationHelper.sendNotificationScheduledCore(notificationAttributes.toBundle()); } - } catch (Exception e) { - Log.e(LOG_TAG, "Problem with boot receiver loading notification " + id, e); } + } catch (Exception e) { + Log.e(LOG_TAG, "Problem with boot receiver loading notification " + id, e); } } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index cdd5be61e..55a508746 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -8,9 +8,6 @@ import android.util.Log; class RNPushNotificationConfig { - private static final String KEY_CHANNEL_CREATE_DEFAULT = "com.dieam.reactnativepushnotification.channel_create_default"; - private static final String KEY_CHANNEL_NAME = "com.dieam.reactnativepushnotification.notification_channel_name"; - private static final String KEY_CHANNEL_DESCRIPTION = "com.dieam.reactnativepushnotification.notification_channel_description"; private static final String KEY_NOTIFICATION_FOREGROUND = "com.dieam.reactnativepushnotification.notification_foreground"; private static final String KEY_NOTIFICATION_COLOR = "com.dieam.reactnativepushnotification.notification_color"; @@ -46,18 +43,6 @@ private String getStringValue(String key, String defaultValue) { return defaultValue; } - public String getChannelName(String channel_id) { - String overrided = this.getStringValue(KEY_CHANNEL_NAME, "rn-push-notification-channel"); - - return this.getStringValue(KEY_CHANNEL_NAME + "." + channel_id, overrided); - } - - public String getChannelDescription(String channel_id) { - String overrided = this.getStringValue(KEY_CHANNEL_DESCRIPTION, ""); - - return this.getStringValue(KEY_CHANNEL_DESCRIPTION + "." + channel_id, overrided); - } - public int getNotificationColor() { try { int resourceId = metadata.getInt(KEY_NOTIFICATION_COLOR); @@ -78,14 +63,4 @@ public boolean getNotificationForeground() { // Default return false; } - - public boolean getChannelCreateDefault() { - try { - return metadata.getBoolean(KEY_CHANNEL_CREATE_DEFAULT, true); - } catch (Exception e) { - Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_CHANNEL_CREATE_DEFAULT + " in manifest. Falling back to default"); - } - // Default - return true; - } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 4e3c8040c..b8764e32a 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -50,7 +50,6 @@ public class RNPushNotificationHelper { public static final String PREFERENCES_KEY = "rn_push_notification"; private static final long DEFAULT_VIBRATION = 300L; - private static final String NOTIFICATION_CHANNEL_ID = "rn-push-notification-channel-id"; private Context context; private RNPushNotificationConfig config; @@ -219,8 +218,6 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Resources res = context.getResources(); String packageName = context.getPackageName(); - String channel_id = NOTIFICATION_CHANNEL_ID; - String title = bundle.getString("title"); if (title == null) { ApplicationInfo appInfo = context.getApplicationInfo(); @@ -252,44 +249,6 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB } } - int importance = 4; // Same as HIGH for lower version - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - importance = NotificationManager.IMPORTANCE_HIGH; - - final String importanceString = bundle.getString("importance"); - - if (importanceString != null) { - switch (importanceString.toLowerCase()) { - case "default": - importance = NotificationManager.IMPORTANCE_DEFAULT; - break; - case "max": - importance = NotificationManager.IMPORTANCE_MAX; - break; - case "high": - importance = NotificationManager.IMPORTANCE_HIGH; - break; - case "low": - importance = NotificationManager.IMPORTANCE_LOW; - break; - case "min": - importance = NotificationManager.IMPORTANCE_MIN; - break; - case "none": - importance = NotificationManager.IMPORTANCE_NONE; - break; - case "unspecified": - importance = NotificationManager.IMPORTANCE_UNSPECIFIED; - break; - default: - importance = NotificationManager.IMPORTANCE_HIGH; - } - } - } - - channel_id = channel_id + "-" + importance; - int visibility = NotificationCompat.VISIBILITY_PRIVATE; final String visibilityString = bundle.getString("visibility"); @@ -308,7 +267,9 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB visibility = NotificationCompat.VISIBILITY_PRIVATE; } } - + + String channel_id = bundle.getString("channelId"); + NotificationCompat.Builder notification = new NotificationCompat.Builder(context, channel_id) .setContentTitle(title) .setTicker(bundle.getString("ticker")) @@ -437,16 +398,13 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { String soundName = bundle.getString("soundName"); + if (soundName == null) { soundName = "default"; } soundUri = getSoundUri(soundName); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher - channel_id = channel_id + "-" + soundName; - } - notification.setSound(soundUri); } @@ -484,8 +442,6 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (vibration == 0) vibration = DEFAULT_VIBRATION; - channel_id = channel_id + "-" + vibration; - vibratePattern = new long[]{0, vibration}; notification.setVibrate(vibratePattern); @@ -514,19 +470,6 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB notification.setUsesChronometer(bundle.getBoolean("usesChronometer", false)); - // Override channel_id if there is one provided - String customChannelId = bundle.getString("channelId"); - - if (customChannelId != null) { - channel_id = customChannelId; - } - - // Override channel_name, channel_description if there is one provided - String channel_name = bundle.getString("channelName"); - String channel_description = bundle.getString("channelDescription"); - - checkOrCreateChannel(notificationManager, channel_id, channel_name, channel_description, soundUri, importance, vibratePattern); - notification.setChannelId(channel_id); notification.setContentIntent(pendingIntent); @@ -844,26 +787,6 @@ private NotificationManager notificationManager() { return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } - public void checkOrCreateDefaultChannel() { - if(!this.config.getChannelCreateDefault()) { - return; - } - - NotificationManager manager = notificationManager(); - - int importance = 4; // Default value of HIGH for lower version - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - importance = NotificationManager.IMPORTANCE_HIGH; - } - - Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - - // Instanciate a default channel with default sound. - String channel_id_sound = NOTIFICATION_CHANNEL_ID + "-" + importance + "-default-" + DEFAULT_VIBRATION; - checkOrCreateChannel(manager, channel_id_sound, null, null, soundUri, importance, new long[] {0, DEFAULT_VIBRATION}); - } - public List listChannels() { List channels = new ArrayList<>(); @@ -935,15 +858,14 @@ private boolean checkOrCreateChannel(NotificationManager manager, String channel NotificationChannel channel = manager.getNotificationChannel(channel_id); - if(channel_name == null) { - channel_name = this.config.getChannelName(channel_id); - } - - if(channel_description == null) { - channel_description = this.config.getChannelDescription(channel_id); - } - - if (channel == null || !channel.getName().equals(channel_name) || !channel.getDescription().equals(channel_description)) { + if ( + channel == null && channel_name != null && channel_description != null || + channel != null && + ( + channel_name != null && !channel.getName().equals(channel_name) || + channel_description != null && !channel.getDescription().equals(channel_description) + ) + ) { // If channel doesn't exist create a new one. // If channel name or description is updated then update the existing channel. channel = new NotificationChannel(channel_id, channel_name, importance); @@ -965,8 +887,10 @@ private boolean checkOrCreateChannel(NotificationManager manager, String channel } manager.createNotificationChannel(channel); + return true; } + return false; } @@ -976,7 +900,7 @@ public boolean createChannel(ReadableMap channelInfo) { String channelId = channelInfo.getString("channelId"); String channelName = channelInfo.getString("channelName"); - String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : null; + String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : ""; String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 13402c1c5..a1d014cde 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -10,7 +10,9 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; +import android.net.Uri; import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; import com.dieam.reactnativepushnotification.helpers.ApplicationBadgeHelper; import com.facebook.react.ReactApplication; @@ -46,6 +48,55 @@ public void handleReceivedMessage(RemoteMessage message) { bundle.putString("message", remoteNotification.getBody()); bundle.putString("sound", remoteNotification.getSound()); bundle.putString("color", remoteNotification.getColor()); + bundle.putString("tag", remoteNotification.getTag()); + bundle.putString("channelId", remoteNotification.getChannelId()); + + Integer visibilty = remoteNotification.getVisibility(); + String visibilityString = "private"; + + if (visibilty != null) { + switch (visibilty) { + case NotificationCompat.VISIBILITY_PUBLIC: + visibilityString = "public"; + break; + case NotificationCompat.VISIBILITY_SECRET: + visibilityString = "secret"; + break; + } + } + + bundle.putString("visibility", visibilityString); + + Integer priority = remoteNotification.getNotificationPriority(); + String priorityString = "high"; + + if (priority != null) { + switch (priority) { + case NotificationCompat.PRIORITY_MAX: + priorityString = "max"; + break; + case NotificationCompat.PRIORITY_LOW: + priorityString = "low"; + break; + case NotificationCompat.PRIORITY_MIN: + priorityString = "min"; + break; + case NotificationCompat.PRIORITY_DEFAULT: + priorityString = "default"; + break; + } + } + + bundle.putString("priority", priorityString); + + Uri uri = remoteNotification.getImageUrl(); + + if(uri != null) { + String imageUrl = uri.toString(); + + bundle.putString("bigPictureUrl", imageUrl); + bundle.putString("largeIconUrl", imageUrl); + } } Map notificationData = message.getData(); @@ -54,32 +105,13 @@ public void handleReceivedMessage(RemoteMessage message) { if (notificationData.containsKey("twi_body")) { bundle.putString("message", notificationData.get("twi_body")); } - JSONObject data = getPushData(notificationData.get("data")); - - if (data != null) { - if (!bundle.containsKey("message")) { - bundle.putString("message", data.optString("alert", null)); - } - if (!bundle.containsKey("title")) { - bundle.putString("title", data.optString("title", null)); - } - if (!bundle.containsKey("sound")) { - bundle.putString("soundName", data.optString("sound", null)); - } - if (!bundle.containsKey("color")) { - bundle.putString("color", data.optString("color", null)); - } - - final int badge = data.optInt("badge", -1); - if (badge >= 0) { - ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(mFirebaseMessagingService, badge); - } - } Bundle dataBundle = new Bundle(); + for(Map.Entry entry : notificationData.entrySet()) { dataBundle.putString(entry.getKey(), entry.getValue()); } + bundle.putParcelable("data", dataBundle); Log.v(LOG_TAG, "onMessageReceived: " + bundle); @@ -113,14 +145,6 @@ public void onReactContextInitialized(ReactContext context) { }); } - private JSONObject getPushData(String dataString) { - try { - return new JSONObject(dataString); - } catch (Exception e) { - return null; - } - } - private void handleRemotePushNotification(ReactApplicationContext context, Bundle bundle) { // If notification ID is not provided by the user for push notification, generate one at random @@ -129,9 +153,12 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl bundle.putString("id", String.valueOf(randomNumberGenerator.nextInt())); } + Application applicationContext = (Application) context.getApplicationContext(); + RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); + RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); - boolean isForeground = isApplicationInForeground(); + boolean isForeground = pushNotificationHelper.isApplicationInForeground(); RNPushNotificationJsDelivery jsDelivery = new RNPushNotificationJsDelivery(context); bundle.putBoolean("foreground", isForeground); @@ -146,25 +173,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl if (config.getNotificationForeground() || !isForeground) { Log.v(LOG_TAG, "sendNotification: " + bundle); - Application applicationContext = (Application) context.getApplicationContext(); - RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); pushNotificationHelper.sendToNotificationCentre(bundle); } } - - private boolean isApplicationInForeground() { - ActivityManager activityManager = (ActivityManager) mFirebaseMessagingService.getSystemService(ACTIVITY_SERVICE); - List processInfos = activityManager.getRunningAppProcesses(); - if (processInfos != null) { - for (RunningAppProcessInfo processInfo : processInfos) { - if (processInfo.processName.equals(mFirebaseMessagingService.getPackageName()) - && processInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND - && processInfo.pkgList.length > 0) { - return true; - } - } - } - return false; - } - } diff --git a/example/NotifService.js b/example/NotifService.js index 2cdc9989c..c9ed55b7b 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -6,6 +6,8 @@ export default class NotifService { this.lastId = 0; this.lastChannelCounter = 0; + this.createDefaultChannels(); + NotificationHandler.attachRegister(onRegister); NotificationHandler.attachNotification(onNotification); @@ -21,6 +23,31 @@ export default class NotifService { }); } + createDefaultChannels() { + PushNotification.createChannel( + { + channelId: "default-channel-id", // (required) + channelName: `Default channel`, // (required) + channelDescription: "A default channel", // (optional) default: undefined. + soundName: "default", // (optional) See `soundName` parameter of `localNotification` function + importance: 4, // (optional) default: 4. Int value of the Android notification importance + vibrate: true, // (optional) default: true. Creates the default vibration patten if true. + }, + (created) => console.log(`createChannel 'default-channel-id' returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + ); + PushNotification.createChannel( + { + channelId: "sound-channel-id", // (required) + channelName: `Sound channel`, // (required) + channelDescription: "A sound channel", // (optional) default: undefined. + soundName: "sample.mp3", // (optional) See `soundName` parameter of `localNotification` function + importance: 4, // (optional) default: 4. Int value of the Android notification importance + vibrate: true, // (optional) default: true. Creates the default vibration patten if true. + }, + (created) => console.log(`createChannel 'sound-channel-id' returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + ); + } + createOrUpdateChannel() { this.lastChannelCounter++; PushNotification.createChannel( @@ -44,6 +71,7 @@ export default class NotifService { this.lastId++; PushNotification.localNotification({ /* Android Only Properties */ + channelId: soundName ? 'sound-channel-id' : 'default-channel-id', ticker: 'My Notification Ticker', // (optional) autoCancel: true, // (optional) default: true largeIcon: 'ic_launcher', // (optional) default: "ic_launcher" @@ -85,6 +113,7 @@ export default class NotifService { date: new Date(Date.now() + 30 * 1000), // in 30 secs /* Android Only Properties */ + channelId: soundName ? 'sound-channel-id' : 'default-channel-id', ticker: 'My Notification Ticker', // (optional) autoCancel: true, // (optional) default: true largeIcon: 'ic_launcher', // (optional) default: "ic_launcher" @@ -115,8 +144,8 @@ export default class NotifService { message: 'My Notification Message', // (required) userInfo: { sceen: "home" }, // (optional) default: {} (using null throws a JSON value '' error) playSound: !!soundName, // (optional) default: true - number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) soundName: soundName ? soundName : 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) + number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) }); } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 584fa4be9..7e9056b6f 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -32,6 +32,8 @@ + + @@ -43,14 +45,8 @@ - - - diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1ef8335cd..325f7f657 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -459,4 +459,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 56c2537f71f3f02200d6918c542a8e89a0b422fa -COCOAPODS: 1.9.3 +COCOAPODS: 1.9.1 diff --git a/example/ios/example/AppDelegate.m b/example/ios/example/AppDelegate.m index 0e513c62e..4ac2f6fba 100644 --- a/example/ios/example/AppDelegate.m +++ b/example/ios/example/AppDelegate.m @@ -40,7 +40,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // Define UNUserNotificationCenter UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - center.delegate = self; + + [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (granted) { + center.delegate = self; + } + }]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; @@ -52,6 +57,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( return YES; } +-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +{ + completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); +} + // Required to register for notifications - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { @@ -73,17 +83,22 @@ - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotif { [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error]; } -// Required for the localNotification event. -- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification + +// IOS 10+ Required for localNotification event +- (void)userNotificationCenter:(UNUserNotificationCenter *)center +didReceiveNotificationResponse:(UNNotificationResponse *)response + withCompletionHandler:(void (^)(void))completionHandler { - [RNCPushNotificationIOS didReceiveLocalNotification:notification]; + [RNCPushNotificationIOS didReceiveNotificationResponse:response]; + completionHandler(); } -//Called when a notification is delivered to a foreground app. --(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +// IOS 4-10 Required for the localNotification event. +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { - completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); + [RNCPushNotificationIOS didReceiveLocalNotification:notification]; } + - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG diff --git a/index.js b/index.js index 96a73bb92..6bf716afa 100644 --- a/index.js +++ b/index.js @@ -146,6 +146,10 @@ Notifications.unregister = function() { * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert. */ Notifications.localNotification = function(details) { + if ('android' === Platform.os && details && !details.channelId) { + console.warn('No channel id passed, notifications may not work.'); + } + if (details && typeof details.id === 'number') { if (isNaN(details.id)) { console.warn('NaN value has been passed as id'); @@ -218,6 +222,10 @@ Notifications.localNotification = function(details) { * @param {Date} details.date - The date and time when the system should deliver the notification */ Notifications.localNotificationSchedule = function(details) { + if ('android' === Platform.os && details && !details.channelId) { + console.warn('No channel id passed, notifications may not work.'); + } + if (details && typeof details.id === 'number') { if(isNaN(details.id)) { console.warn('NaN value has been passed as id'); From a4ba5baa2cd4d2e137c4b43e433492fad3a4cb59 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 23 Sep 2020 23:24:03 +0200 Subject: [PATCH 123/179] Revert #744. --- CHANGELOG.md | 1 + .../modules/RNPushNotificationHelper.java | 2 +- .../modules/RNReceivedMessageHandler.java | 8 +------- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1cea3ed2..d9ad85c75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html - `image` - `tag` - `visibility` +- (Android) `data.twi_body` is no more used to trigger a notification in notification-center. Revert of [#744](https://github.com/zo0r/react-native-push-notification/pull/744) ### Fixed diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index b8764e32a..a44581278 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -205,7 +205,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (bundle.getString("message") == null) { // this happens when a 'data' notification is received - we do not synthesize a local notification in this case - Log.d(LOG_TAG, "Cannot send to notification centre because there is no 'message' field in: " + bundle); + Log.d(LOG_TAG, "Ignore this message if you sent data-only notification. Cannot send to notification centre because there is no 'message' field in: " + bundle); return; } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index a1d014cde..aaed5f823 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -99,14 +99,8 @@ public void handleReceivedMessage(RemoteMessage message) { } } - Map notificationData = message.getData(); - - // Copy `twi_body` to `message` to support Twilio - if (notificationData.containsKey("twi_body")) { - bundle.putString("message", notificationData.get("twi_body")); - } - Bundle dataBundle = new Bundle(); + Map notificationData = message.getData(); for(Map.Entry entry : notificationData.entrySet()) { dataBundle.putString(entry.getKey(), entry.getValue()); From a32a63c496c506b3aa589a2628d110515c2e7914 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 26 Sep 2020 18:18:44 +0200 Subject: [PATCH 124/179] Wrong CHANGELOG. --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5460f9e96..20647bcf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +### Features + +### Fixed + +## [6.0.0] 2020-09-26 + +### Breaking changes + - (Android) Channel Management: In order to limit the scope of responsability of this library, developers are now responsible of the creation of the channels. You can find the documentation at https://github.com/zo0r/react-native-push-notification#channel-management-android. These changes are also made to allow improvements in the future of the library. Here the list of impacts: - You must create your channels before triggering a notification. - These entries in `AndroidManifest` are deprecated: @@ -43,15 +51,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed -<<<<<<< HEAD - (iOS) upgrade `@react-native-community/push-notification-ios`, fixe the value of `userInteraction` [@react-native-community/push-notification-ios#122](https://github.com/react-native-community/push-notification-ios/pull/122). -======= + ## [5.1.1] 2020-09-15 ### Fixed - (Android) Fatal Exception: java.lang.NullPointerException [#1641](https://github.com/zo0r/react-native-push-notification/issues/1641) ->>>>>>> master ## [5.1.0] 2020-08-31 From a9e3ab8292bdc87337b1d76aca867a5d2bb6a562 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 28 Sep 2020 18:34:35 +0200 Subject: [PATCH 125/179] Prevent this issue #1671. --- .../modules/RNReceivedMessageHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index aaed5f823..5a9512906 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -49,7 +49,13 @@ public void handleReceivedMessage(RemoteMessage message) { bundle.putString("sound", remoteNotification.getSound()); bundle.putString("color", remoteNotification.getColor()); bundle.putString("tag", remoteNotification.getTag()); - bundle.putString("channelId", remoteNotification.getChannelId()); + + if(remoteNotification.getChannelId() != null) { + bundle.putString("channelId", remoteNotification.getChannelId()); + } + else { + bundle.putString("channelId", "fcm_fallback_notification_channel"); + } Integer visibilty = remoteNotification.getVisibility(); String visibilityString = "private"; From 7b5f945c1a6c89bd7820c7462caa30289f6b2379 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 28 Sep 2020 23:11:51 +0200 Subject: [PATCH 126/179] Allow to define a default channel in AndroidManifest, useful for foreground notification. --- CHANGELOG.md | 14 ++++++++++++++ README.md | 16 ++++++++++++++++ .../modules/RNPushNotificationConfig.java | 14 ++++++++++++++ .../modules/RNPushNotificationHelper.java | 4 ++++ .../modules/RNReceivedMessageHandler.java | 7 ++++--- package.json | 2 +- 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20647bcf0..1e020276e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,20 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed +## [6.1.0] 2020-09-28 + +### Features + +- (Android) Allow a default channel in the `AndroidManifest`: + ```xml + + ``` + If not defined, fallback to the Firebase value of: + ```xml + + ``` + If not defined, fallback to the default Firebase channel id `fcm_fallback_notification_channel` + ## [6.0.0] 2020-09-26 ### Breaking changes diff --git a/README.md b/README.md index 84ce67511..f0f809a43 100644 --- a/README.md +++ b/README.md @@ -420,6 +420,22 @@ If you want to use a different default channel for remote notification, refer to android:value="@string/default_notification_channel_id" /> ``` +For local notifications, the same kind of option is available: + +- you can use: + ```xml + + ``` +- If not defined, fallback to the Firebase value defined in the `AndroidManifest`: + ```xml + + ``` +- If not defined, fallback to the default Firebase channel id `fcm_fallback_notification_channel` + ### List channels You can list available channels with: diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java index 55a508746..e17927753 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationConfig.java @@ -8,6 +8,8 @@ import android.util.Log; class RNPushNotificationConfig { + private static final String KEY_NOTIFICATION_FIREBASE_DEFAULT_CHANNEL_ID = "com.google.firebase.messaging.default_notification_channel_id"; + private static final String KEY_NOTIFICATION_DEFAULT_CHANNEL_ID = "com.dieam.reactnativepushnotification.default_notification_channel_id"; private static final String KEY_NOTIFICATION_FOREGROUND = "com.dieam.reactnativepushnotification.notification_foreground"; private static final String KEY_NOTIFICATION_COLOR = "com.dieam.reactnativepushnotification.notification_color"; @@ -63,4 +65,16 @@ public boolean getNotificationForeground() { // Default return false; } + + public String getNotificationDefaultChannelId() { + try { + return getStringValue(KEY_NOTIFICATION_DEFAULT_CHANNEL_ID, + getStringValue(KEY_NOTIFICATION_FIREBASE_DEFAULT_CHANNEL_ID, "fcm_fallback_notification_channel") + ); + } catch (Exception e) { + Log.w(RNPushNotification.LOG_TAG, "Unable to find " + KEY_NOTIFICATION_DEFAULT_CHANNEL_ID + " in manifest. Falling back to default"); + } + // Default + return "fcm_fallback_notification_channel"; + } } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 491010215..5fa8feb5c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -269,6 +269,10 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB } String channel_id = bundle.getString("channelId"); + + if(channel_id == null) { + channel_id = this.config.getNotificationDefaultChannelId(); + } NotificationCompat.Builder notification = new NotificationCompat.Builder(context, channel_id) .setContentTitle(title) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 5a9512906..7c2396026 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -31,9 +31,11 @@ public class RNReceivedMessageHandler { private FirebaseMessagingService mFirebaseMessagingService; + private RNPushNotificationConfig config; public RNReceivedMessageHandler(@NonNull FirebaseMessagingService service) { this.mFirebaseMessagingService = service; + this.config = new RNPushNotificationConfig(service.getApplication()); } public void handleReceivedMessage(RemoteMessage message) { @@ -54,7 +56,7 @@ public void handleReceivedMessage(RemoteMessage message) { bundle.putString("channelId", remoteNotification.getChannelId()); } else { - bundle.putString("channelId", "fcm_fallback_notification_channel"); + bundle.putString("channelId", this.config.getNotificationDefaultChannelId()); } Integer visibilty = remoteNotification.getVisibility(); @@ -155,7 +157,6 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl Application applicationContext = (Application) context.getApplicationContext(); - RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); boolean isForeground = pushNotificationHelper.isApplicationInForeground(); @@ -170,7 +171,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl jsDelivery.notifyRemoteFetch(bundle); } - if (config.getNotificationForeground() || !isForeground) { + if (this.config.getNotificationForeground() || !isForeground) { Log.v(LOG_TAG, "sendNotification: " + bundle); pushNotificationHelper.sendToNotificationCentre(bundle); diff --git a/package.json b/package.json index 89f988425..d2d7be879 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "6.0.0", + "version": "6.1.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From e80d36af2557a35252f4e2c572ab6b06d3d970d7 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 29 Sep 2020 12:21:46 +0200 Subject: [PATCH 127/179] Fix #1676 --- CHANGELOG.md | 6 ++++++ .../modules/RNReceivedMessageHandler.java | 11 ++++++----- package.json | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e020276e..c252b9abd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed +## [6.1.1] 2020-09-29 + +### Fixed + +- (Android) Fix a crash when the application is in background [#1676](https://github.com/zo0r/react-native-push-notification/issues/1676) + ## [6.1.0] 2020-09-28 ### Features diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java index 7c2396026..1c9247165 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNReceivedMessageHandler.java @@ -31,11 +31,9 @@ public class RNReceivedMessageHandler { private FirebaseMessagingService mFirebaseMessagingService; - private RNPushNotificationConfig config; public RNReceivedMessageHandler(@NonNull FirebaseMessagingService service) { this.mFirebaseMessagingService = service; - this.config = new RNPushNotificationConfig(service.getApplication()); } public void handleReceivedMessage(RemoteMessage message) { @@ -46,17 +44,19 @@ public void handleReceivedMessage(RemoteMessage message) { // data has it if (remoteNotification != null) { // ^ It's null when message is from GCM + RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); + bundle.putString("title", remoteNotification.getTitle()); bundle.putString("message", remoteNotification.getBody()); bundle.putString("sound", remoteNotification.getSound()); bundle.putString("color", remoteNotification.getColor()); bundle.putString("tag", remoteNotification.getTag()); - + if(remoteNotification.getChannelId() != null) { bundle.putString("channelId", remoteNotification.getChannelId()); } else { - bundle.putString("channelId", this.config.getNotificationDefaultChannelId()); + bundle.putString("channelId", config.getNotificationDefaultChannelId()); } Integer visibilty = remoteNotification.getVisibility(); @@ -157,6 +157,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl Application applicationContext = (Application) context.getApplicationContext(); + RNPushNotificationConfig config = new RNPushNotificationConfig(mFirebaseMessagingService.getApplication()); RNPushNotificationHelper pushNotificationHelper = new RNPushNotificationHelper(applicationContext); boolean isForeground = pushNotificationHelper.isApplicationInForeground(); @@ -171,7 +172,7 @@ private void handleRemotePushNotification(ReactApplicationContext context, Bundl jsDelivery.notifyRemoteFetch(bundle); } - if (this.config.getNotificationForeground() || !isForeground) { + if (config.getNotificationForeground() || !isForeground) { Log.v(LOG_TAG, "sendNotification: " + bundle); pushNotificationHelper.sendToNotificationCentre(bundle); diff --git a/package.json b/package.json index d2d7be879..644fd4675 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "6.1.0", + "version": "6.1.1", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 60883d102caa4c29668d4c0bcbe885a7a9516b8b Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 3 Oct 2020 12:15:52 +0200 Subject: [PATCH 128/179] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0f809a43..579f9df4d 100644 --- a/README.md +++ b/README.md @@ -406,7 +406,7 @@ To use channels, create them at startup and pass the matching `channelId` throug ); ``` -**NOTE: Without channel, remote notifications don't work** +**NOTE: Without channel, notifications don't work** In the notifications options, you must provide a channel id with `channelId: "your-channel-id"`, if the channel doesn't exist the notification might not e triggered. Once the channel is created, the channel cannot be update. Make sure your `channelId` is different if you change these options. If you have created a channel in another way, it will apply options of the channel. From b89eb226d2279195368a891bddf0e825a6130616 Mon Sep 17 00:00:00 2001 From: Nesh Patel Date: Sun, 4 Oct 2020 12:47:11 +0100 Subject: [PATCH 129/179] This fixes the vibration feature for notification for Android notifications for API >= 26. This pattern is used for the Notif Builder for API < 26 and it appears to work there as well. Before: ``` 2020-10-04 12:37:03.630 1936-29464/? E/VibratorService: vibratorOff command failed (1). 2020-10-04 12:37:03.935 1936-29476/? E/VibratorService: vibratorOff command failed (1). ``` After: ``` 2020-10-04 12:07:16.037 1936-4760/? E/VibratorService: vibratorOff command failed (1). 2020-10-04 12:07:16.037 1936-4760/? E/VibratorService: vibratorOn command failed (1). 2020-10-04 12:07:16.438 1936-1936/? E/VibratorService: vibratorOff command failed (1). ``` Have tested this on a physical device as well and it works. This could lead to an obvious extension which is for users to specify a vibration pattern array when creating a channel. --- .../modules/RNPushNotificationHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 5fa8feb5c..03abf1500 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -908,7 +908,7 @@ public boolean createChannel(ReadableMap channelInfo) { String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); - long[] vibratePattern = vibrate ? new long[] { DEFAULT_VIBRATION } : null; + long[] vibratePattern = vibrate ? new long[] { 0, DEFAULT_VIBRATION } : null; NotificationManager manager = notificationManager(); From 063836784ed01390f37f2a9c1abcfe9b380fafb9 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Tue, 20 Oct 2020 23:59:52 +0200 Subject: [PATCH 130/179] Update RNPushNotificationHelper.java --- .../modules/RNPushNotificationHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 03abf1500..3246cf801 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -446,7 +446,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (vibration == 0) vibration = DEFAULT_VIBRATION; - vibratePattern = new long[]{0, vibration}; + vibratePattern = new long[]{vibration}; notification.setVibrate(vibratePattern); } From 9bfd54006c3e46219586a3f870cce45ef0c75e50 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 21 Oct 2020 00:02:26 +0200 Subject: [PATCH 131/179] Revert. --- .../modules/RNPushNotificationHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 3246cf801..03abf1500 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -446,7 +446,7 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (vibration == 0) vibration = DEFAULT_VIBRATION; - vibratePattern = new long[]{vibration}; + vibratePattern = new long[]{0, vibration}; notification.setVibrate(vibratePattern); } From 251a3ace82d816bde5e3402827d6cd551c7f29e9 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 21 Oct 2020 00:30:21 +0200 Subject: [PATCH 132/179] Bump version to 6.1.2 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c252b9abd..2b836ec36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed +## [6.1.2] 2020-10-291 + +### Fixed + +- (Android) Fix for vibration on notifs for Android API >= 26 [#1686](https://github.com/zo0r/react-native-push-notification/pull/1686) + ## [6.1.1] 2020-09-29 ### Fixed diff --git a/package.json b/package.json index 644fd4675..d3b3b36ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "6.1.1", + "version": "6.1.2", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 7d24f9c052976b2d9edef4aa6f56b431803a5475 Mon Sep 17 00:00:00 2001 From: Hamid Date: Sun, 8 Nov 2020 13:37:13 +0330 Subject: [PATCH 133/179] Android: silent channel using playSound flag --- .../modules/RNPushNotificationHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 03abf1500..1a9491d1c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -905,6 +905,7 @@ public boolean createChannel(ReadableMap channelInfo) { String channelId = channelInfo.getString("channelId"); String channelName = channelInfo.getString("channelName"); String channelDescription = channelInfo.hasKey("channelDescription") ? channelInfo.getString("channelDescription") : ""; + boolean playSound = !channelInfo.hasKey("playSound") || channelInfo.getBoolean("playSound"); String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); @@ -912,7 +913,7 @@ public boolean createChannel(ReadableMap channelInfo) { NotificationManager manager = notificationManager(); - Uri soundUri = getSoundUri(soundName); + Uri soundUri = playSound ? getSoundUri(soundName) : null; return checkOrCreateChannel(manager, channelId, channelName, channelDescription, soundUri, importance, vibratePattern); } From f74e38be8a1fffefa45a2366cc5ec2f8706f6b06 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Mon, 9 Nov 2020 19:21:47 +0100 Subject: [PATCH 134/179] Fix a crash when trying to update a channel. --- CHANGELOG.md | 8 +++++++- .../modules/RNPushNotificationHelper.java | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b836ec36..f1a1a5e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,13 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed -## [6.1.2] 2020-10-291 +## [6.1.3] 2020-11-09 + +### Fixed + +- (Android) Null pointer exception when trying to create channel [#134](https://github.com/zo0r/react-native-push-notification/issues/1734) + +## [6.1.2] 2020-10-29 ### Fixed diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 03abf1500..4af0411f1 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -866,8 +866,8 @@ private boolean checkOrCreateChannel(NotificationManager manager, String channel channel == null && channel_name != null && channel_description != null || channel != null && ( - channel_name != null && !channel.getName().equals(channel_name) || - channel_description != null && !channel.getDescription().equals(channel_description) + channel_name != null && !channel_name.equals(channel.getName()) || + channel_description != null && !channel_description.equals(channel.getDescription()) ) ) { // If channel doesn't exist create a new one. diff --git a/package.json b/package.json index d3b3b36ef..375814add 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "6.1.2", + "version": "6.1.3", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 52fee0e61fb9b7e16c6a5255eaebba3bd5a51f83 Mon Sep 17 00:00:00 2001 From: Hamid Date: Tue, 10 Nov 2020 10:25:54 +0330 Subject: [PATCH 135/179] playSound in readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 579f9df4d..9e6254a16 100644 --- a/README.md +++ b/README.md @@ -398,6 +398,7 @@ To use channels, create them at startup and pass the matching `channelId` throug channelId: "channel-id", // (required) channelName: "My channel", // (required) channelDescription: "A channel to categorise your notifications", // (optional) default: undefined. + playSound: false, // (optional) default: true soundName: "default", // (optional) See `soundName` parameter of `localNotification` function importance: 4, // (optional) default: 4. Int value of the Android notification importance vibrate: true, // (optional) default: true. Creates the default vibration patten if true. From bc45aa588ab343eafc5017c1f549e3861f862fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Barbet?= Date: Tue, 10 Nov 2020 09:03:19 +0000 Subject: [PATCH 136/179] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 579f9df4d..6963ffaad 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ public class MainApplication extends Application implements ReactApplication { ```javascript import PushNotificationIOS from "@react-native-community/push-notification-ios"; -var PushNotification = require("react-native-push-notification"); +import PushNotification from "react-native-push-notification"; // Must be outside of any component LifeCycle (such as `componentDidMount`). PushNotification.configure({ @@ -502,7 +502,7 @@ _NOTE: there is currently no api for removing specific notification alerts from ### 3) removeAllDeliveredNotifications ```javascript -PushNotificationIOS.removeAllDeliveredNotifications(); +PushNotification.removeAllDeliveredNotifications(); ``` Remove all delivered notifications from Notification Center @@ -510,7 +510,7 @@ Remove all delivered notifications from Notification Center ### 4) getDeliveredNotifications ```javascript -PushNotificationIOS.getDeliveredNotifications(callback); +PushNotification.getDeliveredNotifications(callback); ``` Provides you with a list of the app’s notifications that are still displayed in Notification Center @@ -533,7 +533,7 @@ A delivered notification is an object containing: ### 5) removeDeliveredNotifications ```javascript -PushNotificationIOS.removeDeliveredNotifications(identifiers); +PushNotification.removeDeliveredNotifications(identifiers); ``` Removes the specified notifications from Notification Center @@ -547,7 +547,7 @@ Removes the specified notifications from Notification Center ### 6) getScheduledLocalNotifications ```javascript -PushNotificationIOS.getScheduledLocalNotifications(callback); +PushNotification.getScheduledLocalNotifications(callback); ``` Provides you with a list of the app’s scheduled local notifications that are yet to be displayed From 05605445ff475de8b9c9190a897f38d68c869e03 Mon Sep 17 00:00:00 2001 From: David <4661784+retyui@users.noreply.github.com> Date: Tue, 10 Nov 2020 22:03:39 +0200 Subject: [PATCH 137/179] [other] Reduce npm package size - https://npmfs.com/package/react-native-push-notification/6.1.3/ --- .npmignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index 8c497b0dd..84ba28601 100644 --- a/.npmignore +++ b/.npmignore @@ -62,4 +62,13 @@ local.properties example # Git -.git \ No newline at end of file +.git + +# GitHub +.github/* + +# Docs +submitting-a-pull-request.md + +# Vscode +.vscode/* From c71c4700445b36fd4b43904bd9ad1a89095d0d4b Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Fri, 20 Nov 2020 16:57:11 -0500 Subject: [PATCH 138/179] Replace deprecated methods presentLocalNotification and scheduleLocalNotification from react-native-push-notification-ios/push-notification-ios; alertAction has been deprecated as of iOS 10 --- README.md | 1 - example/NotifService.js | 2 -- index.js | 23 +++++++++++------------ 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6963ffaad..f3bdee7aa 100644 --- a/README.md +++ b/README.md @@ -336,7 +336,6 @@ PushNotification.localNotification({ invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true /* iOS only properties */ - alertAction: "view", // (optional) default: view category: "", // (optional) default: empty string /* iOS and Android properties */ diff --git a/example/NotifService.js b/example/NotifService.js index c9ed55b7b..792668268 100644 --- a/example/NotifService.js +++ b/example/NotifService.js @@ -93,7 +93,6 @@ export default class NotifService { timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null /* iOS only properties */ - alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string /* iOS and Android properties */ @@ -135,7 +134,6 @@ export default class NotifService { timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null /* iOS only properties */ - alertAction: 'view', // (optional) default: view category: '', // (optional) default: empty string /* iOS and Android properties */ diff --git a/index.js b/index.js index 6bf716afa..57a08ce03 100644 --- a/index.js +++ b/index.js @@ -176,15 +176,14 @@ Notifications.localNotification = function(details) { } // for valid fields see: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html - // alertTitle only valid for apple watch: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/#//apple_ref/occ/instp/UILocalNotification/alertTitle - this.handler.presentLocalNotification({ - alertTitle: details.title, - alertBody: details.message, - alertAction: details.alertAction, + this.handler.addNotificationRequest({ + id: (!details.id ? Math.floor(Math.random() * Math.pow(2, 32)).toString() : details.id), + title: details.title, + body: details.message, + badge: details.number, + sound: soundName, category: details.category, - soundName: soundName, - applicationIconBadgeNumber: details.number, userInfo: details.userInfo }); } else { @@ -250,14 +249,14 @@ Notifications.localNotificationSchedule = function(details) { } const iosDetails = { + id: (!details.id ? Math.floor(Math.random() * Math.pow(2, 32)).toString() : details.id), fireDate: details.date.toISOString(), - alertTitle: details.title, - alertBody: details.message, - category: details.category, + title: details.title, + body: details.message, soundName: soundName, + category: details.category, userInfo: details.userInfo, repeatInterval: details.repeatType, - category: details.category, }; if (details.number) { @@ -268,7 +267,7 @@ Notifications.localNotificationSchedule = function(details) { if (!details.repeatType || details.repeatType === 'time') { delete iosDetails.repeatInterval; } - this.handler.scheduleLocalNotification(iosDetails); + this.handler.addNotificationRequest(iosDetails); } else { if (details && typeof details.number === 'number') { if (isNaN(details.number)) { From 8e89b2784b825fa5bd3aa90a6836bf52635c9234 Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Fri, 20 Nov 2020 19:45:16 -0500 Subject: [PATCH 139/179] swap cancelAllLocalNotifications for removeAllPendingNotificationRequests on iOS; swap getScheduledLocalNotifications for getPendingNotificationRequests on iOS --- index.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 57a08ce03..a00be77dd 100644 --- a/index.js +++ b/index.js @@ -464,7 +464,11 @@ Notifications.clearLocalNotification = function() { }; Notifications.cancelAllLocalNotifications = function() { - return this.callNative('cancelAllLocalNotifications', arguments); + if ( Platform.OS === 'ios' ) { + return this.callNative('removeAllPendingNotificationRequests', arguments); + } else if (Platform.OS === 'android') { + return this.callNative('cancelAllLocalNotifications', arguments); + } }; Notifications.setApplicationIconBadgeNumber = function() { @@ -512,13 +516,13 @@ Notifications.getScheduledLocalNotifications = function(callback) { if(Platform.OS === 'ios'){ mappedNotifications = notifications.map(notif => { return ({ - soundName: notif.soundName, + soundName: notif?.sound, repeatInterval: notif.repeatInterval, - id: notif.userInfo?.id, - date: new Date(notif.fireDate), - number: notif?.applicationIconBadgeNumber, - message: notif?.alertBody, - title: notif?.alertTitle, + id: notif.id, + date: (notif.date ? new Date(notif.date) : null), + number: notif?.badge, + message: notif?.body, + title: notif?.title, }) }) } else if(Platform.OS === 'android') { @@ -538,7 +542,11 @@ Notifications.getScheduledLocalNotifications = function(callback) { callback(mappedNotifications); } - return this.callNative('getScheduledLocalNotifications', [mapNotifications]); + if(Platform.OS === 'ios'){ + return this.callNative('getPendingNotificationRequests', [mapNotifications]); + } else { + return this.callNative('getScheduledLocalNotifications', [mapNotifications]); + } } Notifications.removeDeliveredNotifications = function() { From 329c277fbd23bfc0c42fed1027080c20e08094c8 Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Sun, 22 Nov 2020 15:21:59 -0500 Subject: [PATCH 140/179] Update peer dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 375814add..18149ba73 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "peerDependencies": { - "@react-native-community/push-notification-ios": "^1.5.0", + "@react-native-community/push-notification-ios": "^1.7.4", "react-native": ">=0.33" }, "author": "zo0r ", From 353b735a5620c3f5f81fdf85c8ccf4ba57fac4ab Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Tue, 24 Nov 2020 12:15:37 -0500 Subject: [PATCH 141/179] Fix sound, badge, and repeat properties in localNotificationSchedule; repeatType only supports 'day' on iOS --- README.md | 22 +++++++++++++--------- index.js | 11 +++-------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f3bdee7aa..115b0e384 100644 --- a/README.md +++ b/README.md @@ -559,15 +559,15 @@ Provides you with a list of the app’s scheduled local notifications that are y Returns an array of local scheduled notification objects containing: -| Name | Type | Description | -| -------------- | ------ | ----------------------------------------- | -| id | number | The identifier of this notification. | -| date | Date | The fire date of this notification. | -| title | string | The title of this notification. | -| message | string | The message body of this notification. | -| soundName | string | The sound name of this notification. | -| repeatInterval | number | The repeat interval of this notification. | -| number | number | App notification badge count number. | +| Name | Type | Description | +| -------------- | ------ | -------------------------------------------------------- | +| id | number | The identifier of this notification. | +| date | Date | The fire date of this notification. | +| title | string | The title of this notification. | +| message | string | The message body of this notification. | +| soundName | string | The sound name of this notification. | +| repeatInterval | number | (Android only) The repeat interval of this notification. | +| number | number | App notification badge count number. | ## Abandon Permissions @@ -630,6 +630,10 @@ https://developer.android.com/training/monitoring-device-state/doze-standby (optional) Specify `repeatType` and optionally `repeatTime` (Android-only) while scheduling the local notification. Check the local notification example above. +### iOS +Property `repeatType` can only be `day`. + +### Android Property `repeatType` could be one of `month`, `week`, `day`, `hour`, `minute`, `time`. If specified as time, it should be accompanied by one more parameter `repeatTime` which should the number of milliseconds between each interval. ## Notification Actions diff --git a/index.js b/index.js index a00be77dd..fad90bfa2 100644 --- a/index.js +++ b/index.js @@ -253,20 +253,16 @@ Notifications.localNotificationSchedule = function(details) { fireDate: details.date.toISOString(), title: details.title, body: details.message, - soundName: soundName, + sound: soundName, category: details.category, userInfo: details.userInfo, - repeatInterval: details.repeatType, + repeats: (details.repeatType && details.repeatType == "day"), }; if (details.number) { - iosDetails.applicationIconBadgeNumber = parseInt(details.number, 10); + iosDetails.badge = parseInt(details.number, 10); } - // ignore Android only repeatType - if (!details.repeatType || details.repeatType === 'time') { - delete iosDetails.repeatInterval; - } this.handler.addNotificationRequest(iosDetails); } else { if (details && typeof details.number === 'number') { @@ -517,7 +513,6 @@ Notifications.getScheduledLocalNotifications = function(callback) { mappedNotifications = notifications.map(notif => { return ({ soundName: notif?.sound, - repeatInterval: notif.repeatInterval, id: notif.id, date: (notif.date ? new Date(notif.date) : null), number: notif?.badge, From 86919200853c420996368483c4b1763b41733e3a Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Wed, 25 Nov 2020 14:49:33 -0500 Subject: [PATCH 142/179] Update peer dependency; Update cancelLocalNotifications --- README.md | 2 -- index.js | 8 ++++++-- package.json | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 115b0e384..1d459bdca 100644 --- a/README.md +++ b/README.md @@ -496,8 +496,6 @@ PushNotification.cancelLocalNotifications({id: '123'}); Cancels all scheduled notifications AND clears the notifications alerts that are in the notification centre. -_NOTE: there is currently no api for removing specific notification alerts from the notification centre._ - ### 3) removeAllDeliveredNotifications ```javascript diff --git a/index.js b/index.js index fad90bfa2..c93ab8ad4 100644 --- a/index.js +++ b/index.js @@ -451,8 +451,12 @@ Notifications.scheduleLocalNotification = function() { return this.callNative('scheduleLocalNotification', arguments); }; -Notifications.cancelLocalNotifications = function() { - return this.callNative('cancelLocalNotifications', arguments); +Notifications.cancelLocalNotifications = function(userInfo) { + if ( Platform.OS === 'ios' ) { + return this.callNative('removePendingNotificationRequests', [userInfo.id]); + } else { + return this.callNative('cancelLocalNotifications', [userInfo]); + } }; Notifications.clearLocalNotification = function() { diff --git a/package.json b/package.json index 18149ba73..17ed4f291 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "url": "git+ssh://git@github.com:zo0r/react-native-push-notification.git" }, "peerDependencies": { - "@react-native-community/push-notification-ios": "^1.7.4", + "@react-native-community/push-notification-ios": "^1.8.0", "react-native": ">=0.33" }, "author": "zo0r ", From 28cf219326084932a84a0ec0e8ce4e6cefa1db3e Mon Sep 17 00:00:00 2001 From: Nathan Bolender Date: Wed, 25 Nov 2020 14:50:58 -0500 Subject: [PATCH 143/179] Correct parameter --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index c93ab8ad4..941388c68 100644 --- a/index.js +++ b/index.js @@ -453,7 +453,7 @@ Notifications.scheduleLocalNotification = function() { Notifications.cancelLocalNotifications = function(userInfo) { if ( Platform.OS === 'ios' ) { - return this.callNative('removePendingNotificationRequests', [userInfo.id]); + return this.callNative('removePendingNotificationRequests', [[userInfo.id]]); } else { return this.callNative('cancelLocalNotifications', [userInfo]); } From a50b87ba18dfd655154104e1938fe11f2cd97ed9 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 27 Nov 2020 14:17:43 +0300 Subject: [PATCH 144/179] Update README.md May be we should update readme about local notifications for better understanding how should users setup this library on android --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6963ffaad..ab671d93b 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ In your `android/app/src/main/AndroidManifest.xml` - + @@ -322,7 +322,7 @@ PushNotification.localNotification({ ongoing: false, // (optional) set whether this is an "ongoing" notification priority: "high", // (optional) set notification priority, default: high visibility: "private", // (optional) set notification visibility, default: private - ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear) + ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear). should be used in combine with `com.dieam.reactnativepushnotification.notification_foreground` setting shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false From fa0bd1bdbdb8af3e7a9219ae8c25ee3b3bc8c3f8 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 2 Dec 2020 09:08:17 +0100 Subject: [PATCH 145/179] Rename the ReactNative Package. --- CHANGELOG.md | 5 +- .../modules/RNPushNotification.java | 2 +- component/index.android.js | 2 +- example/ios/Podfile | 80 +-- example/ios/Podfile.lock | 529 +++++++++--------- example/ios/example.xcodeproj/project.pbxproj | 38 ++ example/ios/example/AppDelegate.m | 4 +- example/package.json | 6 +- 8 files changed, 322 insertions(+), 344 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1a1a5e76..6f873a231 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +- (iOS) Replace deprecated local notification methods on iOS [1751](https://github.com/zo0r/react-native-push-notification/pull/1751) +- (Android) Rename the Android package from `ReactNativePushNotification` to `ReactNativePushNotification` resolve [893](https://github.com/zo0r/react-native-push-notification/issues/893) + ### Features ### Fixed @@ -16,7 +19,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed -- (Android) Null pointer exception when trying to create channel [#134](https://github.com/zo0r/react-native-push-notification/issues/1734) +- (Android) Null pointer exception when trying to create channel [#1734](https://github.com/zo0r/react-native-push-notification/issues/1734) ## [6.1.2] 2020-10-29 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 f0d4eed87..75a83ac5c 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -61,7 +61,7 @@ public RNPushNotification(ReactApplicationContext reactContext) { @Override public String getName() { - return "RNPushNotification"; + return "ReactNativePushNotification"; } @Override diff --git a/component/index.android.js b/component/index.android.js index 819acab9b..249559479 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -2,7 +2,7 @@ import { NativeModules, DeviceEventEmitter } from "react-native"; -let RNPushNotification = NativeModules.RNPushNotification; +let RNPushNotification = NativeModules.ReactNativePushNotification; let _notifHandlers = new Map(); var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived'; diff --git a/example/ios/Podfile b/example/ios/Podfile index faf88bd5e..00f500b39 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,94 +1,24 @@ -platform :ios, '9.0' +platform :ios, '10.0' +require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -def add_flipper_pods!(versions = {}) - versions['Flipper'] ||= '~> 0.33.1' - versions['DoubleConversion'] ||= '1.1.7' - versions['Flipper-Folly'] ||= '~> 2.1' - versions['Flipper-Glog'] ||= '0.3.6' - versions['Flipper-PeerTalk'] ||= '~> 0.0.4' - versions['Flipper-RSocket'] ||= '~> 1.0' - - pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug' - - # List all transitive dependencies for FlipperKit pods - # to avoid them being linked in Release builds - pod 'Flipper', versions['Flipper'], :configuration => 'Debug' - pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug' - pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug' - pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug' - pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug' - pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug' - pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug' - pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug' -end - -# Post Install processing for Flipper -def flipper_post_install(installer) - installer.pods_project.targets.each do |target| - if target.name == 'YogaKit' - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.1' - end - end - end -end - target 'example' do # Pods for example - pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" - pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" - pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" - pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" - pod 'React', :path => '../node_modules/react-native/' - pod 'React-Core', :path => '../node_modules/react-native/' - pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' - pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' - pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' - pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' - pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' - pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' - pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' - pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' - pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' - pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' - pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' - pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' - - pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' - pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' - pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' - pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' - pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" - pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" - pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true + config = use_native_modules! - pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' - pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' - pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' + use_react_native!(:path => config["reactNativePath"]) target 'exampleTests' do inherit! :complete # Pods for testing end - use_native_modules! # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable these next few lines. - add_flipper_pods! + use_flipper! post_install do |installer| flipper_post_install(installer) end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 325f7f657..dfed099b2 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -3,297 +3,301 @@ PODS: - CocoaAsyncSocket (7.6.4) - CocoaLibEvent (1.0.0) - DoubleConversion (1.1.6) - - FBLazyVector (0.62.2) - - FBReactNativeSpec (0.62.2): - - Folly (= 2018.10.22.00) - - RCTRequired (= 0.62.2) - - RCTTypeSafety (= 0.62.2) - - React-Core (= 0.62.2) - - React-jsi (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - Flipper (0.33.1): - - Flipper-Folly (~> 2.1) - - Flipper-RSocket (~> 1.0) + - FBLazyVector (0.63.3) + - FBReactNativeSpec (0.63.3): + - Folly (= 2020.01.13.00) + - RCTRequired (= 0.63.3) + - RCTTypeSafety (= 0.63.3) + - React-Core (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - Flipper (0.54.0): + - Flipper-Folly (~> 2.2) + - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.1.1): + - Flipper-Folly (2.3.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.19) + - OpenSSL-Universal (= 1.0.2.20) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - - Flipper-RSocket (1.0.0): - - Flipper-Folly (~> 2.0) - - FlipperKit (0.33.1): - - FlipperKit/Core (= 0.33.1) - - FlipperKit/Core (0.33.1): - - Flipper (~> 0.33.1) + - Flipper-RSocket (1.1.0): + - Flipper-Folly (~> 2.2) + - FlipperKit (0.54.0): + - FlipperKit/Core (= 0.54.0) + - FlipperKit/Core (0.54.0): + - Flipper (~> 0.54.0) - FlipperKit/CppBridge - FlipperKit/FBCxxFollyDynamicConvert - FlipperKit/FBDefines - FlipperKit/FKPortForwarding - - FlipperKit/CppBridge (0.33.1): - - Flipper (~> 0.33.1) - - FlipperKit/FBCxxFollyDynamicConvert (0.33.1): - - Flipper-Folly (~> 2.1) - - FlipperKit/FBDefines (0.33.1) - - FlipperKit/FKPortForwarding (0.33.1): + - FlipperKit/CppBridge (0.54.0): + - Flipper (~> 0.54.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.54.0): + - Flipper-Folly (~> 2.2) + - FlipperKit/FBDefines (0.54.0) + - FlipperKit/FKPortForwarding (0.54.0): - CocoaAsyncSocket (~> 7.6) - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.33.1) - - FlipperKit/FlipperKitLayoutPlugin (0.33.1): + - FlipperKit/FlipperKitHighlightOverlay (0.54.0) + - FlipperKit/FlipperKitLayoutPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitHighlightOverlay - FlipperKit/FlipperKitLayoutTextSearchable - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.33.1) - - FlipperKit/FlipperKitNetworkPlugin (0.33.1): + - FlipperKit/FlipperKitLayoutTextSearchable (0.54.0) + - FlipperKit/FlipperKitNetworkPlugin (0.54.0): - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.33.1): + - FlipperKit/FlipperKitReactPlugin (0.54.0): - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.33.1): + - FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0): - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.33.1): + - FlipperKit/SKIOSNetworkPlugin (0.54.0): - FlipperKit/Core - FlipperKit/FlipperKitNetworkPlugin - - Folly (2018.10.22.00): + - Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion - - Folly/Default (= 2018.10.22.00) + - Folly/Default (= 2020.01.13.00) - glog - - Folly/Default (2018.10.22.00): + - Folly/Default (2020.01.13.00): - boost-for-react-native - DoubleConversion - glog - glog (0.3.5) - - OpenSSL-Universal (1.0.2.19): - - OpenSSL-Universal/Static (= 1.0.2.19) - - OpenSSL-Universal/Static (1.0.2.19) - - RCTRequired (0.62.2) - - RCTTypeSafety (0.62.2): - - FBLazyVector (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTRequired (= 0.62.2) - - React-Core (= 0.62.2) - - React (0.62.2): - - React-Core (= 0.62.2) - - React-Core/DevSupport (= 0.62.2) - - React-Core/RCTWebSocket (= 0.62.2) - - React-RCTActionSheet (= 0.62.2) - - React-RCTAnimation (= 0.62.2) - - React-RCTBlob (= 0.62.2) - - React-RCTImage (= 0.62.2) - - React-RCTLinking (= 0.62.2) - - React-RCTNetwork (= 0.62.2) - - React-RCTSettings (= 0.62.2) - - React-RCTText (= 0.62.2) - - React-RCTVibration (= 0.62.2) - - React-Core (0.62.2): - - Folly (= 2018.10.22.00) + - OpenSSL-Universal (1.0.2.20): + - OpenSSL-Universal/Static (= 1.0.2.20) + - OpenSSL-Universal/Static (1.0.2.20) + - RCTRequired (0.63.3) + - RCTTypeSafety (0.63.3): + - FBLazyVector (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTRequired (= 0.63.3) + - React-Core (= 0.63.3) + - React (0.63.3): + - React-Core (= 0.63.3) + - React-Core/DevSupport (= 0.63.3) + - React-Core/RCTWebSocket (= 0.63.3) + - React-RCTActionSheet (= 0.63.3) + - React-RCTAnimation (= 0.63.3) + - React-RCTBlob (= 0.63.3) + - React-RCTImage (= 0.63.3) + - React-RCTLinking (= 0.63.3) + - React-RCTNetwork (= 0.63.3) + - React-RCTSettings (= 0.63.3) + - React-RCTText (= 0.63.3) + - React-RCTVibration (= 0.63.3) + - React-callinvoker (0.63.3) + - React-Core (0.63.3): + - Folly (= 2020.01.13.00) - glog - - React-Core/Default (= 0.62.2) - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-Core/Default (= 0.63.3) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/CoreModulesHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/CoreModulesHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/Default (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/Default (0.63.3): + - Folly (= 2020.01.13.00) - glog - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/DevSupport (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/DevSupport (0.63.3): + - Folly (= 2020.01.13.00) - glog - - React-Core/Default (= 0.62.2) - - React-Core/RCTWebSocket (= 0.62.2) - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) - - React-jsinspector (= 0.62.2) + - React-Core/Default (= 0.63.3) + - React-Core/RCTWebSocket (= 0.63.3) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) + - React-jsinspector (= 0.63.3) - Yoga - - React-Core/RCTActionSheetHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTActionSheetHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTAnimationHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTAnimationHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTBlobHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTBlobHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTImageHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTImageHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTLinkingHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTLinkingHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTNetworkHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTNetworkHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTSettingsHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTSettingsHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTTextHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTTextHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTVibrationHeaders (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTVibrationHeaders (0.63.3): + - Folly (= 2020.01.13.00) - glog - React-Core/Default - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-Core/RCTWebSocket (0.62.2): - - Folly (= 2018.10.22.00) + - React-Core/RCTWebSocket (0.63.3): + - Folly (= 2020.01.13.00) - glog - - React-Core/Default (= 0.62.2) - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsiexecutor (= 0.62.2) + - React-Core/Default (= 0.63.3) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsiexecutor (= 0.63.3) - Yoga - - React-CoreModules (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTTypeSafety (= 0.62.2) - - React-Core/CoreModulesHeaders (= 0.62.2) - - React-RCTImage (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-cxxreact (0.62.2): + - React-CoreModules (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTTypeSafety (= 0.63.3) + - React-Core/CoreModulesHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - React-RCTImage (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-cxxreact (0.63.3): - boost-for-react-native (= 1.63.0) - DoubleConversion - - Folly (= 2018.10.22.00) + - Folly (= 2020.01.13.00) - glog - - React-jsinspector (= 0.62.2) - - React-jsi (0.62.2): + - React-callinvoker (= 0.63.3) + - React-jsinspector (= 0.63.3) + - React-jsi (0.63.3): - boost-for-react-native (= 1.63.0) - DoubleConversion - - Folly (= 2018.10.22.00) + - Folly (= 2020.01.13.00) - glog - - React-jsi/Default (= 0.62.2) - - React-jsi/Default (0.62.2): + - React-jsi/Default (= 0.63.3) + - React-jsi/Default (0.63.3): - boost-for-react-native (= 1.63.0) - DoubleConversion - - Folly (= 2018.10.22.00) + - Folly (= 2020.01.13.00) - glog - - React-jsiexecutor (0.62.2): + - React-jsiexecutor (0.63.3): - DoubleConversion - - Folly (= 2018.10.22.00) + - Folly (= 2020.01.13.00) - glog - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - React-jsinspector (0.62.2) - - React-RCTActionSheet (0.62.2): - - React-Core/RCTActionSheetHeaders (= 0.62.2) - - React-RCTAnimation (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTTypeSafety (= 0.62.2) - - React-Core/RCTAnimationHeaders (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTBlob (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - React-Core/RCTBlobHeaders (= 0.62.2) - - React-Core/RCTWebSocket (= 0.62.2) - - React-jsi (= 0.62.2) - - React-RCTNetwork (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTImage (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTTypeSafety (= 0.62.2) - - React-Core/RCTImageHeaders (= 0.62.2) - - React-RCTNetwork (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTLinking (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - React-Core/RCTLinkingHeaders (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTNetwork (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTTypeSafety (= 0.62.2) - - React-Core/RCTNetworkHeaders (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTSettings (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - RCTTypeSafety (= 0.62.2) - - React-Core/RCTSettingsHeaders (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - React-RCTText (0.62.2): - - React-Core/RCTTextHeaders (= 0.62.2) - - React-RCTVibration (0.62.2): - - FBReactNativeSpec (= 0.62.2) - - Folly (= 2018.10.22.00) - - React-Core/RCTVibrationHeaders (= 0.62.2) - - ReactCommon/turbomodule/core (= 0.62.2) - - ReactCommon/callinvoker (0.62.2): + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - React-jsinspector (0.63.3) + - React-RCTActionSheet (0.63.3): + - React-Core/RCTActionSheetHeaders (= 0.63.3) + - React-RCTAnimation (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTTypeSafety (= 0.63.3) + - React-Core/RCTAnimationHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTBlob (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - React-Core/RCTBlobHeaders (= 0.63.3) + - React-Core/RCTWebSocket (= 0.63.3) + - React-jsi (= 0.63.3) + - React-RCTNetwork (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTImage (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTTypeSafety (= 0.63.3) + - React-Core/RCTImageHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - React-RCTNetwork (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTLinking (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - React-Core/RCTLinkingHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTNetwork (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTTypeSafety (= 0.63.3) + - React-Core/RCTNetworkHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTSettings (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - RCTTypeSafety (= 0.63.3) + - React-Core/RCTSettingsHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - React-RCTText (0.63.3): + - React-Core/RCTTextHeaders (= 0.63.3) + - React-RCTVibration (0.63.3): + - FBReactNativeSpec (= 0.63.3) + - Folly (= 2020.01.13.00) + - React-Core/RCTVibrationHeaders (= 0.63.3) + - React-jsi (= 0.63.3) + - ReactCommon/turbomodule/core (= 0.63.3) + - ReactCommon/turbomodule/core (0.63.3): - DoubleConversion - - Folly (= 2018.10.22.00) + - Folly (= 2020.01.13.00) - glog - - React-cxxreact (= 0.62.2) - - ReactCommon/turbomodule/core (0.62.2): - - DoubleConversion - - Folly (= 2018.10.22.00) - - glog - - React-Core (= 0.62.2) - - React-cxxreact (= 0.62.2) - - React-jsi (= 0.62.2) - - ReactCommon/callinvoker (= 0.62.2) - - RNCPushNotificationIOS (1.4.0): - - React + - React-callinvoker (= 0.63.3) + - React-Core (= 0.63.3) + - React-cxxreact (= 0.63.3) + - React-jsi (= 0.63.3) + - RNCPushNotificationIOS (1.8.0): + - React-Core - Yoga (1.14.0) - YogaKit (1.18.1): - Yoga (~> 1.14) @@ -302,30 +306,31 @@ DEPENDENCIES: - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) - - Flipper (~> 0.33.1) + - Flipper (~> 0.54.0) - Flipper-DoubleConversion (= 1.1.7) - - Flipper-Folly (~> 2.1) + - Flipper-Folly (~> 2.2) - Flipper-Glog (= 0.3.6) - Flipper-PeerTalk (~> 0.0.4) - - Flipper-RSocket (~> 1.0) - - FlipperKit (~> 0.33.1) - - FlipperKit/Core (~> 0.33.1) - - FlipperKit/CppBridge (~> 0.33.1) - - FlipperKit/FBCxxFollyDynamicConvert (~> 0.33.1) - - FlipperKit/FBDefines (~> 0.33.1) - - FlipperKit/FKPortForwarding (~> 0.33.1) - - FlipperKit/FlipperKitHighlightOverlay (~> 0.33.1) - - FlipperKit/FlipperKitLayoutPlugin (~> 0.33.1) - - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.33.1) - - FlipperKit/FlipperKitNetworkPlugin (~> 0.33.1) - - FlipperKit/FlipperKitReactPlugin (~> 0.33.1) - - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.33.1) - - FlipperKit/SKIOSNetworkPlugin (~> 0.33.1) + - Flipper-RSocket (~> 1.1) + - FlipperKit (~> 0.54.0) + - FlipperKit/Core (~> 0.54.0) + - FlipperKit/CppBridge (~> 0.54.0) + - FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0) + - FlipperKit/FBDefines (~> 0.54.0) + - FlipperKit/FKPortForwarding (~> 0.54.0) + - FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0) + - FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0) + - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0) + - FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0) + - FlipperKit/FlipperKitReactPlugin (~> 0.54.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0) + - FlipperKit/SKIOSNetworkPlugin (~> 0.54.0) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Core (from `../node_modules/react-native/`) - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) @@ -343,7 +348,6 @@ DEPENDENCIES: - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - - ReactCommon/callinvoker (from `../node_modules/react-native/ReactCommon`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)" - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) @@ -380,6 +384,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/TypeSafety" React: :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" React-Core: :path: "../node_modules/react-native/" React-CoreModules: @@ -421,42 +427,43 @@ SPEC CHECKSUMS: boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f - DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 - FBLazyVector: 4aab18c93cd9546e4bfed752b4084585eca8b245 - FBReactNativeSpec: 5465d51ccfeecb7faa12f9ae0024f2044ce4044e - Flipper: 6c1f484f9a88d30ab3e272800d53688439e50f69 + DoubleConversion: cde416483dac037923206447da6e1454df403714 + FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d + FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f + Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: 2de3d03e0acc7064d5e4ed9f730e2f217486f162 + Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - Flipper-RSocket: 1260a31c05c238eabfa9bb8a64e3983049048371 - FlipperKit: 6dc9b8f4ef60d9e5ded7f0264db299c91f18832e - Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 - glog: 1f3da668190260b06b429bb211bfbee5cd790c28 - OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 - RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035 - RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce - React: 29a8b1a02bd764fb7644ef04019270849b9a7ac3 - React-Core: b12bffb3f567fdf99510acb716ef1abd426e0e05 - React-CoreModules: 4a9b87bbe669d6c3173c0132c3328e3b000783d0 - React-cxxreact: e65f9c2ba0ac5be946f53548c1aaaee5873a8103 - React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161 - React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da - React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493 - React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c - React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0 - React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71 - React-RCTImage: e70be9b9c74fe4e42d0005f42cace7981c994ac3 - React-RCTLinking: c1b9739a88d56ecbec23b7f63650e44672ab2ad2 - React-RCTNetwork: 73138b6f45e5a2768ad93f3d57873c2a18d14b44 - React-RCTSettings: 6e3738a87e21b39a8cb08d627e68c44acf1e325a - React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d - React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256 - ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3 - RNCPushNotificationIOS: dc1c0c6aa18a128df123598149f42e848d26a4ac - Yoga: 3ebccbdd559724312790e7742142d062476b698e + Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 + FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d + Folly: b73c3869541e86821df3c387eb0af5f65addfab4 + glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 + OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd + RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047 + RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab + React: f36e90f3ceb976546e97df3403e37d226f79d0e3 + React-callinvoker: 18874f621eb96625df7a24a7dc8d6e07391affcd + React-Core: ac3d816b8e3493970153f4aaf0cff18af0bb95e6 + React-CoreModules: 4016d3a4e518bcfc4f5a51252b5a05692ca6f0e1 + React-cxxreact: ffc9129013b87cb36cf3f30a86695a3c397b0f99 + React-jsi: df07aa95b39c5be3e41199921509bfa929ed2b9d + React-jsiexecutor: b56c03e61c0dd5f5801255f2160a815f4a53d451 + React-jsinspector: 8e68ffbfe23880d3ee9bafa8be2777f60b25cbe2 + React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa + React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2 + React-RCTBlob: 0b284339cbe4b15705a05e2313a51c6d8b51fa40 + React-RCTImage: d1756599ebd4dc2cb19d1682fe67c6b976658387 + React-RCTLinking: 9af0a51c6d6a4dd1674daadafffc6d03033a6d18 + React-RCTNetwork: 332c83929cc5eae0b3bbca4add1d668e1fc18bda + React-RCTSettings: d6953772cfd55f2c68ad72b7ef29efc7ec49f773 + React-RCTText: 65a6de06a7389098ce24340d1d3556015c38f746 + React-RCTVibration: 8e9fb25724a0805107fc1acc9075e26f814df454 + ReactCommon: 4167844018c9ed375cc01a843e9ee564399e53c3 + RNCPushNotificationIOS: 61a7c72bd1ebad3568025957d001e0f0e7b32191 + Yoga: 7d13633d129fd179e01b8953d38d47be90db185a YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 56c2537f71f3f02200d6918c542a8e89a0b422fa +PODFILE CHECKSUM: 2ce9d926fa5d7b425b9668ca074ec805d1ac1617 -COCOAPODS: 1.9.1 +COCOAPODS: 1.10.0 diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj index 268d7cc50..bc6e7614d 100644 --- a/example/ios/example.xcodeproj/project.pbxproj +++ b/example/ios/example.xcodeproj/project.pbxproj @@ -213,6 +213,7 @@ 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, + CEF8B2703D93599E45D6BF6B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -234,6 +235,7 @@ 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 14C94C1C1903F2189AE891A6 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -380,6 +382,24 @@ shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; }; + 14C94C1C1903F2189AE891A6 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -482,6 +502,24 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + CEF8B2703D93599E45D6BF6B /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/example/ios/example/AppDelegate.m b/example/ios/example/AppDelegate.m index 4ac2f6fba..c703e13b0 100644 --- a/example/ios/example/AppDelegate.m +++ b/example/ios/example/AppDelegate.m @@ -6,7 +6,7 @@ #import #import -#if DEBUG +#if FB_SONARKIT_ENABLED #import #import #import @@ -29,7 +29,7 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -#if DEBUG +#if FB_SONARKIT_ENABLED InitializeFlipper(application); #endif diff --git a/example/package.json b/example/package.json index ffdc79905..12d928851 100644 --- a/example/package.json +++ b/example/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@react-native-community/push-notification-ios": "^1.4.0", - "react": "16.11.0", - "react-native": "0.62.2", - "react-native-push-notification": "zo0r/react-native-push-notification#dev" + "react": "16.13.1", + "react-native": "0.63.3", + "react-native-push-notification": "lluis-sancho/react-native-push-notification" }, "devDependencies": { "@babel/core": "^7.9.0", From b343f50a80297ee84bd61bc4febce22b7e84ed3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Sancho?= Date: Sat, 12 Dec 2020 23:19:58 +0100 Subject: [PATCH 146/179] [Android] notification with inline reply (#612) --- README.md | 25 +++++++++++++ .../modules/RNPushNotification.java | 4 +- .../modules/RNPushNotificationActions.java | 12 +++++- .../modules/RNPushNotificationAttributes.java | 14 +++++++ .../modules/RNPushNotificationHelper.java | 37 ++++++++++++++++--- 5 files changed, 84 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bb4f20f52..c10b1dede 100644 --- a/README.md +++ b/README.md @@ -653,6 +653,31 @@ Make sure you have the receiver in `AndroidManifest.xml`: For iOS, you can use this [package](https://github.com/holmesal/react-native-ios-notification-actions) to add notification actions. +Notifications with inline reply: + +You must register an action as "ReplyInput", this will show in the notifications an input to write in. + +EXAMPLE: +```javascript +PushNotification.localNotificationSchedule({ + message: "My Notification Message", // (required) + date: new Date(Date.now() + (60 * 1000)), // in 60 secs + actions: ["ReplyInput"], + reply_placeholder_text: "Write your response...", // (required) + reply_button_text: "Reply" // (required) +}); +``` + +To get the text from the notification: + +```javascript +... +if(notification.action === "ReplyInput"){ + console.log("texto", notification.reply_text)// this will contain the inline reply text. +} +... + + ## Set application badge icon `PushNotification.setApplicationIconBadgeNumber(number: number)` 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 75a83ac5c..f6b1dba6a 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -8,7 +8,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; - import androidx.annotation.NonNull; import androidx.core.app.NotificationManagerCompat; @@ -41,6 +40,7 @@ public class RNPushNotification extends ReactContextBaseJavaModule implements ActivityEventListener { public static final String LOG_TAG = "RNPushNotification";// all logging should use this tag + public static final String KEY_TEXT_REPLY = "key_text_reply"; private RNPushNotificationHelper mRNPushNotificationHelper; private final SecureRandom mRandomNumberGenerator = new SecureRandom(); @@ -95,7 +95,7 @@ public void onNewIntent(Intent intent) { mJsDelivery.notifyNotification(bundle); } } - + @ReactMethod public void invokeApp(ReadableMap data) { Bundle bundle = null; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java index 612812561..9a7e038b7 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationActions.java @@ -13,8 +13,10 @@ import com.facebook.react.ReactApplication; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.ReactContext; +import androidx.core.app.RemoteInput; import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.KEY_TEXT_REPLY; public class RNPushNotificationActions extends BroadcastReceiver { @Override @@ -28,7 +30,15 @@ public void onReceive(final Context context, Intent intent) { } final Bundle bundle = intent.getBundleExtra("notification"); + Bundle remoteInput = null; + if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH){ + remoteInput = RemoteInput.getResultsFromIntent(intent); + } + if (remoteInput != null) { + // Add to reply_text the text written by the user in the notification + bundle.putCharSequence("reply_text", remoteInput.getCharSequence(KEY_TEXT_REPLY)); + } // Dismiss the notification popup. NotificationManager manager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); int notificationID = Integer.parseInt(bundle.getString("id")); @@ -87,4 +97,4 @@ public void onReactContextInitialized(ReactContext context) { }); } } -} \ No newline at end of file +} diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index d60306ea0..976757551 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -47,6 +47,8 @@ public class RNPushNotificationAttributes { private static final String TIMEOUT_AFTER = "timeoutAfter"; private static final String ONLY_ALERT_ONCE = "onlyAlertOnce"; private static final String ONGOING = "ongoing"; + private static final String REPLY_BUTTON_TEXT = "reply_button_text"; + private static final String REPLAY_PLACEHOLDER_TEXT = "reply_placeholder_text"; private static final String ALLOW_WHILE_IDLE = "allowWhileIdle"; private static final String IGNORE_IN_FOREGROUND = "ignoreInForeground"; @@ -84,6 +86,8 @@ public class RNPushNotificationAttributes { private final double timeoutAfter; private final boolean onlyAlertOnce; private final boolean ongoing; + private final String reply_button_text; + private final String reply_placeholder_text; private final boolean allowWhileIdle; private final boolean ignoreInForeground; @@ -122,6 +126,8 @@ public RNPushNotificationAttributes(Bundle bundle) { timeoutAfter = bundle.getDouble(TIMEOUT_AFTER); onlyAlertOnce = bundle.getBoolean(ONLY_ALERT_ONCE); ongoing = bundle.getBoolean(ONGOING); + reply_button_text = bundle.getString(REPLY_BUTTON_TEXT); + reply_placeholder_text = bundle.getString(REPLAY_PLACEHOLDER_TEXT); allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE); ignoreInForeground = bundle.getBoolean(IGNORE_IN_FOREGROUND); } @@ -162,6 +168,8 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { timeoutAfter = jsonObject.has(TIMEOUT_AFTER) ? jsonObject.getDouble(TIMEOUT_AFTER) : -1; onlyAlertOnce = jsonObject.has(ONLY_ALERT_ONCE) ? jsonObject.getBoolean(ONLY_ALERT_ONCE) : false; ongoing = jsonObject.has(ONGOING) ? jsonObject.getBoolean(ONGOING) : false; + reply_button_text = jsonObject.has(REPLY_BUTTON_TEXT) ? jsonObject.getString(REPLY_BUTTON_TEXT) : null; + reply_placeholder_text = jsonObject.has(REPLAY_PLACEHOLDER_TEXT) ? jsonObject.getString(REPLAY_PLACEHOLDER_TEXT) : null; allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; ignoreInForeground = jsonObject.has(IGNORE_IN_FOREGROUND) ? jsonObject.getBoolean(IGNORE_IN_FOREGROUND) : false; } catch (JSONException e) { @@ -259,6 +267,8 @@ public Bundle toBundle() { bundle.putDouble(TIMEOUT_AFTER, timeoutAfter); bundle.putBoolean(ONLY_ALERT_ONCE, onlyAlertOnce); bundle.putBoolean(ONGOING, ongoing); + bundle.putString(REPLY_BUTTON_TEXT, reply_button_text); + bundle.putString(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text); bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle); bundle.putBoolean(IGNORE_IN_FOREGROUND, ignoreInForeground); return bundle; @@ -301,6 +311,8 @@ public JSONObject toJson() { jsonObject.put(TIMEOUT_AFTER, timeoutAfter); jsonObject.put(ONLY_ALERT_ONCE, onlyAlertOnce); jsonObject.put(ONGOING, ongoing); + jsonObject.put(REPLY_BUTTON_TEXT, reply_button_text); + jsonObject.put(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text); jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle); jsonObject.put(IGNORE_IN_FOREGROUND, ignoreInForeground); } catch (JSONException e) { @@ -349,6 +361,8 @@ public String toString() { ", timeoutAfter=" + timeoutAfter + ", onlyAlertOnce=" + onlyAlertOnce + ", ongoing=" + ongoing + + ", reply_button_text=" + reply_button_text + + ", reply_placeholder_text=" + reply_placeholder_text + ", allowWhileIdle=" + allowWhileIdle + ", ignoreInForeground=" + ignoreInForeground + '}'; diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index e3dac9cc3..193e11297 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -23,6 +23,10 @@ import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; +import androidx.core.app.RemoteInput; + +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; @@ -46,6 +50,7 @@ import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; import static com.dieam.reactnativepushnotification.modules.RNPushNotificationAttributes.fromJson; +import static com.dieam.reactnativepushnotification.modules.RNPushNotification.KEY_TEXT_REPLY; public class RNPushNotificationHelper { public static final String PREFERENCES_KEY = "rn_push_notification"; @@ -514,13 +519,35 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB PendingIntent pendingActionIntent = PendingIntent.getBroadcast(context, notificationID, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - notification.addAction(new NotificationCompat.Action.Builder(icon, action, pendingActionIntent).build()); - } else { - notification.addAction(icon, action, pendingActionIntent); + if(action.equals("ReplyInput")){ + //Action with inline reply + if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH){ + RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) + .setLabel(bundle.getString("reply_placeholder_text")) + .build(); + NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder( + icon, bundle.getString("reply_button_text"), pendingActionIntent) + .addRemoteInput(remoteInput) + .setAllowGeneratedReplies(true) + .build(); + + notification.addAction(replyAction); + } + else{ + // The notification will not have action + break; + } + } + else{ + // Add "action" for later identifying which button gets pressed + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + notification.addAction(new NotificationCompat.Action.Builder(icon, action, pendingActionIntent).build()); + } else { + notification.addAction(icon, action, pendingActionIntent); + } } } + } // Remove the notification from the shared preferences once it has been shown From c12315c27b22e33540758c40022f2b1a9672108e Mon Sep 17 00:00:00 2001 From: vanso-hubsi Date: Sat, 12 Dec 2020 23:31:52 +0100 Subject: [PATCH 147/179] implement 'bigLargeIcon' for Android notifications (#1730) * implement 'bigLargeIcon' for Android notifications * fix (non-url) bigLargeIcon Co-authored-by: hubsif --- README.md | 2 + .../modules/RNPushNotificationHelper.java | 25 +++++++++-- .../RNPushNotificationPicturesAggregator.java | 43 +++++++++++++++++-- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c10b1dede..daf8a2859 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,8 @@ PushNotification.localNotification({ bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop subText: "This is a subText", // (optional) default: none bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined + bigLargeIcon: "ic_launcher", // (optional) default: undefined + bigLargeIconUrl: "https://www.example.tld/bigicon.jpg", // (optional) default: undefined color: "red", // (optional) default: system default vibrate: true, // (optional) default: true vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 193e11297..842cbdfff 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -191,16 +191,17 @@ public void sendNotificationScheduledCore(Bundle bundle) { public void sendToNotificationCentre(final Bundle bundle) { RNPushNotificationPicturesAggregator aggregator = new RNPushNotificationPicturesAggregator(new RNPushNotificationPicturesAggregator.Callback() { - public void call(Bitmap largeIconImage, Bitmap bigPictureImage) { - sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage); + public void call(Bitmap largeIconImage, Bitmap bigPictureImage, Bitmap bigLargeIconImage) { + sendToNotificationCentreWithPicture(bundle, largeIconImage, bigPictureImage, bigLargeIconImage); } }); aggregator.setLargeIconUrl(context, bundle.getString("largeIconUrl")); + aggregator.setBigLargeIconUrl(context, bundle.getString("bigLargeIconUrl")); aggregator.setBigPictureUrl(context, bundle.getString("bigPictureUrl")); } - public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconBitmap, Bitmap bigPictureBitmap) { + public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconBitmap, Bitmap bigPictureBitmap, Bitmap bigLargeIconBitmap) { try { Class intentClass = getMainActivityClass(); if (intentClass == null) { @@ -380,10 +381,26 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB NotificationCompat.Style style; if(bigPictureBitmap != null) { + + // Big large icon + if(bigLargeIconBitmap == null) { + int bigLargeIconResId = 0; + + String bigLargeIcon = bundle.getString("bigLargeIcon"); + + if (bigLargeIcon != null && !bigLargeIcon.isEmpty()) { + bigLargeIconResId = res.getIdentifier(bigLargeIcon, "mipmap", packageName); + if (bigLargeIconResId != 0) { + bigLargeIconBitmap = BitmapFactory.decodeResource(res, bigLargeIconResId); + } + } + } + style = new NotificationCompat.BigPictureStyle() .bigPicture(bigPictureBitmap) .setBigContentTitle(title) - .setSummaryText(message); + .setSummaryText(message) + .bigLargeIcon(bigLargeIconBitmap); } else { style = new NotificationCompat.BigTextStyle().bigText(bigText); diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java index 27c7389a8..733bcbe44 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationPicturesAggregator.java @@ -22,13 +22,14 @@ public class RNPushNotificationPicturesAggregator { interface Callback { - public void call(Bitmap largeIconImage, Bitmap bigPictureImage); + public void call(Bitmap largeIconImage, Bitmap bigPictureImage, Bitmap bigLargeIconImage); } private AtomicInteger count = new AtomicInteger(0); private Bitmap largeIconImage; private Bitmap bigPictureImage; + private Bitmap bigLargeIconImage; private Callback callback; @@ -108,6 +109,42 @@ public void onFailureImpl(DataSource dataSource) { }); } + public void setBigLargeIcon(Bitmap bitmap) { + this.bigLargeIconImage = bitmap; + this.finished(); + } + + public void setBigLargeIconUrl(Context context, String url) { + if(null == url) { + this.setBigLargeIcon(null); + return; + } + + Uri uri = null; + + try { + uri = Uri.parse(url); + } catch(Exception ex) { + Log.e(LOG_TAG, "Failed to parse bigLargeIconUrl", ex); + this.setBigLargeIcon(null); + return; + } + + final RNPushNotificationPicturesAggregator aggregator = this; + + this.downloadRequest(context, uri, new BaseBitmapDataSubscriber() { + @Override + public void onNewResultImpl(@Nullable Bitmap bitmap) { + aggregator.setBigLargeIcon(bitmap); + } + + @Override + public void onFailureImpl(DataSource dataSource) { + aggregator.setBigLargeIcon(null); + } + }); + } + private void downloadRequest(Context context, Uri uri, BaseBitmapDataSubscriber subscriber) { ImageRequest imageRequest = ImageRequestBuilder .newBuilderWithSource(uri) @@ -128,8 +165,8 @@ private void finished() { synchronized(this.count) { int val = this.count.incrementAndGet(); - if(val >= 2 && this.callback != null) { - this.callback.call(this.largeIconImage, this.bigPictureImage); + if(val >= 3 && this.callback != null) { + this.callback.call(this.largeIconImage, this.bigPictureImage, this.bigLargeIconImage); } } } From 2e5fa1c2297e834070b2f0041273936fec75d130 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 12 Dec 2020 23:37:06 +0100 Subject: [PATCH 148/179] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f873a231..0c27bd2a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Features +- (Android) implement 'bigLargeIcon' for Android notifications (must be combined with BigPicture) [#1730](https://github.com/zo0r/react-native-push-notification/pull/1730) +- (Android) notification with inline reply [#612](https://github.com/zo0r/react-native-push-notification/pull/612) + ### Fixed ## [6.1.3] 2020-11-09 From 629c532cce186e3bd3968aaec101d8a0182fd29a Mon Sep 17 00:00:00 2001 From: Jason Ho Date: Tue, 22 Dec 2020 13:23:09 -0800 Subject: [PATCH 149/179] Default using drawable as Android small icon --- .../modules/RNPushNotificationHelper.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 4af0411f1..504a3b864 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -319,9 +319,12 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB String smallIcon = bundle.getString("smallIcon"); if (smallIcon != null && !smallIcon.isEmpty()) { - smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); + smallIconResId = res.getIdentifier(smallIcon, "drawable", packageName); + if (smallIconResId == 0) { + smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName); + } } else if(smallIcon == null) { - smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); + smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName); } if (smallIconResId == 0) { @@ -341,9 +344,9 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB String largeIcon = bundle.getString("largeIcon"); if (largeIcon != null && !largeIcon.isEmpty()) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); + largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); } else if(largeIcon == null) { - largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); + largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); } // Before Lolipop there was no large icon for notifications. From 3e87b12a7ecc3d4adda1f59e97d18269f1e60b28 Mon Sep 17 00:00:00 2001 From: Jason Ho Date: Wed, 23 Dec 2020 11:04:52 -0800 Subject: [PATCH 150/179] Default using drawable as Android large icon --- .../modules/RNPushNotificationHelper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 504a3b864..a4e0af3bb 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -344,7 +344,10 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB String largeIcon = bundle.getString("largeIcon"); if (largeIcon != null && !largeIcon.isEmpty()) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); + largeIconResId = res.getIdentifier(largeIcon, "drawable", packageName); + if (largeIconResId == 0) { + largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); + } } else if(largeIcon == null) { largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); } From 3641bf66cc6147715a272069167cf48de3d2a00e Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 23 Dec 2020 22:41:38 +0100 Subject: [PATCH 151/179] Release 7.0.0 --- CHANGELOG.md | 13 ++- README.md | 12 ++- .../modules/RNPushNotificationAttributes.java | 86 ++++++++++++------- .../modules/RNPushNotificationHelper.java | 5 +- example/package.json | 2 +- index.js | 32 ++++++- package.json | 2 +- 7 files changed, 109 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c27bd2a1..80b03dacc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,15 +8,24 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes +### Features + +### Fixed + +## [7.0.0] 2020-12-23 + +### Breaking changes + - (iOS) Replace deprecated local notification methods on iOS [1751](https://github.com/zo0r/react-native-push-notification/pull/1751) - (Android) Rename the Android package from `ReactNativePushNotification` to `ReactNativePushNotification` resolve [893](https://github.com/zo0r/react-native-push-notification/issues/893) +- (Android) Allow `userInfo` to be stored in scheduled notification as in iOS (mapped as `data` on press or list scheduled notifications). ### Features +- (Android) silent channel using playSound flag - (Android) implement 'bigLargeIcon' for Android notifications (must be combined with BigPicture) [#1730](https://github.com/zo0r/react-native-push-notification/pull/1730) - (Android) notification with inline reply [#612](https://github.com/zo0r/react-native-push-notification/pull/612) - -### Fixed +- (Android) Support using drawable as Android small icon [#1787](https://github.com/zo0r/react-native-push-notification/pull/1787) ## [6.1.3] 2020-11-09 diff --git a/README.md b/README.md index d372f23c0..7691be011 100644 --- a/README.md +++ b/README.md @@ -653,8 +653,6 @@ Make sure you have the receiver in `AndroidManifest.xml`: ``` -For iOS, you can use this [package](https://github.com/holmesal/react-native-ios-notification-actions) to add notification actions. - Notifications with inline reply: You must register an action as "ReplyInput", this will show in the notifications an input to write in. @@ -678,7 +676,17 @@ if(notification.action === "ReplyInput"){ console.log("texto", notification.reply_text)// this will contain the inline reply text. } ... +``` + +For iOS, you can use: + +```javascript +PushNotification.setNotificationCategories(categories); +``` + +And use the `category` field in the notification. +Documentation [here](https://github.com/react-native-push-notification-ios/push-notification-ios#how-to-perform-different-action-based-on-user-selected-action) to add notification actions. ## Set application badge icon diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java index 976757551..a2d3d5657 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationAttributes.java @@ -10,6 +10,8 @@ import org.json.JSONException; import org.json.JSONObject; +import java.util.Iterator; + import static com.dieam.reactnativepushnotification.modules.RNPushNotification.LOG_TAG; public class RNPushNotificationAttributes { @@ -51,6 +53,7 @@ public class RNPushNotificationAttributes { private static final String REPLAY_PLACEHOLDER_TEXT = "reply_placeholder_text"; private static final String ALLOW_WHILE_IDLE = "allowWhileIdle"; private static final String IGNORE_IN_FOREGROUND = "ignoreInForeground"; + private static final String USER_INFO = "userInfo"; private final String id; private final String message; @@ -90,6 +93,7 @@ public class RNPushNotificationAttributes { private final String reply_placeholder_text; private final boolean allowWhileIdle; private final boolean ignoreInForeground; + private final String userInfo; public RNPushNotificationAttributes(Bundle bundle) { id = bundle.getString(ID); @@ -130,6 +134,7 @@ public RNPushNotificationAttributes(Bundle bundle) { reply_placeholder_text = bundle.getString(REPLAY_PLACEHOLDER_TEXT); allowWhileIdle = bundle.getBoolean(ALLOW_WHILE_IDLE); ignoreInForeground = bundle.getBoolean(IGNORE_IN_FOREGROUND); + userInfo = bundle.getString(USER_INFO); } private RNPushNotificationAttributes(JSONObject jsonObject) { @@ -172,6 +177,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { reply_placeholder_text = jsonObject.has(REPLAY_PLACEHOLDER_TEXT) ? jsonObject.getString(REPLAY_PLACEHOLDER_TEXT) : null; allowWhileIdle = jsonObject.has(ALLOW_WHILE_IDLE) ? jsonObject.getBoolean(ALLOW_WHILE_IDLE) : false; ignoreInForeground = jsonObject.has(IGNORE_IN_FOREGROUND) ? jsonObject.getBoolean(IGNORE_IN_FOREGROUND) : false; + userInfo = jsonObject.has(USER_INFO) ? jsonObject.getString(USER_INFO) : null; } catch (JSONException e) { throw new IllegalStateException("Exception while initializing RNPushNotificationAttributes from JSON", e); } @@ -180,6 +186,7 @@ private RNPushNotificationAttributes(JSONObject jsonObject) { @NonNull public static RNPushNotificationAttributes fromJson(String notificationAttributesJson) throws JSONException { JSONObject jsonObject = new JSONObject(notificationAttributesJson); + return new RNPushNotificationAttributes(jsonObject); } @@ -191,41 +198,49 @@ public static RNPushNotificationAttributes fromJson(String notificationAttribute * @return true all fields in userInfo object match, false otherwise */ public boolean matches(ReadableMap userInfo) { - Bundle bundle = toBundle(); + try { + if(this.userInfo == null) { + return false; + } + + JSONObject jsonObject = new JSONObject(this.userInfo); - ReadableMapKeySetIterator iterator = userInfo.keySetIterator(); - while (iterator.hasNextKey()) { - String key = iterator.nextKey(); + ReadableMapKeySetIterator iterator = userInfo.keySetIterator(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); - if (!bundle.containsKey(key)) - return false; + if (!jsonObject.has(key)) + return false; - switch (userInfo.getType(key)) { - case Null: { - if (bundle.get(key) != null) - return false; - break; - } - case Boolean: { - if (userInfo.getBoolean(key) != bundle.getBoolean(key)) - return false; - break; - } - case Number: { - if ((userInfo.getDouble(key) != bundle.getDouble(key)) && (userInfo.getInt(key) != bundle.getInt(key))) - return false; - break; - } - case String: { - if (!userInfo.getString(key).equals(bundle.getString(key))) - return false; - break; - } - case Map: - return false;//there are no maps in the bundle - case Array: - return false;//there are no arrays in the bundle - } + switch (userInfo.getType(key)) { + case Null: { + if (jsonObject.get(key) != null) + return false; + break; + } + case Boolean: { + if (userInfo.getBoolean(key) != jsonObject.getBoolean(key)) + return false; + break; + } + case Number: { + if ((userInfo.getDouble(key) != jsonObject.getDouble(key)) && (userInfo.getInt(key) != jsonObject.getInt(key))) + return false; + break; + } + case String: { + if (!userInfo.getString(key).equals(jsonObject.getString(key))) + return false; + break; + } + case Map: + return false;//there are no maps in the jsonObject + case Array: + return false;//there are no arrays in the jsonObject + } + } + } catch(JSONException e) { + return false; } return true; @@ -271,6 +286,7 @@ public Bundle toBundle() { bundle.putString(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text); bundle.putBoolean(ALLOW_WHILE_IDLE, allowWhileIdle); bundle.putBoolean(IGNORE_IN_FOREGROUND, ignoreInForeground); + bundle.putString(USER_INFO, userInfo); return bundle; } @@ -315,6 +331,7 @@ public JSONObject toJson() { jsonObject.put(REPLAY_PLACEHOLDER_TEXT, reply_placeholder_text); jsonObject.put(ALLOW_WHILE_IDLE, allowWhileIdle); jsonObject.put(IGNORE_IN_FOREGROUND, ignoreInForeground); + jsonObject.put(USER_INFO, userInfo); } catch (JSONException e) { Log.e(LOG_TAG, "Exception while converting RNPushNotificationAttributes to " + "JSON. Returning an empty object", e); @@ -365,6 +382,7 @@ public String toString() { ", reply_placeholder_text=" + reply_placeholder_text + ", allowWhileIdle=" + allowWhileIdle + ", ignoreInForeground=" + ignoreInForeground + + ", userInfo=" + userInfo + '}'; } @@ -388,6 +406,10 @@ public String getNumber() { return number; } + public String getUserInfo() { + return userInfo; + } + public String getRepeatType() { return repeatType; } diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index 64d780c2a..07489bef2 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -431,10 +431,6 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { String soundName = bundle.getString("soundName"); - if (soundName == null) { - soundName = "default"; - } - soundUri = getSoundUri(soundName); notification.setSound(soundUri); @@ -772,6 +768,7 @@ public WritableArray getScheduledLocalNotifications() { notificationMap.putString("id", notification.getId()); notificationMap.putString("repeatInterval", notification.getRepeatType()); notificationMap.putString("soundName", notification.getSound()); + notificationMap.putString("data", notification.getUserInfo()); scheduled.pushMap(notificationMap); } catch (JSONException e) { diff --git a/example/package.json b/example/package.json index 12d928851..11eb4b7c3 100644 --- a/example/package.json +++ b/example/package.json @@ -14,7 +14,7 @@ "@react-native-community/push-notification-ios": "^1.4.0", "react": "16.13.1", "react-native": "0.63.3", - "react-native-push-notification": "lluis-sancho/react-native-push-notification" + "react-native-push-notification": "zo0r/react-native-push-notification#master" }, "devDependencies": { "@babel/core": "^7.9.0", diff --git a/index.js b/index.js index 941388c68..f06e4d913 100644 --- a/index.js +++ b/index.js @@ -210,6 +210,10 @@ Notifications.localNotification = function(details) { if(details && Array.isArray(details.actions)) { details.actions = JSON.stringify(details.actions); } + + if(details.userInfo) { + details.userInfo = JSON.stringify(details.userInfo); + } this.handler.presentLocalNotification(details); } @@ -289,6 +293,10 @@ Notifications.localNotificationSchedule = function(details) { details.actions = JSON.stringify(details.actions); } + if(details.userInfo) { + details.userInfo = JSON.stringify(details.userInfo); + } + details.fireDate = details.date.getTime(); delete details.date; // ignore iOS only repeatType @@ -360,6 +368,8 @@ Notifications._transformNotificationObject = function(data, isFromBackground = n title: data.getTitle(), soundName: data.getSound(), fireDate: Date.parse(data._fireDate), + action: data.getActionIdentifier(), + reply_text: data.getUserText(), finish: (res) => data.finish(res) }; @@ -381,6 +391,15 @@ Notifications._transformNotificationObject = function(data, isFromBackground = n /* void */ } } + + if ( typeof _notification.userInfo === 'string' ) { + try { + _notification.userInfo = JSON.parse(_notification.userInfo); + } catch(e) { + /* void */ + } + } + _notification.data = { ...(typeof _notification.userInfo === 'object' ? _notification.userInfo : {}), @@ -521,11 +540,17 @@ Notifications.getScheduledLocalNotifications = function(callback) { date: (notif.date ? new Date(notif.date) : null), number: notif?.badge, message: notif?.body, - title: notif?.title, + title: notif?.title, + data: notif?.userInfo }) }) } else if(Platform.OS === 'android') { mappedNotifications = notifications.map(notif => { + + try { + notif.data = JSON.parse(notif.data); + } catch(e) { } + return ({ soundName: notif.soundName, repeatInterval: notif.repeatInterval, @@ -534,6 +559,7 @@ Notifications.getScheduledLocalNotifications = function(callback) { number: notif.number, message: notif.message, title: notif.title, + data: notif.data, }) }) } @@ -576,4 +602,8 @@ Notifications.deleteChannel = function() { return this.callNative('deleteChannel', arguments); }; +Notifications.setNotificationCategories = function() { + return this.callNative('setNotificationCategories', arguments); +} + module.exports = Notifications; diff --git a/package.json b/package.json index 17ed4f291..d10492967 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "6.1.3", + "version": "7.0.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From 568f25f0adaed42687d241be99b39806afabbfc0 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 23 Dec 2020 22:47:12 +0100 Subject: [PATCH 152/179] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7691be011..e7520914d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ React Native Local and Remote Notifications for iOS and Android -## 🎉 Version 6.x is live ! 🎉 +## 🎉 Version 7.x is live ! 🎉 Check out for changes and migration in the CHANGELOG: From 268265829a79cece530716c7201d09bf212cff0d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 23 Dec 2020 22:49:03 +0100 Subject: [PATCH 153/179] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b03dacc..3f4b81509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Breaking changes - (iOS) Replace deprecated local notification methods on iOS [1751](https://github.com/zo0r/react-native-push-notification/pull/1751) -- (Android) Rename the Android package from `ReactNativePushNotification` to `ReactNativePushNotification` resolve [893](https://github.com/zo0r/react-native-push-notification/issues/893) +- (Android) Rename the Android package from `RNPushNotification` to `ReactNativePushNotification` resolve [893](https://github.com/zo0r/react-native-push-notification/issues/893) - (Android) Allow `userInfo` to be stored in scheduled notification as in iOS (mapped as `data` on press or list scheduled notifications). ### Features From 21a101f40d4de72fd12f75eb4d82b9f2fbcaee0d Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sat, 26 Dec 2020 23:43:40 +0400 Subject: [PATCH 154/179] (fix) deep clone details and notifications --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index f06e4d913..40ce91324 100644 --- a/index.js +++ b/index.js @@ -145,7 +145,7 @@ Notifications.unregister = function() { * @param {String} details.ticker - ANDROID ONLY: The ticker displayed in the status bar. * @param {Object} details.userInfo - iOS ONLY: The userInfo used in the notification alert. */ -Notifications.localNotification = function(details) { +Notifications.localNotification = function({...details}) { if ('android' === Platform.os && details && !details.channelId) { console.warn('No channel id passed, notifications may not work.'); } @@ -224,7 +224,7 @@ Notifications.localNotification = function(details) { * @param {Object} details (same as localNotification) * @param {Date} details.date - The date and time when the system should deliver the notification */ -Notifications.localNotificationSchedule = function(details) { +Notifications.localNotificationSchedule = function({...details}) { if ('android' === Platform.os && details && !details.channelId) { console.warn('No channel id passed, notifications may not work.'); } @@ -329,7 +329,7 @@ Notifications._onRemoteFetch = function(notificationData) { } }; -Notifications._onAction = function(notification) { +Notifications._onAction = function({...notification}) { if ( typeof notification.data === 'string' ) { try { notification.data = JSON.parse(notificationData.data); From c052494b8aec072302d00dd1dbfcdabe0e45b87c Mon Sep 17 00:00:00 2001 From: Cayley Humphries Date: Wed, 13 Jan 2021 11:17:35 -0800 Subject: [PATCH 155/179] [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); From b8949c2e7d9f5aa125bb76d3a8bcda536ea44fc5 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 16 Jan 2021 21:50:47 +0100 Subject: [PATCH 156/179] Update to 7.1.0. --- CHANGELOG.md | 4 ++++ example/package.json | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f4b81509..33326bd3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ### Fixed +## [7.1.0] 2021-01-16 + +- (Android) Add hooks to intent handling and bundle parsing [1819](https://github.com/zo0r/react-native-push-notification/pull/1819) + ## [7.0.0] 2020-12-23 ### Breaking changes diff --git a/example/package.json b/example/package.json index 11eb4b7c3..eed46cbab 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,7 @@ "pod-install": "cd ios && pod install" }, "dependencies": { - "@react-native-community/push-notification-ios": "^1.4.0", + "@react-native-community/push-notification-ios": "^1.7.0", "react": "16.13.1", "react-native": "0.63.3", "react-native-push-notification": "zo0r/react-native-push-notification#master" diff --git a/package.json b/package.json index d10492967..9516dd79f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-push-notification", - "version": "7.0.0", + "version": "7.1.0", "description": "React Native Local and Remote Notifications", "main": "index.js", "scripts": { From b555040091a8cd335d408fe902dd2ae6d8f0211d Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Sat, 16 Jan 2021 21:52:01 +0100 Subject: [PATCH 157/179] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33326bd3e..c84af38da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## [7.1.0] 2021-01-16 +# Features + - (Android) Add hooks to intent handling and bundle parsing [1819](https://github.com/zo0r/react-native-push-notification/pull/1819) ## [7.0.0] 2020-12-23 From 4d43ddb7893bb00aa0baf39984d3b690fe83055e Mon Sep 17 00:00:00 2001 From: Mostafa Arafa Date: Tue, 19 Jan 2021 12:12:53 +0200 Subject: [PATCH 158/179] unsubscribeFromTopic fix --- component/index.android.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/component/index.android.js b/component/index.android.js index 249559479..3496c045b 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -32,6 +32,10 @@ NotificationsComponent.prototype.subscribeToTopic = function(topic) { RNPushNotification.subscribeToTopic(topic); }; +NotificationsComponent.prototype.unsubscribeFromTopic = function(topic) { + RNPushNotification.unsubscribeFromTopic(topic); +}; + NotificationsComponent.prototype.cancelLocalNotifications = function(details) { RNPushNotification.cancelLocalNotifications(details); }; From 036b194af7340fea01be1bd2de49dffb15fb6140 Mon Sep 17 00:00:00 2001 From: Boris Tacyniak Date: Wed, 20 Jan 2021 09:46:34 +0100 Subject: [PATCH 159/179] Release fix 7.1.1. --- .github/ISSUE_TEMPLATE/bug_report.md | 2 ++ CHANGELOG.md | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1b8aec628..df62fddde 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,6 +6,8 @@ about: Report a reproducible bug or regression in this library. # Bug