From 6497ee023b9baf872a2df7d5f4051d9c8dccedf8 Mon Sep 17 00:00:00 2001 From: Lidan Hifi Date: Sun, 25 Sep 2016 01:50:25 +0300 Subject: [PATCH] added cancelLocalNotification and cancelAllLocalNotifications support --- README.md | 26 ++++++++++- RNNotifications/RNNotifications.m | 31 +++++++++++-- example/index.ios.js | 4 +- .../ios/NotificationsExampleApp/AppDelegate.m | 2 +- index.ios.js | 14 +++++- package.json | 3 +- test/index.ios.spec.js | 44 ++++++++++++++++--- 7 files changed, 111 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index df198e2..3042c16 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Triggering local notifications is fully compatible with React Native `PushNotifi Example: ```javascript -NotificationsIOS.localNotification({ +let localNotification = NotificationsIOS.localNotification({ alertBody: "Local notificiation!", alertTitle: "Local Notification Title", alertAction: "Click here to open", @@ -178,6 +178,30 @@ Notification object contains: - `category`- The category of this notification, required for [interactive notifications](#interactive--actionable-notifications-ios-only) (optional). - `userInfo`- An optional object containing additional notification data. +### Cancel Local Notification +```NotificationsIOS.localNotification``` method returns `notificationId`, which is used in order to cancel created local notification. You can cancel local notification by calling `NotificationsIOS.cancelLocalNotification(notificationId)` method. + +Example: + +```javascript +let someLocalNotification = NotificationsIOS.localNotification({ + alertBody: "Local notificiation!", + alertTitle: "Local Notification Title", + alertAction: "Click here to open", + soundName: "chime.aiff", + category: "SOME_CATEGORY", + userInfo: { } +}); + +NotificationsIOS.cancelLocalNotification(someLocalNotification); +``` + +### Cancel All Local Notifications + +```javascript +NotificationsIOS.cancelAllLocalNotifications(); +``` + --- ## Managed Notifications (iOS only) diff --git a/RNNotifications/RNNotifications.m b/RNNotifications/RNNotifications.m index da25848..b6bd128 100644 --- a/RNNotifications/RNNotifications.m +++ b/RNNotifications/RNNotifications.m @@ -191,6 +191,10 @@ RCT_EXPORT_MODULE() { UIApplicationState state = [UIApplication sharedApplication].applicationState; + NSMutableDictionary* newUserInfo = notification.userInfo.mutableCopy; + [newUserInfo removeObjectForKey:@"__id"]; + notification.userInfo = newUserInfo; + if (state == UIApplicationStateActive) { [self didReceiveNotificationOnForegroundState:notification.userInfo]; } else if (state == UIApplicationStateInactive) { @@ -483,13 +487,34 @@ RCT_EXPORT_METHOD(consumeBackgroundQueue) } } -RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification) +RCT_EXPORT_METHOD(localNotification:(NSDictionary *)notification withId:(NSString *)notificationId) { + UILocalNotification* localNotification = [RCTConvert UILocalNotification:notification]; + NSMutableArray* userInfo = localNotification.userInfo.mutableCopy; + [userInfo setValue:notificationId forKey:@"__id"]; + localNotification.userInfo = userInfo; + if ([notification objectForKey:@"fireDate"] != nil) { - [RCTSharedApplication() scheduleLocalNotification:[RCTConvert UILocalNotification:notification]]; + [RCTSharedApplication() scheduleLocalNotification:localNotification]; } else { - [RCTSharedApplication() presentLocalNotificationNow:[RCTConvert UILocalNotification:notification]]; + [RCTSharedApplication() presentLocalNotificationNow:localNotification]; } } +RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId) +{ + for (UILocalNotification* notification in [UIApplication sharedApplication].scheduledLocalNotifications) { + NSDictionary* notificationInfo = notification.userInfo; + + if ([[notificationInfo objectForKey:@"__id"] isEqualToString:notificationId]) { + [[UIApplication sharedApplication] cancelLocalNotification:notification]; + } + } +} + +RCT_EXPORT_METHOD(cancelAllLocalNotifications) +{ + [RCTSharedApplication() cancelAllLocalNotifications]; +} + @end diff --git a/example/index.ios.js b/example/index.ios.js index 333f57e..80c2748 100644 --- a/example/index.ios.js +++ b/example/index.ios.js @@ -77,7 +77,7 @@ class NotificationsExampleApp extends Component { onNotificationReceivedBackground(notification) { NotificationsIOS.log("Notification Received Background: " + JSON.stringify(notification)); - NotificationsIOS.localNotification({ + let localNotification = NotificationsIOS.localNotification({ alertBody: "Received background notificiation!", alertTitle: "Local Notification Title", alertAction: "Click here to open", @@ -87,6 +87,8 @@ class NotificationsExampleApp extends Component { }); // NotificationsIOS.backgroundTimeRemaining(time => NotificationsIOS.log("remaining background time: " + time)); + + // NotificationsIOS.cancelLocalNotification(localNotification); } onNotificationOpened(notification) { diff --git a/example/ios/NotificationsExampleApp/AppDelegate.m b/example/ios/NotificationsExampleApp/AppDelegate.m index 36d06d6..fbe809f 100644 --- a/example/ios/NotificationsExampleApp/AppDelegate.m +++ b/example/ios/NotificationsExampleApp/AppDelegate.m @@ -33,7 +33,7 @@ * on the same Wi-Fi network. */ - jsCodeLocation = [NSURL URLWithString:@"http://172.31.9.91:8081/index.ios.bundle?platform=ios&dev=true"]; + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; /** * OPTION 2 diff --git a/index.ios.js b/index.ios.js index 7f6d2f2..335209b 100644 --- a/index.ios.js +++ b/index.ios.js @@ -5,6 +5,7 @@ "use strict"; import { NativeModules, DeviceEventEmitter, NativeAppEventEmitter } from "react-native"; import Map from "core-js/library/es6/map"; +import uuid from "uuid"; const NativeRNNotifications = NativeModules.RNNotifications; // eslint-disable-line no-unused-vars import IOSNotification from "./notification.ios"; @@ -179,6 +180,17 @@ export default class NotificationsIOS { * - `fireDate` : The date and time when the system should deliver the notification. if not specified, the notification will be dispatched immediately. */ static localNotification(notification: Object) { - NativeRNNotifications.localNotification(notification); + let notificationId = uuid.v4(); + NativeRNNotifications.localNotification(notification, notificationId); + + return notificationId; + } + + static cancelLocalNotification(notificationId: String) { + NativeRNNotifications.cancelLocalNotification(notificationId); + } + + static cancelAllLocalNotifications() { + NativeRNNotifications.cancelAllLocalNotifications(); } } diff --git a/package.json b/package.json index 3159e48..ba9af00 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ ], "nativePackage": true, "dependencies": { - "core-js": "^1.0.0" + "core-js": "^1.0.0", + "uuid": "^2.0.3" }, "peerDependencies": { "react-native": ">=0.25.1" diff --git a/test/index.ios.spec.js b/test/index.ios.spec.js index db6654d..c9cdd82 100644 --- a/test/index.ios.spec.js +++ b/test/index.ios.spec.js @@ -24,9 +24,12 @@ describe("NotificationsIOS", () => { nativeRegisterPushKit, nativeBackgroundTimeRemaining, nativeConsumeBackgroundQueue, - nativeLocalNotification; + nativeLocalNotification, + nativeCancelLocalNotification, + nativeCancelAllLocalNotifications; let NotificationsIOS, NotificationAction, NotificationCategory; let someHandler = () => {}; + let constantGuid = "some-random-uuid"; /*eslint-enable indent*/ before(() => { @@ -40,8 +43,13 @@ describe("NotificationsIOS", () => { nativeBackgroundTimeRemaining = sinon.spy(); nativeConsumeBackgroundQueue = sinon.spy(); nativeLocalNotification = sinon.spy(); + nativeCancelLocalNotification = sinon.spy(); + nativeCancelAllLocalNotifications = sinon.spy(); let libUnderTest = proxyquire("../index.ios", { + "uuid": { + v4: () => constantGuid + }, "react-native": { NativeModules: { RNNotifications: { @@ -50,7 +58,9 @@ describe("NotificationsIOS", () => { registerPushKit: nativeRegisterPushKit, backgroundTimeRemaining: nativeBackgroundTimeRemaining, consumeBackgroundQueue: nativeConsumeBackgroundQueue, - localNotification: nativeLocalNotification + localNotification: nativeLocalNotification, + cancelLocalNotification: nativeCancelLocalNotification, + cancelAllLocalNotifications: nativeCancelAllLocalNotifications } }, NativeAppEventEmitter: { @@ -87,6 +97,8 @@ describe("NotificationsIOS", () => { nativeBackgroundTimeRemaining.reset(); nativeConsumeBackgroundQueue.reset(); nativeLocalNotification.reset(); + nativeCancelLocalNotification.reset(); + nativeCancelAllLocalNotifications.reset(); }); after(() => { @@ -100,6 +112,8 @@ describe("NotificationsIOS", () => { nativeBackgroundTimeRemaining = null; nativeConsumeBackgroundQueue = null; nativeLocalNotification = null; + nativeCancelLocalNotification = null; + nativeCancelAllLocalNotifications = null; NotificationsIOS = null; NotificationAction = null; @@ -229,8 +243,12 @@ describe("NotificationsIOS", () => { }); }); - describe("Get background remaining time", () => { - it("should call native consume background queue method", () => { + describe("Dispatch local notification", () => { + it("should return generated notification guid", () => { + expect(NotificationsIOS.localNotification({})).to.equal(constantGuid); + }); + + it("should call native local notification method with generated notification guid and notification object", () => { let someLocalNotification = { alertBody: "some body", alertTitle: "some title", @@ -244,7 +262,23 @@ describe("NotificationsIOS", () => { NotificationsIOS.localNotification(someLocalNotification); - expect(nativeLocalNotification).to.have.been.calledWith(someLocalNotification); + expect(nativeLocalNotification).to.have.been.calledWith(someLocalNotification, constantGuid); + }); + }); + + describe("Cancel local notification", () => { + it("should call native cancel local notification method", () => { + NotificationsIOS.cancelLocalNotification(constantGuid); + + expect(nativeCancelLocalNotification).to.have.been.calledWith(constantGuid); + }); + }); + + describe("Cancel all local notifications", () => { + it("should call native cancel all local notifications method", () => { + NotificationsIOS.cancelAllLocalNotifications(); + + expect(nativeCancelAllLocalNotifications).to.have.been.calledWith(); }); }); }); -- 2.26.2