Commit 6b7bb9c9 authored by Ryan Eberhardt's avatar Ryan Eberhardt

Merge branch 'feature/remove-delivered-notifications' into dismiss-notifications

parents 77bce6a6 a15e038a
......@@ -440,6 +440,28 @@ Now the server should push the notification a bit differently- background instea
---
## Remove notifications (iOS only)
### getDeliveredNotifications
`PushNotification.getDeliveredNotifications(callback: (notifications: [Object]) => void)`
Provides you with a list of the app’s notifications that are still displayed in Notification Center.
### removeDeliveredNotifications
`PushNotification.removeDeliveredNotifications(identifiers: [string])`
Removes the specified notifications from Notification Center.
### removeAllDeliveredNotifications
`PushNotification.removeAllDeliveredNotifications()`
Removes all delivered notifications from Notification Center.
---
## PushKit API (iOS only)
The PushKit framework provides the classes for your iOS apps to receive background pushes from remote servers. it has better support for background notifications compared to regular push notifications with `content-available: 1`. More info in [iOS PushKit documentation](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Reference/PushKit_Framework/).
......
......@@ -15,6 +15,7 @@
#import "RCTUtils.h"
#endif
#import "RNNotificationsBridgeQueue.h"
#import <UserNotifications/UserNotifications.h>
NSString* const RNNotificationCreateAction = @"CREATE";
NSString* const RNNotificationClearAction = @"CLEAR";
......@@ -107,6 +108,29 @@ RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{
}
@end
static NSDictionary *RCTFormatUNNotification(UNNotification *notification)
{
NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary];
UNNotificationContent *content = notification.request.content;
formattedNotification[@"identifier"] = notification.request.identifier;
if (notification.date) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *dateString = [formatter stringFromDate:notification.date];
formattedNotification[@"fireDate"] = dateString;
}
formattedNotification[@"alertTitle"] = RCTNullIfNil(content.title);
formattedNotification[@"alertBody"] = RCTNullIfNil(content.body);
formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));
return formattedNotification;
}
@implementation RNNotifications
RCT_EXPORT_MODULE()
......@@ -572,4 +596,39 @@ RCT_EXPORT_METHOD(checkPermissions:(RCTPromiseResolveBlock) resolve
});
}
#if !TARGET_OS_TV
RCT_EXPORT_METHOD(removeAllDeliveredNotifications)
{
if ([UNUserNotificationCenter class]) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllDeliveredNotifications];
}
}
RCT_EXPORT_METHOD(removeDeliveredNotifications:(NSArray<NSString *> *)identifiers)
{
if ([UNUserNotificationCenter class]) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeDeliveredNotificationsWithIdentifiers:identifiers];
}
}
RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback)
{
if ([UNUserNotificationCenter class]) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
NSMutableArray<NSDictionary *> *formattedNotifications = [NSMutableArray new];
for (UNNotification *notification in notifications) {
[formattedNotifications addObject:RCTFormatUNNotification(notification)];
}
callback(@[formattedNotifications]);
}];
}
}
#endif !TARGET_OS_TV
@end
......@@ -216,4 +216,39 @@ export default class NotificationsIOS {
static checkPermissions() {
return NativeRNNotifications.checkPermissions();
}
/**
* Remove all delivered notifications from Notification Center
*/
static removeAllDeliveredNotifications() {
return NativeRNNotifications.removeAllDeliveredNotifications();
}
/**
* Removes the specified notifications from Notification Center
*
* @param identifiers Array of notification identifiers
*/
static removeDeliveredNotifications(identifiers: [string]) {
return NativeRNNotifications.removeDeliveredNotifications(identifiers);
}
/**
* Provides you with a list of the app’s notifications that are still displayed in Notification Center
*
* @param callback Function which receive an array of delivered notifications
*
* A delivered notification is an object containing:
*
* - `identifier` : The identifier of this notification.
* - `alertBody` : The message displayed in the notification alert.
* - `alertTitle` : The message title displayed in the notification.
* - `category` : The category of this notification, if has one.
* - `userInfo` : An optional object containing additional notification data.
* - `thread-id` : The thread identifier of this notification, if has one.
* - `fireDate` : The date and time when the system should deliver the notification. if not specified, the notification will be dispatched immediately.
*/
static getDeliveredNotifications(callback: (notifications: [Object]) => void) {
return NativeRNNotifications.getDeliveredNotifications(callback);
}
}
......@@ -5,6 +5,7 @@ export default class IOSNotification {
_badge: number;
_category: string;
_type: string; // regular / managed
_thread: string;
constructor(notification: Object) {
this._data = {};
......@@ -21,6 +22,7 @@ export default class IOSNotification {
this._badge = notification.aps.badge;
this._category = notification.managedAps.category;
this._type = "managed";
this._thread = notification.aps["thread-id"];
} else if (
notification.aps &&
notification.aps.alert) {
......@@ -30,6 +32,7 @@ export default class IOSNotification {
this._badge = notification.aps.badge;
this._category = notification.aps.category;
this._type = "regular";
this._thread = notification.aps["thread-id"];
}
Object.keys(notification).filter(key => key !== "aps").forEach(key => {
......@@ -60,4 +63,8 @@ export default class IOSNotification {
getType(): ?string {
return this._type;
}
getThread(): ?string {
return this._thread;
}
}
......@@ -30,11 +30,15 @@ describe("NotificationsIOS", () => {
nativeCancelAllLocalNotifications,
nativeSetBadgesCount,
nativeIsRegisteredForRemoteNotifications,
nativeCheckPermissions;
nativeCheckPermissions,
nativeRemoveAllDeliveredNotifications,
nativeRemoveDeliveredNotifications,
nativeGetDeliveredNotifications;
let NotificationsIOS, NotificationAction, NotificationCategory;
let someHandler = () => {};
let constantGuid = "some-random-uuid";
let identifiers = ["some-random-uuid", "other-random-uuid"];
/*eslint-enable indent*/
before(() => {
......@@ -53,6 +57,9 @@ describe("NotificationsIOS", () => {
nativeSetBadgesCount = sinon.spy();
nativeIsRegisteredForRemoteNotifications = sinon.spy();
nativeCheckPermissions = sinon.spy();
nativeRemoveAllDeliveredNotifications = sinon.spy();
nativeRemoveDeliveredNotifications = sinon.spy();
nativeGetDeliveredNotifications = sinon.spy();
let libUnderTest = proxyquire("../index.ios", {
"uuid": {
......@@ -71,7 +78,10 @@ describe("NotificationsIOS", () => {
cancelAllLocalNotifications: nativeCancelAllLocalNotifications,
setBadgesCount: nativeSetBadgesCount,
isRegisteredForRemoteNotifications: nativeIsRegisteredForRemoteNotifications,
checkPermissions: nativeCheckPermissions
checkPermissions: nativeCheckPermissions,
removeAllDeliveredNotifications: nativeRemoveAllDeliveredNotifications,
removeDeliveredNotifications: nativeRemoveDeliveredNotifications,
getDeliveredNotifications: nativeGetDeliveredNotifications
}
},
NativeAppEventEmitter: {
......@@ -112,6 +122,9 @@ describe("NotificationsIOS", () => {
nativeCancelAllLocalNotifications.reset();
nativeIsRegisteredForRemoteNotifications.reset();
nativeCheckPermissions.reset();
nativeRemoveAllDeliveredNotifications.reset();
nativeRemoveDeliveredNotifications.reset();
nativeGetDeliveredNotifications.reset();
});
after(() => {
......@@ -129,6 +142,9 @@ describe("NotificationsIOS", () => {
nativeCancelAllLocalNotifications = null;
nativeIsRegisteredForRemoteNotifications = null;
nativeCheckPermissions = null;
nativeRemoveAllDeliveredNotifications = null;
nativeRemoveDeliveredNotifications = null;
nativeGetDeliveredNotifications = null;
NotificationsIOS = null;
NotificationAction = null;
......@@ -306,7 +322,6 @@ describe("NotificationsIOS", () => {
});
});
describe("Is registered for remote notifications ", () => {
it("should call native is registered for remote notifications", () => {
NotificationsIOS.isRegisteredForRemoteNotifications();
......@@ -322,4 +337,29 @@ describe("NotificationsIOS", () => {
});
});
describe("Remove all delivered notifications", () => {
it("should call native remove all delivered notifications method", () => {
NotificationsIOS.removeAllDeliveredNotifications();
expect(nativeRemoveAllDeliveredNotifications).to.have.been.calledWith();
});
});
describe("Remove delivered notifications", () => {
it("should call native remove delivered notifications method", () => {
NotificationsIOS.removeDeliveredNotifications(identifiers);
expect(nativeRemoveDeliveredNotifications).to.have.been.calledWith(identifiers);
});
});
describe("Get delivered notifications", () => {
it("should call native get delivered notifications method", () => {
const callback = (notifications) => console.log(notifications);
NotificationsIOS.getDeliveredNotifications(callback);
expect(nativeGetDeliveredNotifications).to.have.been.calledWith(callback);
});
});
});
......@@ -4,7 +4,7 @@ import IOSNotification from "../notification.ios";
describe("iOS Notification Object", () => {
let notification;
let someBadgeCount = 123, someSound = "someSound", someCategory = "some_notification_category";
let someBadgeCount = 123, someSound = "someSound", someCategory = "some_notification_category", someThread = "thread-1";
describe("for a regular iOS push notification", () => {
let regularNativeNotifications = [
......@@ -17,7 +17,8 @@ describe("iOS Notification Object", () => {
},
badge: someBadgeCount,
sound: someSound,
category: someCategory
category: someCategory,
"thread-id": someThread
},
key1: "value1",
key2: "value2"
......@@ -33,7 +34,8 @@ describe("iOS Notification Object", () => {
},
badge: someBadgeCount,
sound: someSound,
category: someCategory
category: someCategory,
"thread-id": someThread
},
key1: "value1",
key2: "value2"
......@@ -65,6 +67,10 @@ describe("iOS Notification Object", () => {
expect(notification.getCategory()).to.equal(someCategory);
});
it("should return the thread", () => {
expect(notification.getThread()).to.equal("thread-1");
});
it("should return the custom data", () => {
expect(notification.getData()).to.deep.equal({ key1: "value1", key2: "value2" });
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment