Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PushNotificationIOS requestPermission promisified #7900

Closed
wants to merge 8 commits into from
Closed

PushNotificationIOS requestPermission promisified #7900

wants to merge 8 commits into from

Conversation

JAStanton
Copy link
Contributor

@JAStanton JAStanton commented Jun 2, 2016

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 scenario but we would have no clean way to determine if they have rejected the permission. It would break the example flow.

Test plan
In this video I display:

  • Requesting permission -- if the dialog is currently open. <-- Only available with this PR
  • Active - if I have all (badge, sound, and alert) push notification permissions or not
  • Detailed permissions which show device token (truncated), badge, sound, and alert.

pushnotifications 1

@ghost
Copy link

ghost commented Jun 2, 2016

By analyzing the blame information on this pull request, we identified @nicklockwood and @slycoder to be potential reviewers.

@ghost
Copy link

ghost commented Jun 2, 2016

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at [email protected]. Thanks!

@ghost
Copy link

ghost commented Jun 2, 2016

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 2, 2016
@satya164 satya164 added the Platform: iOS iOS applications. label Jun 2, 2016
{
if (self.requestPermissionsResolveBlock == nil) return;

NSMutableDictionary* notificationTypes = [NSMutableDictionary dictionaryWithObjectsAndKeys:@NO, @"alert", @NO, @"badge", @NO, @"sound", nil];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cleaner to write this as:

NSDictionary *notificationTypes = @{
  @"alert": @(notificationSettings.types & UIUserNotificationTypeAlert),
  ...
};

(may need an extra BOOL cast)

Copy link
Contributor Author

@JAStanton JAStanton Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot do a BOOL because it's going into an NSDictionary, it needs to be a NSNumber instead. Casted it to that.

Copy link
Contributor

@nicklockwood nicklockwood Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JAStanton I think @javache meant

@((BOOL)(notificationSettings.types & UIUserNotificationTypeAlert))

So that the value of the NSNumber is 1 or 0 instead of the numeric value of the UIUserNotificationTypeAlert enum.

However, that won't work either, since casting to a BOOL doesn't actually affect the value. I think what you'd actually need to write is

@(notificationSettings.types & UIUserNotificationTypeAlert > 0)

That's equivalent to

[NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeAlert]

But we prefer the modern @(...) syntax to [NSNumber numberWithX:...] in our codebase.

Copy link
Contributor Author

@JAStanton JAStanton Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, yeah I updated the PR to achieve the second approach but I agree with the shorthand of the first approach! Updated again! Done

@ghost
Copy link

ghost commented Jun 3, 2016

@JAStanton updated the pull request.

@ghost
Copy link

ghost commented Jun 3, 2016

@JAStanton updated the pull request.

}
UIUserNotificationSettings *notificationSettings = notification.userInfo;
NSDictionary *notificationTypes = @{
@"alert": @((BOOL)notificationSettings.types & UIUserNotificationTypeAlert),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won't actually work, for the reason I mentioned - casting to BOOL is basically just casting to char/int8, it won't actually coerce the value to be true or false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be written as

 @"alert": @(notificationSettings.types & UIUserNotificationTypeAlert > 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, alright I played with it on my device and the only change I made was wrapping the bitwise-and in parenthesis before comparing it. Otherwise it works fine 👍

@ghost
Copy link

ghost commented Jun 3, 2016

@JAStanton updated the pull request.

@nicklockwood
Copy link
Contributor

@facebook-github-bot shipit

@facebook-github-bot facebook-github-bot added GH Review: accepted Import Started This pull request has been imported. This does not imply the PR has been approved. and removed GH Review: review-needed labels Jun 3, 2016
@ghost
Copy link

ghost commented Jun 3, 2016

Thanks for importing. If you are an FB employee go to Phabricator to review.

@ghost
Copy link

ghost commented Jun 3, 2016

@JAStanton updated the pull request.

if (self.requestPermissionsResolveBlock == nil) {
return;
}
UIUserNotificationSettings *notificationSettings = notification.userInfo;
Copy link
Contributor

@nicklockwood nicklockwood Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JAStanton This failed to land due to a type error detected by our build system. You're assigning notification.userInfo (which is defined as being an NSDictionary) to a property of type UIUserNotificationSettings. I'm not sure why this worked for you locally, but it seems unlikely that it's correct.

Copy link
Contributor Author

@JAStanton JAStanton Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice, so it works because I was passing in UIUserNotificationSettings to the userInfo parameter of my NSNotification message instead of setting it a dictionary like how it's supposed to be used. Bummer. Updated, take a look! Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JAStanton ah, I totally missed that. Should just be a simple case of wrapping notificationSettings in a dictionary and then unwrapping it then:

@{ @"settings": notificationSettings }

@facebook-github-bot
Copy link
Contributor

@JAStanton updated the pull request.

@nicklockwood
Copy link
Contributor

@facebook-github-bot shipit

@ghost
Copy link

ghost commented Jun 3, 2016

Thanks for importing. If you are an FB employee go to Phabricator to review.

@ghost ghost closed this in f4dbf37 Jun 3, 2016
@chandlervdw
Copy link

chandlervdw commented Jul 27, 2016

@JAStanton in the docs, it's not explicit how to use this. Is the following correct?

PushNotificationIOS.requestPermissions().then((permissions) => console.log(permissions));

What am I missing? The above never fires the console.log().

samerce pushed a commit to iodine/react-native that referenced this pull request Aug 23, 2016
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
mpretty-cyro pushed a commit to HomePass/react-native that referenced this pull request Aug 25, 2016
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
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Import Started This pull request has been imported. This does not imply the PR has been approved. Platform: iOS iOS applications.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants