mirror of
https://github.com/status-im/react-native.git
synced 2025-01-17 13:01:13 +00:00
5b4b027477
Summary: _(This is a remake of #6907, which I botched pretty good with a rebase.)_ This returns an `Array` of Local Notifications that have been scheduled to be delivered. Available attributes on return Notification object (if set in the local notification itself): `alertAction` `alertBody` `applicationIconBadgeNumber` `category` `fireDate` `soundName` `userInfo` More could be added to this but I just matched what was available in the `Object` passed to `presentLocalNotification` and `scheduleLocalNotification`. **Motivation** I needed to determine the number and other details about local notifications that were already scheduled. There is an API for this in iOS but one hadn't been built yet for React Native. I created the Obj-C method and updated the documentation in `PushNotificationIOS.js` as well. **Usage:** ```js PushNotificationIOS.getScheduledLocalNotifications( (notifications) => { console.log(notifications); }); ``` **Sample Output:** ```js [ Object { aler Closes https://github.com/facebook/react-native/pull/7937 Differential Revision: D3392476 Pulled By: javache fbshipit-source-id: d83f419bfcfbdaf9b955724dcf5cfe26834895fb
337 lines
13 KiB
Objective-C
337 lines
13 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTPushNotificationManager.h"
|
|
|
|
#import "RCTBridge.h"
|
|
#import "RCTConvert.h"
|
|
#import "RCTEventDispatcher.h"
|
|
#import "RCTUtils.h"
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
|
|
|
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
|
|
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
|
|
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
|
|
#define UIUserNotificationTypeNone UIRemoteNotificationTypeNone
|
|
#define UIUserNotificationType UIRemoteNotificationType
|
|
|
|
#endif
|
|
|
|
NSString *const RCTLocalNotificationReceived = @"LocalNotificationReceived";
|
|
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
|
|
NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
|
|
NSString *const RCTRegisterUserNotificationSettings = @"RegisterUserNotificationSettings";
|
|
|
|
NSString *const RCTErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
|
|
|
|
@interface RCTPushNotificationManager ()
|
|
@property (nonatomic, copy) RCTPromiseResolveBlock requestPermissionsResolveBlock;
|
|
@end
|
|
|
|
@implementation RCTConvert (UILocalNotification)
|
|
|
|
+ (UILocalNotification *)UILocalNotification:(id)json
|
|
{
|
|
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
|
|
UILocalNotification *notification = [UILocalNotification new];
|
|
notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
|
|
notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
|
|
notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
|
|
notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
|
|
notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
|
|
notification.category = [RCTConvert NSString:details[@"category"]];
|
|
if (details[@"applicationIconBadgeNumber"]) {
|
|
notification.applicationIconBadgeNumber = [RCTConvert NSInteger:details[@"applicationIconBadgeNumber"]];
|
|
}
|
|
return notification;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation RCTPushNotificationManager
|
|
|
|
static NSDictionary *formatLocalNotification(UILocalNotification *notification)
|
|
{
|
|
NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];
|
|
if (notification.fireDate) {
|
|
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
|
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
|
|
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
|
|
formattedLocalNotification[@"fireDate"] = fireDateString;
|
|
}
|
|
formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
|
|
formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
|
|
formattedLocalNotification[@"applicationIconBadgeNumber"] = @(notification.applicationIconBadgeNumber);
|
|
formattedLocalNotification[@"category"] = RCTNullIfNil(notification.category);
|
|
formattedLocalNotification[@"soundName"] = RCTNullIfNil(notification.soundName);
|
|
formattedLocalNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(notification.userInfo));
|
|
return formattedLocalNotification;
|
|
}
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
- (void)startObserving
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(handleLocalNotificationReceived:)
|
|
name:RCTLocalNotificationReceived
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(handleRemoteNotificationReceived:)
|
|
name:RCTRemoteNotificationReceived
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(handleRemoteNotificationsRegistered:)
|
|
name:RCTRemoteNotificationsRegistered
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(handleRegisterUserNotificationSettings:)
|
|
name:RCTRegisterUserNotificationSettings
|
|
object:nil];
|
|
}
|
|
|
|
- (void)stopObserving
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (NSArray<NSString *> *)supportedEvents
|
|
{
|
|
return @[@"localNotificationReceived",
|
|
@"remoteNotificationReceived",
|
|
@"remoteNotificationsRegistered"];
|
|
}
|
|
|
|
// TODO: Once all JS call sites for popInitialNotification have
|
|
// been removed we can get rid of this
|
|
- (NSDictionary<NSString *, id> *)constantsToExport
|
|
{
|
|
NSDictionary<NSString *, id> *initialNotification =
|
|
[self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
|
|
return @{@"initialNotification": RCTNullIfNil(initialNotification)};
|
|
}
|
|
|
|
+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
|
|
{
|
|
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
|
|
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRegisterUserNotificationSettings
|
|
object:self
|
|
userInfo:@{@"notificationSettings": notificationSettings}];
|
|
}
|
|
}
|
|
|
|
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
|
{
|
|
NSMutableString *hexString = [NSMutableString string];
|
|
NSUInteger deviceTokenLength = deviceToken.length;
|
|
const unsigned char *bytes = deviceToken.bytes;
|
|
for (NSUInteger i = 0; i < deviceTokenLength; i++) {
|
|
[hexString appendFormat:@"%02x", bytes[i]];
|
|
}
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
|
|
object:self
|
|
userInfo:@{@"deviceToken" : [hexString copy]}];
|
|
}
|
|
|
|
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
|
|
{
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
|
|
object:self
|
|
userInfo:notification];
|
|
}
|
|
|
|
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification
|
|
{
|
|
NSMutableDictionary *details = [NSMutableDictionary new];
|
|
if (notification.alertBody) {
|
|
details[@"alertBody"] = notification.alertBody;
|
|
}
|
|
if (notification.userInfo) {
|
|
details[@"userInfo"] = RCTJSONClean(notification.userInfo);
|
|
}
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTLocalNotificationReceived
|
|
object:self
|
|
userInfo:details];
|
|
}
|
|
|
|
- (void)handleLocalNotificationReceived:(NSNotification *)notification
|
|
{
|
|
[self sendEventWithName:@"localNotificationReceived" body:notification.userInfo];
|
|
}
|
|
|
|
- (void)handleRemoteNotificationReceived:(NSNotification *)notification
|
|
{
|
|
[self sendEventWithName:@"remoteNotificationReceived" body:notification.userInfo];
|
|
}
|
|
|
|
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
|
|
{
|
|
[self sendEventWithName:@"remoteNotificationsRegistered" body:notification.userInfo];
|
|
}
|
|
|
|
- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
|
|
{
|
|
if (self.requestPermissionsResolveBlock == nil) {
|
|
return;
|
|
}
|
|
|
|
UIUserNotificationSettings *notificationSettings = notification.userInfo[@"notificationSettings"];
|
|
NSDictionary *notificationTypes = @{
|
|
@"alert": @((notificationSettings.types & UIUserNotificationTypeAlert) > 0),
|
|
@"sound": @((notificationSettings.types & UIUserNotificationTypeSound) > 0),
|
|
@"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
|
|
};
|
|
|
|
self.requestPermissionsResolveBlock(notificationTypes);
|
|
self.requestPermissionsResolveBlock = nil;
|
|
}
|
|
|
|
/**
|
|
* Update the application icon badge number on the home screen
|
|
*/
|
|
RCT_EXPORT_METHOD(setApplicationIconBadgeNumber:(NSInteger)number)
|
|
{
|
|
RCTSharedApplication().applicationIconBadgeNumber = number;
|
|
}
|
|
|
|
/**
|
|
* Get the current application icon badge number on the home screen
|
|
*/
|
|
RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback)
|
|
{
|
|
callback(@[@(RCTSharedApplication().applicationIconBadgeNumber)]);
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
{
|
|
if (RCTRunningInAppExtension()) {
|
|
reject(RCTErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension"));
|
|
return;
|
|
}
|
|
|
|
if (self.requestPermissionsResolveBlock != nil) {
|
|
RCTLogError(@"Cannot call requestPermissions twice before the first has returned.");
|
|
return;
|
|
}
|
|
|
|
self.requestPermissionsResolveBlock = resolve;
|
|
|
|
UIUserNotificationType types = UIUserNotificationTypeNone;
|
|
if (permissions) {
|
|
if ([RCTConvert BOOL:permissions[@"alert"]]) {
|
|
types |= UIUserNotificationTypeAlert;
|
|
}
|
|
if ([RCTConvert BOOL:permissions[@"badge"]]) {
|
|
types |= UIUserNotificationTypeBadge;
|
|
}
|
|
if ([RCTConvert BOOL:permissions[@"sound"]]) {
|
|
types |= UIUserNotificationTypeSound;
|
|
}
|
|
} else {
|
|
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
|
|
}
|
|
|
|
UIApplication *app = RCTSharedApplication();
|
|
if ([app respondsToSelector:@selector(registerUserNotificationSettings:)]) {
|
|
UIUserNotificationSettings *notificationSettings =
|
|
[UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
|
|
[app registerUserNotificationSettings:notificationSettings];
|
|
} else {
|
|
[app registerForRemoteNotificationTypes:(NSUInteger)types];
|
|
}
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(abandonPermissions)
|
|
{
|
|
[RCTSharedApplication() unregisterForRemoteNotifications];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
|
|
{
|
|
if (RCTRunningInAppExtension()) {
|
|
callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
|
|
return;
|
|
}
|
|
|
|
NSUInteger types = 0;
|
|
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
|
|
types = [RCTSharedApplication() currentUserNotificationSettings].types;
|
|
} else {
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
|
|
|
types = [RCTSharedApplication() enabledRemoteNotificationTypes];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
callback(@[@{
|
|
@"alert": @((types & UIUserNotificationTypeAlert) > 0),
|
|
@"badge": @((types & UIUserNotificationTypeBadge) > 0),
|
|
@"sound": @((types & UIUserNotificationTypeSound) > 0),
|
|
}]);
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
|
|
{
|
|
[RCTSharedApplication() presentLocalNotificationNow:notification];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(scheduleLocalNotification:(UILocalNotification *)notification)
|
|
{
|
|
[RCTSharedApplication() scheduleLocalNotification:notification];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(cancelAllLocalNotifications)
|
|
{
|
|
[RCTSharedApplication() cancelAllLocalNotifications];
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary *)userInfo)
|
|
{
|
|
for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
|
|
__block BOOL matchesAll = YES;
|
|
NSDictionary *notificationInfo = notification.userInfo;
|
|
[userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
|
if (![notificationInfo[key] isEqual:obj]) {
|
|
matchesAll = NO;
|
|
*stop = YES;
|
|
}
|
|
}];
|
|
if (matchesAll) {
|
|
[[UIApplication sharedApplication] cancelLocalNotification:notification];
|
|
}
|
|
}
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve
|
|
reject:(__unused RCTPromiseRejectBlock)reject)
|
|
{
|
|
NSDictionary<NSString *, id> *initialNotification =
|
|
[self.bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
|
|
resolve(RCTNullIfNil(initialNotification));
|
|
}
|
|
|
|
RCT_EXPORT_METHOD(getScheduledLocalNotifications:(RCTResponseSenderBlock)callback)
|
|
{
|
|
NSArray<UILocalNotification *> *scheduledLocalNotifications = [UIApplication sharedApplication].scheduledLocalNotifications;
|
|
NSMutableArray *formattedScheduledLocalNotifications = [[NSMutableArray alloc] init];
|
|
for (UILocalNotification *notification in scheduledLocalNotifications) {
|
|
[formattedScheduledLocalNotifications addObject:formatLocalNotification(notification)];
|
|
}
|
|
callback(@[formattedScheduledLocalNotifications]);
|
|
}
|
|
|
|
@end
|