Add an event for remote notification registration, and improve permissions request

Summary:
In order to add Push support to the Parse JS SDK in React Native, we need a way to receive the APNS device token from the JS context. This adds another event to PushNotificationIOS, so that code can respond to a successful registration.

Additionally, I've updated the `requestPermissions` call to accept an optional map of parameters. This way, developers can request a subset of user notification types.
Closes https://github.com/facebook/react-native/pull/1304
Github Author: Andrew Imm <andrewi@fb.com>

Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
Andrew Imm 2015-06-03 14:11:20 -07:00
parent b2b89c0b68
commit 89a1e94a15
3 changed files with 117 additions and 38 deletions

View File

@ -20,6 +20,7 @@ var _initialNotification = RCTPushNotificationManager &&
RCTPushNotificationManager.initialNotification;
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
/**
* Handle push notifications for your app, including permission handling and
@ -49,30 +50,72 @@ class PushNotificationIOS {
}
/**
* Attaches a listener to remote notifications while the app is running in the
* foreground or the background.
* Attaches a listener to remote notification events while the app is running
* in the foreground or the background.
*
* The handler will get be invoked with an instance of `PushNotificationIOS`
* Valid events are:
*
* - `notification` : Fired when a remote notification is received. The
* handler will be invoked with an instance of `PushNotificationIOS`.
* - `register`: Fired when the user registers for remote notifications. The
* handler will be invoked with a hex string representing the deviceToken.
*/
static addEventListener(type: string, handler: Function) {
invariant(
type === 'notification',
'PushNotificationIOS only supports `notification` events'
);
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
DEVICE_NOTIF_EVENT,
(notifData) => {
handler(new PushNotificationIOS(notifData));
}
type === 'notification' || type === 'register',
'PushNotificationIOS only supports `notification` and `register` events'
);
if (type === 'notification') {
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
DEVICE_NOTIF_EVENT,
(notifData) => {
handler(new PushNotificationIOS(notifData));
}
);
} else if (type === 'register') {
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
NOTIF_REGISTER_EVENT,
(registrationInfo) => {
handler(registrationInfo.deviceToken);
}
);
}
}
/**
* Requests all notification permissions from iOS, prompting the user's
* dialog box.
* Requests notification permissions from iOS, prompting the user's
* dialog box. By default, it will request all notification permissions, but
* a subset of these can be requested by passing a map of requested
* permissions.
* The following permissions are supported:
*
* - `alert`
* - `badge`
* - `sound`
*
* If a map is provided to the method, only the permissions with truthy values
* will be requested.
*/
static requestPermissions() {
RCTPushNotificationManager.requestPermissions();
static requestPermissions(permissions?: {
alert?: boolean,
badge?: boolean,
sound?: boolean
}) {
var requestedPermissions = {};
if (permissions) {
requestedPermissions = {
alert: !!permissions.alert,
badge: !!permissions.badge,
sound: !!permissions.sound
};
} else {
requestedPermissions = {
alert: true,
badge: true,
sound: true
};
}
RCTPushNotificationManager.requestPermissions(requestedPermissions);
}
/**
@ -97,8 +140,8 @@ class PushNotificationIOS {
*/
static removeEventListener(type: string, handler: Function) {
invariant(
type === 'notification',
'PushNotificationIOS only supports `notification` events'
type === 'notification' || type === 'register',
'PushNotificationIOS only supports `notification` and `register` events'
);
if (!_notifHandlers[handler]) {
return;

View File

@ -14,6 +14,7 @@
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
@end

View File

@ -12,7 +12,18 @@
#import "RCTBridge.h"
#import "RCTEventDispatcher.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 RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
@implementation RCTPushNotificationManager
{
@ -30,6 +41,10 @@ RCT_EXPORT_MODULE()
selector:@selector(handleRemoteNotificationReceived:)
name:RCTRemoteNotificationReceived
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationsRegistered:)
name:RCTRemoteNotificationsRegistered
object:nil];
}
return self;
}
@ -52,6 +67,21 @@ RCT_EXPORT_MODULE()
}
}
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSMutableString *hexString = [NSMutableString string];
const unsigned char *bytes = [deviceToken bytes];
for (int i = 0; i < [deviceToken length]; i++) {
[hexString appendFormat:@"%02x", bytes[i]];
}
NSDictionary *userInfo = @{
@"deviceToken" : [hexString copy]
};
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
object:self
userInfo:userInfo];
}
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
@ -65,6 +95,12 @@ RCT_EXPORT_MODULE()
body:[notification userInfo]];
}
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
{
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered"
body:[notification userInfo]];
}
/**
* Update the application icon badge number on the home screen
*/
@ -83,36 +119,35 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback
]);
}
RCT_EXPORT_METHOD(requestPermissions)
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
{
Class _UIUserNotificationSettings;
if ((_UIUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings"))) {
UIUserNotificationType types = UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert;
UIUserNotificationSettings *notificationSettings = [_UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
UIUserNotificationType types = UIRemoteNotificationTypeNone;
if (permissions) {
if ([permissions[@"alert"] boolValue]) {
types |= UIUserNotificationTypeAlert;
}
if ([permissions[@"badge"] boolValue]) {
types |= UIUserNotificationTypeBadge;
}
if ([permissions[@"sound"] boolValue]) {
types |= UIUserNotificationTypeSound;
}
} else {
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert];
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
id notificationSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
#else
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
#endif
}
}
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
#endif
NSUInteger types = 0;
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];