Skip to content

Commit edfdafc

Browse files
p-sunfacebook-github-bot
authored andcommitted
Resolve and reject promise for PushNotificationIOS.requestPermissions
Summary: **Resolve/Reject Promise** * Add onFulfill and onReject to the `PushNotificationIOS.requestPermissions()` Promise **Replace Apple-deprecated notification method** * Old: In iOS 10, `UIApplication.registerUserNotificationSettings` was deprecated. Calling this would then call the AppDelegate's lifecycle function `didRegisterUserNotificationSettings`, and then in the AppDelegate, we'd call `RCTPushNotificationManager.didRegisterUserNotificationSettings` to return the user settings. [registerusernotificationsettings Doc](https://developer.apple.com/documentation/uikit/uiapplication/1622932-registerusernotificationsettings?language=objc) * New: Replace deprecated function with Apple's recommended `UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler`, which no longer needs the AppDelegate lifecycle method because it directly returns the user's settings in a completion hander. [requestauthorizationwithoptions Doc](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649527-requestauthorizationwithoptions?language=objc) **Add Tests** * Add tests on `PushNotificationIOSExample.js` to test that the onFulfill and onReject are called * On `PushNotificationIOSExample.js`, instead of asking permission upon page load, ask for permission when the user taps the button "Request Notifications (Should Display Alert)". * Before, asking for permission multiple times before would result in the RN error "cannot call requestPermissions twice before the first has returned", now you can ask for permission as many times as you want because I've removed the now unused `RCTPromiseResolveBlock`. **Future** If this works on device (we have to land this to test push on device), we can delete `RTCPushNotificationManager.didRegisterUserNotificationSettings` which is being called from several apps. Changelog: [iOS] [Added] Resolve and reject promise for PushNotificationIOS.requestPermissions Reviewed By: PeteTheHeat Differential Revision: D19700061 fbshipit-source-id: 02ba815787efc9047f33ffcdfafe962b134afe6d
1 parent a35efb9 commit edfdafc

File tree

2 files changed

+79
-71
lines changed

2 files changed

+79
-71
lines changed

Libraries/PushNotificationIOS/RCTPushNotificationManager.mm

+30-53
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
static NSString *const kLocalNotificationReceived = @"LocalNotificationReceived";
2323
static NSString *const kRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
24-
static NSString *const kRegisterUserNotificationSettings = @"RegisterUserNotificationSettings";
2524
static NSString *const kRemoteNotificationRegistrationFailed = @"RemoteNotificationRegistrationFailed";
2625

2726
static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
@@ -83,9 +82,6 @@ @interface RCTPushNotificationManager () <NativePushNotificationManagerIOS>
8382
#endif //TARGET_OS_TV / TARGET_OS_UIKITFORMAC
8483

8584
@implementation RCTPushNotificationManager
86-
{
87-
RCTPromiseResolveBlock _requestPermissionsResolveBlock;
88-
}
8985

9086
#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC
9187

@@ -152,10 +148,6 @@ - (void)startObserving
152148
selector:@selector(handleRemoteNotificationReceived:)
153149
name:RCTRemoteNotificationReceived
154150
object:nil];
155-
[[NSNotificationCenter defaultCenter] addObserver:self
156-
selector:@selector(handleRegisterUserNotificationSettings:)
157-
name:kRegisterUserNotificationSettings
158-
object:nil];
159151
[[NSNotificationCenter defaultCenter] addObserver:self
160152
selector:@selector(handleRemoteNotificationsRegistered:)
161153
name:kRemoteNotificationsRegistered
@@ -181,12 +173,6 @@ - (void)stopObserving
181173

182174
+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
183175
{
184-
if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
185-
[RCTSharedApplication() registerForRemoteNotifications];
186-
[[NSNotificationCenter defaultCenter] postNotificationName:kRegisterUserNotificationSettings
187-
object:self
188-
userInfo:@{@"notificationSettings": notificationSettings}];
189-
}
190176
}
191177

192178
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
@@ -272,25 +258,6 @@ - (void)handleRemoteNotificationRegistrationError:(NSNotification *)notification
272258
[self sendEventWithName:@"remoteNotificationRegistrationError" body:errorDetails];
273259
}
274260

275-
- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
276-
{
277-
if (_requestPermissionsResolveBlock == nil) {
278-
return;
279-
}
280-
281-
UIUserNotificationSettings *notificationSettings = notification.userInfo[@"notificationSettings"];
282-
NSDictionary *notificationTypes = @{
283-
@"alert": @((notificationSettings.types & UIUserNotificationTypeAlert) > 0),
284-
@"sound": @((notificationSettings.types & UIUserNotificationTypeSound) > 0),
285-
@"badge": @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
286-
};
287-
288-
_requestPermissionsResolveBlock(notificationTypes);
289-
// Clean up listener added in requestPermissions
290-
[self removeListeners:1];
291-
_requestPermissionsResolveBlock = nil;
292-
}
293-
294261
RCT_EXPORT_METHOD(onFinishRemoteNotification:(NSString *)notificationId fetchResult:(NSString *)fetchResult) {
295262
UIBackgroundFetchResult result = [RCTConvert UIBackgroundFetchResult:fetchResult];
296263
RCTRemoteNotificationCallback completionHandler = self.remoteNotificationCallbacks[notificationId];
@@ -322,19 +289,13 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
322289
resolve:(RCTPromiseResolveBlock)resolve
323290
reject:(RCTPromiseRejectBlock)reject)
324291
{
325-
if (RCTRunningInAppExtension()) {
326-
reject(kErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension"));
327-
return;
328-
}
329-
330-
if (_requestPermissionsResolveBlock != nil) {
331-
RCTLogError(@"Cannot call requestPermissions twice before the first has returned.");
332-
return;
333-
}
292+
if (RCTRunningInAppExtension()) {
293+
reject(kErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(@"Requesting push notifications is currently unavailable in an app extension"));
294+
return;
295+
}
334296

335297
// Add a listener to make sure that startObserving has been called
336298
[self addListener:@"remoteNotificationsRegistered"];
337-
_requestPermissionsResolveBlock = resolve;
338299

339300
UIUserNotificationType types = UIUserNotificationTypeNone;
340301

@@ -348,9 +309,18 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
348309
types |= UIUserNotificationTypeSound;
349310
}
350311

351-
UIUserNotificationSettings *notificationSettings =
352-
[UIUserNotificationSettings settingsForTypes:types categories:nil];
353-
[RCTSharedApplication() registerUserNotificationSettings:notificationSettings];
312+
[UNUserNotificationCenter.currentNotificationCenter
313+
requestAuthorizationWithOptions:types
314+
completionHandler:^(BOOL granted, NSError *_Nullable error) {
315+
if (error != NULL) {
316+
reject(@"-1", @"Error - Push authorization request failed.", error);
317+
} else {
318+
[RCTSharedApplication() registerForRemoteNotifications];
319+
[UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
320+
resolve(RCTPromiseResolveValueForUNNotificationSettings(settings));
321+
}];
322+
}
323+
}];
354324
}
355325

356326
RCT_EXPORT_METHOD(abandonPermissions)
@@ -361,16 +331,23 @@ - (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
361331
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
362332
{
363333
if (RCTRunningInAppExtension()) {
364-
callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
334+
callback(@[RCTSettingsDictForUNNotificationSettings(NO, NO, NO)]);
365335
return;
366336
}
367337

368-
NSUInteger types = [RCTSharedApplication() currentUserNotificationSettings].types;
369-
callback(@[@{
370-
@"alert": @((types & UIUserNotificationTypeAlert) > 0),
371-
@"badge": @((types & UIUserNotificationTypeBadge) > 0),
372-
@"sound": @((types & UIUserNotificationTypeSound) > 0),
373-
}]);
338+
[UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
339+
callback(@[RCTPromiseResolveValueForUNNotificationSettings(settings)]);
340+
}];
341+
}
342+
343+
static inline NSDictionary *RCTPromiseResolveValueForUNNotificationSettings(UNNotificationSettings* _Nonnull settings) {
344+
return RCTSettingsDictForUNNotificationSettings(settings.alertSetting == UNNotificationSettingEnabled,
345+
settings.badgeSetting == UNNotificationSettingEnabled,
346+
settings.soundSetting == UNNotificationSettingEnabled);
347+
}
348+
349+
static inline NSDictionary *RCTSettingsDictForUNNotificationSettings(BOOL alert, BOOL badge, BOOL sound) {
350+
return @{@"alert": @(alert), @"badge": @(badge), @"sound": @(sound)};
374351
}
375352

376353
RCT_EXPORT_METHOD(presentLocalNotification:(JS::NativePushNotificationManagerIOS::Notification &)notification)

RNTester/js/examples/PushNotificationIOS/PushNotificationIOSExample.js

+49-18
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ class NotificationExample extends React.Component<{...}> {
4949
'localNotification',
5050
this._onLocalNotification,
5151
);
52-
53-
PushNotificationIOS.requestPermissions();
5452
}
5553

5654
componentWillUnmount() {
@@ -173,18 +171,51 @@ class NotificationPermissionExample extends React.Component<
173171
return (
174172
<View>
175173
<Button
176-
onPress={this._showPermissions.bind(this)}
177-
label="Show enabled permissions"
174+
onPress={this._requestPermissions}
175+
label="Request Notifications (Should Display Alert)"
178176
/>
179-
<Text>{JSON.stringify(this.state.permissions)}</Text>
177+
<Button onPress={this._checkPermissions} label="Check permissions" />
178+
<Text style={{textAlign: 'center'}}>
179+
{JSON.stringify(this.state.permissions)}
180+
</Text>
180181
</View>
181182
);
182183
}
183184

184-
_showPermissions() {
185+
_requestPermissions = () => {
186+
PushNotificationIOS.requestPermissions().then(
187+
onFulfill => {
188+
this._showAlert(
189+
'Successfully requested permissions -- ' +
190+
'Alert: ' +
191+
onFulfill.alert.toString() +
192+
', Badge: ' +
193+
onFulfill.badge.toString() +
194+
', Sound: ' +
195+
onFulfill.sound.toString(),
196+
);
197+
this._checkPermissions();
198+
},
199+
(onReject?) => {
200+
this._showAlert('Error requesting permissions');
201+
this._checkPermissions();
202+
},
203+
);
204+
};
205+
206+
_checkPermissions = () => {
185207
PushNotificationIOS.checkPermissions(permissions => {
186208
this.setState({permissions});
187209
});
210+
};
211+
212+
_showAlert(text) {
213+
Alert.alert('Notification Permission', text, [
214+
{
215+
text: 'Dismiss',
216+
onPress: null,
217+
},
218+
]);
188219
}
189220
}
190221

@@ -202,6 +233,18 @@ const styles = StyleSheet.create({
202233
exports.title = 'PushNotificationIOS';
203234
exports.description = 'Apple PushNotification and badge value';
204235
exports.examples = [
236+
{
237+
title: 'Notifications Permissions',
238+
render(): React.Element<any> {
239+
return <NotificationPermissionExample />;
240+
},
241+
},
242+
{
243+
title: 'Push Notifications',
244+
render(): React.Element<any> {
245+
return <NotificationExample />;
246+
},
247+
},
205248
{
206249
title: 'Badge Number',
207250
render(): React.Element<any> {
@@ -221,16 +264,4 @@ exports.examples = [
221264
);
222265
},
223266
},
224-
{
225-
title: 'Push Notifications',
226-
render(): React.Element<any> {
227-
return <NotificationExample />;
228-
},
229-
},
230-
{
231-
title: 'Notifications Permissions',
232-
render(): React.Element<any> {
233-
return <NotificationPermissionExample />;
234-
},
235-
},
236267
];

0 commit comments

Comments
 (0)