diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 56b20748..ecef6077 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -1,20 +1,19 @@ --- -name: ⚠️ Bug/Issue report -about: Please provide as much detail as possible to help us with a bug or issue. Issues +name: ⚠️ Bug/Issue report +about: Please provide as much detail as possible to help us with a bug or issue. Issues will be closed if they do not follow the template. - --- - ### Issue @@ -23,7 +22,7 @@ The issue list of this repo is exclusively for bug reports. ### Environment -1. Application Target Platform: +1. Application Target Platform: @@ -47,14 +46,14 @@ The issue list of this repo is exclusively for bug reports. -7. Are you using `typescript`? +7. Are you using `typescript`? - --- + Loving `react-native-firebase`? Please consider supporting them with any of the below: - - 👉 Back financially via [Open Collective](https://opencollective.com/react-native-firebase/donate) - - 👉 Follow [`React Native Firebase`](https://twitter.com/rnfirebase) and [`Invertase`](https://twitter.com/invertaseio) on Twitter - - 👉 Star this repo on GitHub ⭐️ +* 👉 Back financially via [Open Collective](https://opencollective.com/react-native-firebase/donate) +* 👉 Follow [`React Native Firebase`](https://twitter.com/rnfirebase) and [`Invertase`](https://twitter.com/invertaseio) on Twitter +* 👉 Star this repo on GitHub ⭐️ diff --git a/README.md b/README.md index efc70c90..c74bccb6 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a | **Crashlytics**           | ❌ | ✅ | ✅ | ❌ | | **Crash Reporting** | ✅ | ✅ | ✅ | ❌ | | **Dynamic Links** | ❌ | ✅ | ✅ | ❌ | -| **[Functions Callable](https://firebase.googleblog.com/2018/04/launching-cloud-functions-for-firebase-1-0.html?m=1)**             |   ❌   |   ❌   | ✅ |   ✅   | +| **[Functions Callable](https://firebase.googleblog.com/2018/04/launching-cloud-functions-for-firebase-1-0.html?m=1)**             |   ❌   |   ❌   | ✅ |   ✅   | | **Invites** | ❌ | ❌ | ✅ | ❌ | | **Instance ID**          | ❌ | ❌ | **?** | ❌ | | **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ | @@ -64,11 +64,11 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a > The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`. -| | 2.2.x | 3.3.x | 4.0.x | 4.1.x | 4.2.x | -| -------------------- | -------- | -------- | -------- | -------- | -------- | -| React Native | 0.47 + | 0.50 + | 0.52 + | 0.52 + | 0.52-55.x | -| Firebase Android SDK | 11.0.0 + | 11.8.0 + | 12.0.0 + | 15.0.0 + | 15.0.0 + | -| Firebase iOS SDK | 4.0.0 + | 4.7.0 + | 4.11.0 + | 4.13.0 + | 5.0.0 + | +| | 2.2.x | 3.3.x | 4.0.x | 4.1.x | 4.2.x | +| -------------------- | -------- | -------- | -------- | -------- | --------- | +| React Native | 0.47 + | 0.50 + | 0.52 + | 0.52 + | 0.52-55.x | +| Firebase Android SDK | 11.0.0 + | 11.8.0 + | 12.0.0 + | 15.0.0 + | 15.0.0 + | +| Firebase iOS SDK | 4.0.0 + | 4.7.0 + | 4.11.0 + | 4.13.0 + | 5.0.0 + | --- 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 00cf83f5..ffc3c5d1 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java +++ b/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java @@ -279,13 +279,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 60351ef6..f347306d 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; @@ -153,7 +154,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)) { @@ -195,6 +196,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 d9ffd5c3..3e9704ce 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 @@ -296,6 +301,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..2b8a0553 100644 --- a/ios/RNFirebase/notifications/RNFirebaseNotifications.m +++ b/ios/RNFirebase/notifications/RNFirebaseNotifications.m @@ -372,7 +372,7 @@ RCT_EXPORT_METHOD(setBadge:(NSInteger) number resolve(nil); }); } - + RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { jsReady = TRUE; resolve(nil); @@ -487,11 +487,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 65bf3579..a2033c9d 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1213,6 +1213,7 @@ declare module 'react-native-firebase' { showWhen?: boolean; smallIcon?: any; sortKey?: string; + tag?: string; ticker?: string; timeoutAfter?: number; usesChronometer?: boolean; @@ -1265,6 +1266,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 e76facb7..279be7fe 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 @@ -719,6 +735,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/AndroidNotifications.js b/lib/modules/notifications/AndroidNotifications.js index 6873f052..c697d6fd 100644 --- a/lib/modules/notifications/AndroidNotifications.js +++ b/lib/modules/notifications/AndroidNotifications.js @@ -92,6 +92,20 @@ export default class AndroidNotifications { return Promise.resolve(); } + removeDeliveredNotificationsByTag(tag: string): Promise { + if (Platform.OS === 'android') { + if (typeof tag !== 'string') { + throw new Error( + `AndroidNotifications:removeDeliveredNotificationsByTag expects an 'string' but got type ${typeof tag}` + ); + } + return getNativeModule( + this._notifications + ).removeDeliveredNotificationsByTag(tag); + } + return Promise.resolve(); + } + deleteChannelGroup(groupId: string): Promise { if (Platform.OS === 'android') { if (typeof groupId !== 'string') { @@ -99,9 +113,7 @@ export default class AndroidNotifications { `AndroidNotifications:deleteChannelGroup expects an 'string' but got type ${typeof groupId}` ); } - return getNativeModule(this._notifications).deleteChannelGroup( - groupId - ); + return getNativeModule(this._notifications).deleteChannelGroup(groupId); } return Promise.resolve(); } @@ -113,9 +125,7 @@ export default class AndroidNotifications { `AndroidNotifications:deleteChannel expects an 'string' but got type ${typeof channelId}` ); } - return getNativeModule(this._notifications).deleteChannel( - channelId - ); + return getNativeModule(this._notifications).deleteChannel(channelId); } return Promise.resolve(); } diff --git a/lib/modules/notifications/types.js b/lib/modules/notifications/types.js index c43ceac3..f51e9da2 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,