From 89806d97f73ef9aea903c75e23d898bc3fdfff81 Mon Sep 17 00:00:00 2001 From: David Gruseck Date: Mon, 7 May 2018 17:35:10 +0200 Subject: [PATCH] [Android] Add the ability to remove notifications based on the tag --- .../notifications/DisplayNotificationTask.java | 7 ++++++- .../RNFirebaseNotificationManager.java | 12 +++++++++++- .../notifications/RNFirebaseNotifications.java | 6 ++++++ .../notifications/RNFirebaseNotifications.m | 13 ++++++++++--- lib/index.d.ts | 2 ++ .../notifications/AndroidNotification.js | 17 +++++++++++++++++ lib/modules/notifications/index.js | 15 +++++++++++++++ lib/modules/notifications/types.js | 1 + 8 files changed, 68 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java b/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java index cb2b069f..99aa6e38 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java +++ b/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java @@ -272,13 +272,18 @@ public class DisplayNotificationTask extends AsyncTask { } } + String tag = null; + if (android.containsKey("tag")) { + tag = android.getString("tag"); + } + // Create the notification intent PendingIntent contentIntent = createIntent(intentClass, notification, android.getString("clickAction")); nb = nb.setContentIntent(contentIntent); // Build the notification and send it Notification builtNotification = nb.build(); - notificationManager.notify(notificationId.hashCode(), builtNotification); + notificationManager.notify(tag, notificationId.hashCode(), builtNotification); if (reactContext != null) { Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification)); diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java index fccab1ee..2201129c 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java @@ -17,6 +17,7 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.service.notification.StatusBarNotification; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; @@ -139,7 +140,7 @@ public class RNFirebaseNotificationManager { if (!notification.getBundle("schedule").containsKey("repeated") || !notification.getBundle("schedule").getBoolean("repeated")) { String notificationId = notification.getString("notificationId"); - preferences.edit().remove(notificationId).apply();; + preferences.edit().remove(notificationId).apply(); } if (Utils.isAppInForeground(context)) { @@ -181,6 +182,15 @@ public class RNFirebaseNotificationManager { promise.resolve(null); } + public void removeDeliveredNotificationsByTag(String tag, Promise promise) { + StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications(); + for (StatusBarNotification statusBarNotification : statusBarNotifications) { + if (statusBarNotification.getTag() == tag) { + notificationManager.cancel(statusBarNotification.getTag(), statusBarNotification.getId()); + } + } + promise.resolve(null); + } public void rescheduleNotifications() { ArrayList bundles = getScheduledNotifications(); diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java index f8236e23..b096dfa4 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java @@ -112,6 +112,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen notificationManager.removeDeliveredNotification(notificationId, promise); } + @ReactMethod + public void removeDeliveredNotificationsByTag(String tag, Promise promise) { + notificationManager.removeDeliveredNotificationsByTag(tag, promise); + } + @ReactMethod public void setBadge(int badge, Promise promise) { // Store the badge count for later retrieval @@ -284,6 +289,7 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen } if (notification.getTag() != null) { androidMap.putString("group", notification.getTag()); + androidMap.putString("tag", notification.getTag()); } notificationMap.putMap("android", androidMap); diff --git a/ios/RNFirebase/notifications/RNFirebaseNotifications.m b/ios/RNFirebase/notifications/RNFirebaseNotifications.m index 274f4d7d..c30fbcad 100644 --- a/ios/RNFirebase/notifications/RNFirebaseNotifications.m +++ b/ios/RNFirebase/notifications/RNFirebaseNotifications.m @@ -343,6 +343,13 @@ RCT_EXPORT_METHOD(removeDeliveredNotification:(NSString*) notificationId resolve(nil); } +RCT_EXPORT_METHOD(removeDeliveredNotificationsByTag:(NSString*) tag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + // No implementation for ios + resolve(nil); +} + RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { @@ -372,7 +379,7 @@ RCT_EXPORT_METHOD(setBadge:(NSInteger) number resolve(nil); }); } - + RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { jsReady = TRUE; resolve(nil); @@ -487,11 +494,11 @@ RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro NSString *identifier = a[@"identifier"]; NSURL *url = [NSURL fileURLWithPath:a[@"url"]]; NSMutableDictionary *attachmentOptions = nil; - + if (a[@"options"]) { NSDictionary *options = a[@"options"]; attachmentOptions = [[NSMutableDictionary alloc] init]; - + for (id key in options) { if ([key isEqualToString:@"typeHint"]) { attachmentOptions[UNNotificationAttachmentOptionsTypeHintKey] = options[key]; diff --git a/lib/index.d.ts b/lib/index.d.ts index bdb5eb6e..0af68363 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1181,6 +1181,7 @@ declare module 'react-native-firebase' { showWhen?: boolean; smallIcon?: any; sortKey?: string; + tag?: string; ticker?: string; timeoutAfter?: number; usesChronometer?: boolean; @@ -1233,6 +1234,7 @@ declare module 'react-native-firebase' { setShowWhen(showWhen: boolean): Notification; setSmallIcon(icon: string, level?: number): Notification; setSortKey(sortKey: string): Notification; + setTag(tag: string): Notification; setTicker(ticker: string): Notification; setTimeoutAfter(timeoutAfter: number): Notification; setUsesChronometer(usesChronometer: boolean): Notification; diff --git a/lib/modules/notifications/AndroidNotification.js b/lib/modules/notifications/AndroidNotification.js index 915b112b..0545707a 100644 --- a/lib/modules/notifications/AndroidNotification.js +++ b/lib/modules/notifications/AndroidNotification.js @@ -53,6 +53,7 @@ export default class AndroidNotification { _smallIcon: SmallIcon; _sortKey: string | void; // TODO: style: Style; // Need to figure out if this can work + _tag: string | void; _ticker: string | void; _timeoutAfter: number | void; _usesChronometer: boolean | void; @@ -106,6 +107,7 @@ export default class AndroidNotification { this._showWhen = data.showWhen; this._smallIcon = data.smallIcon; this._sortKey = data.sortKey; + this._tag = data.tag; this._ticker = data.ticker; this._timeoutAfter = data.timeoutAfter; this._usesChronometer = data.usesChronometer; @@ -238,6 +240,10 @@ export default class AndroidNotification { return this._sortKey; } + get tag(): ?string { + return this._tag; + } + get ticker(): ?string { return this._ticker; } @@ -615,6 +621,16 @@ export default class AndroidNotification { return this._notification; } + /** + * + * @param tag + * @returns {Notification} + */ + setTag(tag: string): Notification { + this._tag = tag; + return this._notification; + } + /** * * @param ticker @@ -709,6 +725,7 @@ export default class AndroidNotification { smallIcon: this._smallIcon, sortKey: this._sortKey, // TODO: style: Style, + tag: this._tag, ticker: this._ticker, timeoutAfter: this._timeoutAfter, usesChronometer: this._usesChronometer, diff --git a/lib/modules/notifications/index.js b/lib/modules/notifications/index.js index b42d3d65..6a6267c6 100644 --- a/lib/modules/notifications/index.js +++ b/lib/modules/notifications/index.js @@ -291,6 +291,21 @@ export default class Notifications extends ModuleBase { return getNativeModule(this).removeDeliveredNotification(notificationId); } + /** + * Remove a delivered notifications by tag. + * @param tag + */ + removeDeliveredNotificationsByTag(tag: string): Promise { + if (!tag) { + return Promise.reject( + new Error( + 'Notifications: removeDeliveredNotificationsByTag expects a `tag`' + ) + ); + } + return getNativeModule(this).removeDeliveredNotificationsByTag(tag); + } + /** * Schedule a notification * @param notification diff --git a/lib/modules/notifications/types.js b/lib/modules/notifications/types.js index 780eabab..21364518 100644 --- a/lib/modules/notifications/types.js +++ b/lib/modules/notifications/types.js @@ -170,6 +170,7 @@ export type NativeAndroidNotification = {| smallIcon: SmallIcon, sortKey?: string, // TODO: style: Style, + tag?: string, ticker?: string, timeoutAfter?: number, usesChronometer?: boolean,