Merge pull request #1058 from dgruseck/master

[Android] Add the ability to remove notifications based on the tag
This commit is contained in:
Michael Diarmid 2018-07-20 11:35:08 +01:00 committed by GitHub
commit 321e4a2909
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 86 additions and 36 deletions

View File

@ -1,20 +1,19 @@
--- ---
name: ⚠️ Bug/Issue report name: ⚠️ Bug/Issue report
about: Please provide as much detail as possible to help us with a bug or issue. Issues 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. will be closed if they do not follow the template.
--- ---
<!--- <!---
BEFORE YOU MAKE AN ISSUE BEFORE YOU MAKE AN ISSUE
The issue list of this repo is exclusively for bug reports. The issue list of this repo is exclusively for bug reports.
1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests 1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests
2) For questions and support please use our Discord chat: https://discord.gg/C9aK28N or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase 2) For questions and support please use our Discord chat: https://discord.gg/C9aK28N or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed. 3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
--> -->
### Issue ### Issue
@ -23,7 +22,7 @@ The issue list of this repo is exclusively for bug reports.
### Environment ### Environment
1. Application Target Platform: 1. Application Target Platform:
<!--- (e.g. iOS, Android, Both) ---> <!--- (e.g. iOS, Android, Both) --->
@ -47,14 +46,14 @@ The issue list of this repo is exclusively for bug reports.
<!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) ---> <!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) --->
7. Are you using `typescript`? 7. Are you using `typescript`?
<!--- yes/no ---> <!--- yes/no --->
--- ---
Loving `react-native-firebase`? Please consider supporting them with any of the below: 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) * 👉 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 * 👉 Follow [`React Native Firebase`](https://twitter.com/rnfirebase) and [`Invertase`](https://twitter.com/invertaseio) on Twitter
- 👉 Star this repo on GitHub ⭐️ * 👉 Star this repo on GitHub ⭐️

View File

@ -49,7 +49,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
| **Crashlytics**           | ❌ | ✅ | ✅ | ❌ | | **Crashlytics**           | ❌ | ✅ | ✅ | ❌ |
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ | | **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
| **Dynamic Links** | ❌ | ✅ | ✅ | ❌ | | **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** | ❌ | ❌ | ✅ | ❌ | | **Invites** | ❌ | ❌ | ✅ | ❌ |
| **Instance ID**          | ❌ | ❌ | **?** | ❌ | | **Instance ID**          | ❌ | ❌ | **?** | ❌ |
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ | | **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`. > 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 | | | 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 | | 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 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 + | | Firebase iOS SDK | 4.0.0 + | 4.7.0 + | 4.11.0 + | 4.13.0 + | 5.0.0 + |
--- ---

View File

@ -279,13 +279,18 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
} }
} }
String tag = null;
if (android.containsKey("tag")) {
tag = android.getString("tag");
}
// Create the notification intent // Create the notification intent
PendingIntent contentIntent = createIntent(intentClass, notification, android.getString("clickAction")); PendingIntent contentIntent = createIntent(intentClass, notification, android.getString("clickAction"));
nb = nb.setContentIntent(contentIntent); nb = nb.setContentIntent(contentIntent);
// Build the notification and send it // Build the notification and send it
Notification builtNotification = nb.build(); Notification builtNotification = nb.build();
notificationManager.notify(notificationId.hashCode(), builtNotification); notificationManager.notify(tag, notificationId.hashCode(), builtNotification);
if (reactContext != null) { if (reactContext != null) {
Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification)); Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification));

View File

@ -17,6 +17,7 @@ import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput; import android.support.v4.app.RemoteInput;
@ -153,7 +154,7 @@ public class RNFirebaseNotificationManager {
if (!notification.getBundle("schedule").containsKey("repeated") if (!notification.getBundle("schedule").containsKey("repeated")
|| !notification.getBundle("schedule").getBoolean("repeated")) { || !notification.getBundle("schedule").getBoolean("repeated")) {
String notificationId = notification.getString("notificationId"); String notificationId = notification.getString("notificationId");
preferences.edit().remove(notificationId).apply();; preferences.edit().remove(notificationId).apply();
} }
if (Utils.isAppInForeground(context)) { if (Utils.isAppInForeground(context)) {
@ -195,6 +196,15 @@ public class RNFirebaseNotificationManager {
promise.resolve(null); 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() { public void rescheduleNotifications() {
ArrayList<Bundle> bundles = getScheduledNotifications(); ArrayList<Bundle> bundles = getScheduledNotifications();

View File

@ -112,6 +112,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
notificationManager.removeDeliveredNotification(notificationId, promise); notificationManager.removeDeliveredNotification(notificationId, promise);
} }
@ReactMethod
public void removeDeliveredNotificationsByTag(String tag, Promise promise) {
notificationManager.removeDeliveredNotificationsByTag(tag, promise);
}
@ReactMethod @ReactMethod
public void setBadge(int badge, Promise promise) { public void setBadge(int badge, Promise promise) {
// Store the badge count for later retrieval // Store the badge count for later retrieval
@ -296,6 +301,7 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
} }
if (notification.getTag() != null) { if (notification.getTag() != null) {
androidMap.putString("group", notification.getTag()); androidMap.putString("group", notification.getTag());
androidMap.putString("tag", notification.getTag());
} }
notificationMap.putMap("android", androidMap); notificationMap.putMap("android", androidMap);

View File

@ -372,7 +372,7 @@ RCT_EXPORT_METHOD(setBadge:(NSInteger) number
resolve(nil); resolve(nil);
}); });
} }
RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
jsReady = TRUE; jsReady = TRUE;
resolve(nil); resolve(nil);
@ -487,11 +487,11 @@ RCT_EXPORT_METHOD(jsInitialised:(RCTPromiseResolveBlock)resolve rejecter:(RCTPro
NSString *identifier = a[@"identifier"]; NSString *identifier = a[@"identifier"];
NSURL *url = [NSURL fileURLWithPath:a[@"url"]]; NSURL *url = [NSURL fileURLWithPath:a[@"url"]];
NSMutableDictionary *attachmentOptions = nil; NSMutableDictionary *attachmentOptions = nil;
if (a[@"options"]) { if (a[@"options"]) {
NSDictionary *options = a[@"options"]; NSDictionary *options = a[@"options"];
attachmentOptions = [[NSMutableDictionary alloc] init]; attachmentOptions = [[NSMutableDictionary alloc] init];
for (id key in options) { for (id key in options) {
if ([key isEqualToString:@"typeHint"]) { if ([key isEqualToString:@"typeHint"]) {
attachmentOptions[UNNotificationAttachmentOptionsTypeHintKey] = options[key]; attachmentOptions[UNNotificationAttachmentOptionsTypeHintKey] = options[key];

2
lib/index.d.ts vendored
View File

@ -1213,6 +1213,7 @@ declare module 'react-native-firebase' {
showWhen?: boolean; showWhen?: boolean;
smallIcon?: any; smallIcon?: any;
sortKey?: string; sortKey?: string;
tag?: string;
ticker?: string; ticker?: string;
timeoutAfter?: number; timeoutAfter?: number;
usesChronometer?: boolean; usesChronometer?: boolean;
@ -1265,6 +1266,7 @@ declare module 'react-native-firebase' {
setShowWhen(showWhen: boolean): Notification; setShowWhen(showWhen: boolean): Notification;
setSmallIcon(icon: string, level?: number): Notification; setSmallIcon(icon: string, level?: number): Notification;
setSortKey(sortKey: string): Notification; setSortKey(sortKey: string): Notification;
setTag(tag: string): Notification;
setTicker(ticker: string): Notification; setTicker(ticker: string): Notification;
setTimeoutAfter(timeoutAfter: number): Notification; setTimeoutAfter(timeoutAfter: number): Notification;
setUsesChronometer(usesChronometer: boolean): Notification; setUsesChronometer(usesChronometer: boolean): Notification;

View File

@ -53,6 +53,7 @@ export default class AndroidNotification {
_smallIcon: SmallIcon; _smallIcon: SmallIcon;
_sortKey: string | void; _sortKey: string | void;
// TODO: style: Style; // Need to figure out if this can work // TODO: style: Style; // Need to figure out if this can work
_tag: string | void;
_ticker: string | void; _ticker: string | void;
_timeoutAfter: number | void; _timeoutAfter: number | void;
_usesChronometer: boolean | void; _usesChronometer: boolean | void;
@ -106,6 +107,7 @@ export default class AndroidNotification {
this._showWhen = data.showWhen; this._showWhen = data.showWhen;
this._smallIcon = data.smallIcon; this._smallIcon = data.smallIcon;
this._sortKey = data.sortKey; this._sortKey = data.sortKey;
this._tag = data.tag;
this._ticker = data.ticker; this._ticker = data.ticker;
this._timeoutAfter = data.timeoutAfter; this._timeoutAfter = data.timeoutAfter;
this._usesChronometer = data.usesChronometer; this._usesChronometer = data.usesChronometer;
@ -238,6 +240,10 @@ export default class AndroidNotification {
return this._sortKey; return this._sortKey;
} }
get tag(): ?string {
return this._tag;
}
get ticker(): ?string { get ticker(): ?string {
return this._ticker; return this._ticker;
} }
@ -615,6 +621,16 @@ export default class AndroidNotification {
return this._notification; return this._notification;
} }
/**
*
* @param tag
* @returns {Notification}
*/
setTag(tag: string): Notification {
this._tag = tag;
return this._notification;
}
/** /**
* *
* @param ticker * @param ticker
@ -719,6 +735,7 @@ export default class AndroidNotification {
smallIcon: this._smallIcon, smallIcon: this._smallIcon,
sortKey: this._sortKey, sortKey: this._sortKey,
// TODO: style: Style, // TODO: style: Style,
tag: this._tag,
ticker: this._ticker, ticker: this._ticker,
timeoutAfter: this._timeoutAfter, timeoutAfter: this._timeoutAfter,
usesChronometer: this._usesChronometer, usesChronometer: this._usesChronometer,

View File

@ -92,6 +92,20 @@ export default class AndroidNotifications {
return Promise.resolve(); return Promise.resolve();
} }
removeDeliveredNotificationsByTag(tag: string): Promise<void> {
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<void> { deleteChannelGroup(groupId: string): Promise<void> {
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
if (typeof groupId !== 'string') { if (typeof groupId !== 'string') {
@ -99,9 +113,7 @@ export default class AndroidNotifications {
`AndroidNotifications:deleteChannelGroup expects an 'string' but got type ${typeof groupId}` `AndroidNotifications:deleteChannelGroup expects an 'string' but got type ${typeof groupId}`
); );
} }
return getNativeModule(this._notifications).deleteChannelGroup( return getNativeModule(this._notifications).deleteChannelGroup(groupId);
groupId
);
} }
return Promise.resolve(); return Promise.resolve();
} }
@ -113,9 +125,7 @@ export default class AndroidNotifications {
`AndroidNotifications:deleteChannel expects an 'string' but got type ${typeof channelId}` `AndroidNotifications:deleteChannel expects an 'string' but got type ${typeof channelId}`
); );
} }
return getNativeModule(this._notifications).deleteChannel( return getNativeModule(this._notifications).deleteChannel(channelId);
channelId
);
} }
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -170,6 +170,7 @@ export type NativeAndroidNotification = {|
smallIcon: SmallIcon, smallIcon: SmallIcon,
sortKey?: string, sortKey?: string,
// TODO: style: Style, // TODO: style: Style,
tag?: string,
ticker?: string, ticker?: string,
timeoutAfter?: number, timeoutAfter?: number,
usesChronometer?: boolean, usesChronometer?: boolean,