Skip to content

Commit

Permalink
PushNotificationIOS requestPermission promisified
Browse files Browse the repository at this point in the history
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 facebook#7900

Differential Revision: D3387424

Pulled By: nicklockwood

fbshipit-source-id: e27df41e83216e4e2a14d1e42c6b26e72236f48c
  • Loading branch information
JAStanton authored and Morgan Pretty committed Aug 24, 2016
1 parent f787ae7 commit 57e8ea4
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
12 changes: 10 additions & 2 deletions Libraries/PushNotificationIOS/PushNotificationIOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -236,7 +244,7 @@ class PushNotificationIOS {
sound: true
};
}
RCTPushNotificationManager.requestPermissions(requestedPermissions);
return RCTPushNotificationManager.requestPermissions(requestedPermissions);
}

/**
Expand Down
43 changes: 42 additions & 1 deletion Libraries/PushNotificationIOS/RCTPushNotificationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -66,6 +73,10 @@ - (void)startObserving
selector:@selector(handleRemoteNotificationsRegistered:)
name:RCTRemoteNotificationsRegistered
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRegisterUserNotificationSettings:)
name:RCTRegisterUserNotificationSettings
object:nil];
}

- (void)stopObserving
Expand Down Expand Up @@ -93,6 +104,9 @@ + (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings
{
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRegisterUserNotificationSettings
object:self
userInfo:@{@"notificationSettings": notificationSettings}];
}
}

Expand Down Expand Up @@ -145,6 +159,23 @@ - (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
*/
Expand All @@ -161,12 +192,22 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
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"]]) {
Expand Down

0 comments on commit 57e8ea4

Please sign in to comment.