diff --git a/README.md b/README.md index e544f8c0a2a6a39da27dd1812d5139fa25e6bb76..641a32944696cbdd980648fa823c8c3069e1a223 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,6 @@ Example: let localNotification = NotificationsIOS.localNotification({ alertBody: "Local notificiation!", alertTitle: "Local Notification Title", - alertAction: "Click here to open", soundName: "chime.aiff", category: "SOME_CATEGORY", userInfo: { } @@ -338,7 +337,7 @@ Notification object contains: - **`fireDate`**- The date and time when the system should deliver the notification (optinal - default is immidiate dispatch). - `alertBody`- The message displayed in the notification alert. - `alertTitle`- The title of the notification, displayed in the notifications center. -- `alertAction`- The "action" displayed beneath an actionable notification. +- `alertAction`- The "action" displayed beneath an actionable notification on the lockscreen (e.g. "Slide to **open**"). Note that Apple no longer shows this in iOS 10. - `soundName`- The sound played when the notification is fired (optional). - `category`- The category of this notification, required for [interactive notifications](#interactive--actionable-notifications-ios-only) (optional). - `userInfo`- An optional object containing additional notification data. @@ -357,8 +356,9 @@ NotificationsAndroid.localNotification({ Upon notification opening (tapping by the device user), all data fields will be delivered as-is). -### Cancel Local Notification -The `NotificationsIOS.localNotification()` and `NotificationsAndroid.localNotification()` methods return unique `notificationId` values, which can be used in order to cancel specific local notifications. You can cancel local notification by calling `NotificationsIOS.cancelLocalNotification(notificationId)` or `NotificationsAndroid.cancelLocalNotification(notificationId)`. +### Cancel Scheduled Local Notifications + +The `NotificationsIOS.localNotification()` and `NotificationsAndroid.localNotification()` methods return unique `notificationId` values, which can be used in order to cancel specific local notifications that were scheduled for delivery on `fireDate` and have not yet been delivered. You can cancel local notification by calling `NotificationsIOS.cancelLocalNotification(notificationId)` or `NotificationsAndroid.cancelLocalNotification(notificationId)`. Example (iOS): @@ -366,7 +366,6 @@ Example (iOS): let someLocalNotification = NotificationsIOS.localNotification({ alertBody: "Local notificiation!", alertTitle: "Local Notification Title", - alertAction: "Click here to open", soundName: "chime.aiff", category: "SOME_CATEGORY", userInfo: { } @@ -375,12 +374,26 @@ let someLocalNotification = NotificationsIOS.localNotification({ NotificationsIOS.cancelLocalNotification(someLocalNotification); ``` -### Cancel All Local Notifications (iOS-only!) +To cancel all local notifications (**iOS only!**), use `cancelAllLocalNotifications()`: ```javascript NotificationsIOS.cancelAllLocalNotifications(); ``` +### Cancel Delivered Local Notifications (iOS 10+ only) + +To dismiss notifications from the notification center that have already been shown to the user, call `NotificationsIOS.removeDeliveredNotifications([notificationId])`: + +```javascript +let someLocalNotification = NotificationsIOS.localNotification({...}); + +NotificationsIOS.removeDeliveredNotifications([someLocalNotification]); +``` + +Call `removeAllDeliveredNotifications()` to dismiss all delivered notifications +(note that this will dismiss push notifications in addition to local +notifications). + --- ## Managed Notifications (iOS only) @@ -444,13 +457,13 @@ Now the server should push the notification a bit differently- background instea ### getDeliveredNotifications -`PushNotification.getDeliveredNotifications(callback: (notifications: [Object]) => void)` +`PushNotification.getDeliveredNotifications(callback: (notifications: Array) => void)` Provides you with a list of the app’s notifications that are still displayed in Notification Center. ### removeDeliveredNotifications -`PushNotification.removeDeliveredNotifications(identifiers: [string])` +`PushNotification.removeDeliveredNotifications(identifiers: Array)` Removes the specified notifications from Notification Center. diff --git a/RNNotifications/RNNotifications.m b/RNNotifications/RNNotifications.m index 304758c520a6141a38fc41f21007499779ce4380..3c12a9dbcb5db7580cf4cc4cd81abecaf8dda8c5 100644 --- a/RNNotifications/RNNotifications.m +++ b/RNNotifications/RNNotifications.m @@ -17,6 +17,8 @@ #import "RNNotificationsBridgeQueue.h" #import +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) + NSString* const RNNotificationCreateAction = @"CREATE"; NSString* const RNNotificationClearAction = @"CLEAR"; @@ -108,26 +110,58 @@ RCT_ENUM_CONVERTER(UIUserNotificationActionBehavior, (@{ } @end +@implementation RCTConvert (UNNotificationRequest) ++ (UNNotificationRequest *)UNNotificationRequest:(id)json withId:(NSString*)notificationId +{ + NSDictionary *details = [self NSDictionary:json]; + + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + content.body = [RCTConvert NSString:details[@"alertBody"]]; + content.title = [RCTConvert NSString:details[@"alertTitle"]]; + content.sound = [RCTConvert NSString:details[@"soundName"]] + ? [UNNotificationSound soundNamed:[RCTConvert NSString:details[@"soundName"]]] + : [UNNotificationSound defaultSound]; + content.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]] ?: @{}; + content.categoryIdentifier = [RCTConvert NSString:details[@"category"]]; + + NSDate *triggerDate = [RCTConvert NSDate:details[@"fireDate"]]; + UNCalendarNotificationTrigger *trigger = nil; + if (triggerDate != nil) { + NSDateComponents *triggerDateComponents = [[NSCalendar currentCalendar] + components:NSCalendarUnitYear + + NSCalendarUnitMonth + NSCalendarUnitDay + + NSCalendarUnitHour + NSCalendarUnitMinute + + NSCalendarUnitSecond + NSCalendarUnitTimeZone + fromDate:triggerDate]; + trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDateComponents + repeats:NO]; + } + + return [UNNotificationRequest requestWithIdentifier:notificationId + content:content trigger:trigger]; +} +@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; } @@ -545,25 +579,35 @@ RCT_EXPORT_METHOD(consumeBackgroundQueue) 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) { - [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10")) { + UNNotificationRequest* localNotification = [RCTConvert UNNotificationRequest:notification withId:notificationId]; + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:localNotification withCompletionHandler:nil]; } else { - [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; + UILocalNotification* localNotification = [RCTConvert UILocalNotification:notification]; + NSMutableArray* userInfo = localNotification.userInfo.mutableCopy; + [userInfo setValue:notificationId forKey:@"__id"]; + localNotification.userInfo = userInfo; + + if ([notification objectForKey:@"fireDate"] != nil) { + [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; + } else { + [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; + } } } RCT_EXPORT_METHOD(cancelLocalNotification:(NSString *)notificationId) { - for (UILocalNotification* notification in [UIApplication sharedApplication].scheduledLocalNotifications) { - NSDictionary* notificationInfo = notification.userInfo; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10")) { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center removePendingNotificationRequestsWithIdentifiers:@[notificationId]]; + } else { + for (UILocalNotification* notification in [UIApplication sharedApplication].scheduledLocalNotifications) { + NSDictionary* notificationInfo = notification.userInfo; - if ([[notificationInfo objectForKey:@"__id"] isEqualToString:notificationId]) { - [[UIApplication sharedApplication] cancelLocalNotification:notification]; + if ([[notificationInfo objectForKey:@"__id"] isEqualToString:notificationId]) { + [[UIApplication sharedApplication] cancelLocalNotification:notification]; + } } } } @@ -576,7 +620,7 @@ RCT_EXPORT_METHOD(cancelAllLocalNotifications) RCT_EXPORT_METHOD(isRegisteredForRemoteNotifications:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { BOOL ans; - + if (TARGET_IPHONE_SIMULATOR) { ans = [[[UIApplication sharedApplication] currentUserNotificationSettings] types] != 0; } @@ -620,7 +664,7 @@ RCT_EXPORT_METHOD(getDeliveredNotifications:(RCTResponseSenderBlock)callback) UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center getDeliveredNotificationsWithCompletionHandler:^(NSArray * _Nonnull notifications) { NSMutableArray *formattedNotifications = [NSMutableArray new]; - + for (UNNotification *notification in notifications) { [formattedNotifications addObject:RCTFormatUNNotification(notification)]; } diff --git a/index.ios.js b/index.ios.js index 210e9512c82dc4de9e61f24994563b5d3fc68d0e..d5ac85686d636caa6e814b8d0b4716d0eb3b19dc 100644 --- a/index.ios.js +++ b/index.ios.js @@ -229,7 +229,7 @@ export default class NotificationsIOS { * * @param identifiers Array of notification identifiers */ - static removeDeliveredNotifications(identifiers: [string]) { + static removeDeliveredNotifications(identifiers: Array) { return NativeRNNotifications.removeDeliveredNotifications(identifiers); } @@ -248,7 +248,7 @@ export default class NotificationsIOS { * - `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) { + static getDeliveredNotifications(callback: (notifications: Array) => void) { return NativeRNNotifications.getDeliveredNotifications(callback); } }