Skip to content

Commit 89a1e94

Browse files
committed
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 #1304 Github Author: Andrew Imm <[email protected]> Test Plan: Imported from GitHub, without a `Test Plan:` line.
1 parent b2b89c0 commit 89a1e94

File tree

3 files changed

+117
-38
lines changed

3 files changed

+117
-38
lines changed

Libraries/PushNotificationIOS/PushNotificationIOS.js

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var _initialNotification = RCTPushNotificationManager &&
2020
RCTPushNotificationManager.initialNotification;
2121

2222
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
23+
var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
2324

2425
/**
2526
* Handle push notifications for your app, including permission handling and
@@ -49,30 +50,72 @@ class PushNotificationIOS {
4950
}
5051

5152
/**
52-
* Attaches a listener to remote notifications while the app is running in the
53-
* foreground or the background.
53+
* Attaches a listener to remote notification events while the app is running
54+
* in the foreground or the background.
5455
*
55-
* The handler will get be invoked with an instance of `PushNotificationIOS`
56+
* Valid events are:
57+
*
58+
* - `notification` : Fired when a remote notification is received. The
59+
* handler will be invoked with an instance of `PushNotificationIOS`.
60+
* - `register`: Fired when the user registers for remote notifications. The
61+
* handler will be invoked with a hex string representing the deviceToken.
5662
*/
5763
static addEventListener(type: string, handler: Function) {
5864
invariant(
59-
type === 'notification',
60-
'PushNotificationIOS only supports `notification` events'
61-
);
62-
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
63-
DEVICE_NOTIF_EVENT,
64-
(notifData) => {
65-
handler(new PushNotificationIOS(notifData));
66-
}
65+
type === 'notification' || type === 'register',
66+
'PushNotificationIOS only supports `notification` and `register` events'
6767
);
68+
if (type === 'notification') {
69+
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
70+
DEVICE_NOTIF_EVENT,
71+
(notifData) => {
72+
handler(new PushNotificationIOS(notifData));
73+
}
74+
);
75+
} else if (type === 'register') {
76+
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
77+
NOTIF_REGISTER_EVENT,
78+
(registrationInfo) => {
79+
handler(registrationInfo.deviceToken);
80+
}
81+
);
82+
}
6883
}
6984

7085
/**
71-
* Requests all notification permissions from iOS, prompting the user's
72-
* dialog box.
86+
* Requests notification permissions from iOS, prompting the user's
87+
* dialog box. By default, it will request all notification permissions, but
88+
* a subset of these can be requested by passing a map of requested
89+
* permissions.
90+
* The following permissions are supported:
91+
*
92+
* - `alert`
93+
* - `badge`
94+
* - `sound`
95+
*
96+
* If a map is provided to the method, only the permissions with truthy values
97+
* will be requested.
7398
*/
74-
static requestPermissions() {
75-
RCTPushNotificationManager.requestPermissions();
99+
static requestPermissions(permissions?: {
100+
alert?: boolean,
101+
badge?: boolean,
102+
sound?: boolean
103+
}) {
104+
var requestedPermissions = {};
105+
if (permissions) {
106+
requestedPermissions = {
107+
alert: !!permissions.alert,
108+
badge: !!permissions.badge,
109+
sound: !!permissions.sound
110+
};
111+
} else {
112+
requestedPermissions = {
113+
alert: true,
114+
badge: true,
115+
sound: true
116+
};
117+
}
118+
RCTPushNotificationManager.requestPermissions(requestedPermissions);
76119
}
77120

78121
/**
@@ -97,8 +140,8 @@ class PushNotificationIOS {
97140
*/
98141
static removeEventListener(type: string, handler: Function) {
99142
invariant(
100-
type === 'notification',
101-
'PushNotificationIOS only supports `notification` events'
143+
type === 'notification' || type === 'register',
144+
'PushNotificationIOS only supports `notification` and `register` events'
102145
);
103146
if (!_notifHandlers[handler]) {
104147
return;

Libraries/PushNotificationIOS/RCTPushNotificationManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
1515

1616
+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
17+
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
1718
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
1819

1920
@end

Libraries/PushNotificationIOS/RCTPushNotificationManager.m

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,18 @@
1212
#import "RCTBridge.h"
1313
#import "RCTEventDispatcher.h"
1414

15+
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
16+
17+
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
18+
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
19+
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
20+
#define UIUserNotificationTypeNone UIRemoteNotificationTypeNone
21+
#define UIUserNotificationType UIRemoteNotificationType
22+
23+
#endif
24+
1525
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
26+
NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
1627

1728
@implementation RCTPushNotificationManager
1829
{
@@ -30,6 +41,10 @@ - (instancetype)init
3041
selector:@selector(handleRemoteNotificationReceived:)
3142
name:RCTRemoteNotificationReceived
3243
object:nil];
44+
[[NSNotificationCenter defaultCenter] addObserver:self
45+
selector:@selector(handleRemoteNotificationsRegistered:)
46+
name:RCTRemoteNotificationsRegistered
47+
object:nil];
3348
}
3449
return self;
3550
}
@@ -52,6 +67,21 @@ + (void)application:(UIApplication *)application didRegisterUserNotificationSett
5267
}
5368
}
5469

70+
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
71+
{
72+
NSMutableString *hexString = [NSMutableString string];
73+
const unsigned char *bytes = [deviceToken bytes];
74+
for (int i = 0; i < [deviceToken length]; i++) {
75+
[hexString appendFormat:@"%02x", bytes[i]];
76+
}
77+
NSDictionary *userInfo = @{
78+
@"deviceToken" : [hexString copy]
79+
};
80+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
81+
object:self
82+
userInfo:userInfo];
83+
}
84+
5585
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
5686
{
5787
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
@@ -65,6 +95,12 @@ - (void)handleRemoteNotificationReceived:(NSNotification *)notification
6595
body:[notification userInfo]];
6696
}
6797

98+
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
99+
{
100+
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered"
101+
body:[notification userInfo]];
102+
}
103+
68104
/**
69105
* Update the application icon badge number on the home screen
70106
*/
@@ -83,36 +119,35 @@ - (void)handleRemoteNotificationReceived:(NSNotification *)notification
83119
]);
84120
}
85121

86-
RCT_EXPORT_METHOD(requestPermissions)
122+
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
87123
{
88-
Class _UIUserNotificationSettings;
89-
if ((_UIUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings"))) {
90-
UIUserNotificationType types = UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert;
91-
UIUserNotificationSettings *notificationSettings = [_UIUserNotificationSettings settingsForTypes:types categories:nil];
92-
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
124+
UIUserNotificationType types = UIRemoteNotificationTypeNone;
125+
if (permissions) {
126+
if ([permissions[@"alert"] boolValue]) {
127+
types |= UIUserNotificationTypeAlert;
128+
}
129+
if ([permissions[@"badge"] boolValue]) {
130+
types |= UIUserNotificationTypeBadge;
131+
}
132+
if ([permissions[@"sound"] boolValue]) {
133+
types |= UIUserNotificationTypeSound;
134+
}
93135
} else {
136+
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
137+
}
94138

95-
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
96-
97-
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
98-
UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert];
99-
139+
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
140+
id notificationSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
141+
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
142+
[[UIApplication sharedApplication] registerForRemoteNotifications];
143+
#else
144+
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
100145
#endif
101146

102-
}
103147
}
104148

105149
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
106150
{
107-
108-
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
109-
110-
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
111-
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
112-
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
113-
114-
#endif
115-
116151
NSUInteger types = 0;
117152
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
118153
types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];

0 commit comments

Comments
 (0)