mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-07 22:42:13 +08:00
Summary:In order to use iOS notification actions with local notifications, we need to be able to specify a category string. This PR adds a category property to the `details` object used to create a local notification.
I also added support for the `alertAction` property, which is used to control the "slide to {alertAction}" text beneath the notification.
Finally, I added the doc for `userInfo` to `presentLocalNotification` (previously was only documented for `scheduleLocalNotification`.
**Test plan (required)**
I implemented the example from the [react-native-ios-notification-actions README](https://github.com/holmesal/react-native-ios-notification-actions), and created a couple of actions and grouped them under a category with identifier `something_happened`.
Prior to the changes in this PR, the shown local notification would not contain any actions.
With the changes in this PR, the shown local notification contains the specified actions.
Like so:
 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";
|
|
|
|
@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"]];
|
|
return notification;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation RCTPushNotificationManager
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
- (void)setBridge:(RCTBridge *)bridge
|
|
{
|
|
_bridge = bridge;
|
|
|
|
[[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];
|
|
}
|
|
|
|
- (NSDictionary<NSString *, id> *)constantsToExport
|
|
{
|
|
NSDictionary<NSString *, id> *initialNotification =
|
|
[_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
|
|
return @{@"initialNotification": RCTNullIfNil(initialNotification)};
|
|
}
|
|
|
|
+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
|
|
{
|
|
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
|
|
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
|
}
|
|
}
|
|
|
|
+ (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
|
|
{
|
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"localNotificationReceived"
|
|
body:notification.userInfo];
|
|
}
|
|
|
|
- (void)handleRemoteNotificationReceived:(NSNotification *)notification
|
|
{
|
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationReceived"
|
|
body:notification.userInfo];
|
|
}
|
|
|
|
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
|
|
{
|
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered"
|
|
body:notification.userInfo];
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
if (RCTRunningInAppExtension()) {
|
|
return;
|
|
}
|
|
|
|
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];
|
|
[app registerForRemoteNotifications];
|
|
} 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];
|
|
}
|
|
}
|
|
}
|
|
|
|
@end
|