PushNotificationIOS requestPermission promisified

Summary:
**Motivation**
Today it's hard to build a good flow around requesting permissions if we don't know when the user rejects the push notification permission.

With this PR I wrap `PushNotificationIOS#requestPermission` in a promise. The promise will return with the updated permissions when the user accepts, rejects or has previously rejected the permission.

An example flow of how an app should handle push notifications with the change proposed:
1) Show user an explanation of push notification permissions with a button to enable,
2) User presses the enable push notifications button,
3) If the user accepts -> take them into the app,
4) if the user rejects -> explain how to enable permission in the settings app.
5) My app will now store some state about how it has asked permissions for push notifications so that the next time the user is taken through this flow they will go straight to step 4.

Without this change we could listen to the `register` event that PushNotificationIOS fires on the success sc
Closes https://github.com/facebook/react-native/pull/7900

Differential Revision: D3387424

Pulled By: nicklockwood

fbshipit-source-id: e27df41e83216e4e2a14d1e42c6b26e72236f48c
This commit is contained in:
Jonathan Stanton 2016-06-03 16:14:44 -07:00 committed by Facebook Github Bot 7
parent 724134746b
commit f4dbf37ba8
2 changed files with 52 additions and 3 deletions

View File

@ -216,12 +216,20 @@ class PushNotificationIOS {
*
* If a map is provided to the method, only the permissions with truthy values
* will be requested.
* This method returns a promise that will resolve when the user accepts,
* rejects, or if the permissions were previously rejected. The promise
* resolves to the current state of the permission.
*/
static requestPermissions(permissions?: {
alert?: boolean,
badge?: boolean,
sound?: boolean
}) {
}): Promise<{
alert: boolean,
badge: boolean,
sound: boolean
}> {
var requestedPermissions = {};
if (permissions) {
requestedPermissions = {
@ -236,7 +244,7 @@ class PushNotificationIOS {
sound: true
};
}
RCTPushNotificationManager.requestPermissions(requestedPermissions);
return RCTPushNotificationManager.requestPermissions(requestedPermissions);
}
/**

View File

@ -27,6 +27,13 @@
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)
@ -66,6 +73,10 @@ RCT_EXPORT_MODULE()
selector:@selector(handleRemoteNotificationsRegistered:)
name:RCTRemoteNotificationsRegistered
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRegisterUserNotificationSettings:)
name:RCTRegisterUserNotificationSettings
object:nil];
}
- (void)stopObserving
@ -93,6 +104,9 @@ RCT_EXPORT_MODULE()
{
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRegisterUserNotificationSettings
object:self
userInfo:@{@"notificationSettings": notificationSettings}];
}
}
@ -145,6 +159,23 @@ RCT_EXPORT_MODULE()
[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
*/
@ -161,12 +192,22 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback
callback(@[@(RCTSharedApplication().applicationIconBadgeNumber)]);
}
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
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"]]) {