Skip to content

Commit

Permalink
registration error event
Browse files Browse the repository at this point in the history
Summary:
This is an updated version of facebook#2336 and facebook#7694.

 ---

This adds a `registrationError` event that is emitted by `PushNotificationIOS` whenever an application receives a registration error from APNS (APNS service failure, running on simulator, etc).  This event fires to the exclusion of the `register` event (and vice versa).

**How to use**

Add the following to your `AppDelegate.m`:

```obj-c
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
  [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
}
```

And register an event handler for the event:

```js
PushNotificationIOS.addEventListener('registrationError', function({ message, code }) {
  // Complete your registration process in error.
});
```

**Test plan**

Added support for this event (and `register`) to UIExplorer as a proof of concept.  Navigating to the push notifications example on a simulator is an easy way to reproduce this e
Closes facebook#9650

Differential Revision: D3822142

Pulled By: javache

fbshipit-source-id: a15ed8941b74dc3eed2c44c658deccbcaf39ce3d
  • Loading branch information
nevir authored and mikelambert committed Sep 29, 2016
1 parent bd5f971 commit 6ddcbf3
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 20 deletions.
33 changes: 33 additions & 0 deletions Examples/UIExplorer/UIExplorer/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#import "RCTJavaScriptLoader.h"
#import "RCTLinkingManager.h"
#import "RCTRootView.h"
#import "RCTPushNotificationManager.h"

@interface AppDelegate() <RCTBridgeDelegate>

Expand Down Expand Up @@ -76,4 +77,36 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge
onComplete:loadCallback];
}

# pragma mark - Push Notifications

// Required to register for notifications
- (void)application:(__unused UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
}

// Required for the remoteNotificationsRegistered event.
- (void)application:(__unused UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

// Required for the remoteNotificationRegistrationError event.
- (void)application:(__unused UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
}

// Required for the remoteNotificationReceived event.
- (void)application:(__unused UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
{
[RCTPushNotificationManager didReceiveRemoteNotification:notification];
}

// Required for the localNotificationReceived event.
- (void)application:(__unused UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RCTPushNotificationManager didReceiveLocalNotification:notification];
}

@end
40 changes: 31 additions & 9 deletions Examples/UIExplorer/js/PushNotificationIOSExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,18 @@ class Button extends React.Component {

class NotificationExample extends React.Component {
componentWillMount() {
// Add listener for push notifications
PushNotificationIOS.addEventListener('notification', this._onNotification);
// Add listener for local notifications
PushNotificationIOS.addEventListener('register', this._onRegistered);
PushNotificationIOS.addEventListener('registrationError', this._onRegistrationError);
PushNotificationIOS.addEventListener('notification', this._onRemoteNotification);
PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification);

PushNotificationIOS.requestPermissions();
}

componentWillUnmount() {
// Remove listener for push notifications
PushNotificationIOS.removeEventListener('notification', this._onNotification);
// Remove listener for local notifications
PushNotificationIOS.removeEventListener('register', this._onRegistered);
PushNotificationIOS.removeEventListener('registrationError', this._onRegistrationError);
PushNotificationIOS.removeEventListener('notification', this._onRemoteNotification);
PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification);
}

Expand Down Expand Up @@ -101,7 +103,29 @@ class NotificationExample extends React.Component {
});
}

_onNotification(notification) {
_onRegistered(deviceToken) {
AlertIOS.alert(
'Registered For Remote Push',
`Device Token: ${deviceToken}`,
[{
text: 'Dismiss',
onPress: null,
}]
);
}

_onRegistrationError(error) {
AlertIOS.alert(
'Failed To Register For Remote Push',
`Error (${error.code}): ${error.message}`,
[{
text: 'Dismiss',
onPress: null,
}]
);
}

_onRemoteNotification(notification) {
AlertIOS.alert(
'Push Notification Received',
'Alert message: ' + notification.getMessage(),
Expand Down Expand Up @@ -170,8 +194,6 @@ exports.examples = [
{
title: 'Badge Number',
render(): ReactElement<any> {
PushNotificationIOS.requestPermissions();

return (
<View>
<Button
Expand Down
60 changes: 50 additions & 10 deletions Libraries/PushNotificationIOS/PushNotificationIOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,36 @@ const _notifHandlers = new Map();

const DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
const NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
const NOTIF_REGISTRATION_ERROR_EVENT = 'remoteNotificationRegistrationError';
const DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';

/**
* An event emitted by PushNotificationIOS.
*/
export type PushNotificationEventName = $Enum<{
/**
* Fired when a remote notification is received. The handler will be invoked
* with an instance of `PushNotificationIOS`.
*/
notification: string,
/**
* Fired when a local notification is received. The handler will be invoked
* with an instance of `PushNotificationIOS`.
*/
localNotification: string,
/**
* Fired when the user registers for remote notifications. The handler will be
* invoked with a hex string representing the deviceToken.
*/
register: string,
/**
* Fired when the user fails to register for remote notifications. Typically
* occurs when APNS is having issues, or the device is a simulator. The
* handler will be invoked with {message: string, code: number, details: any}.
*/
registrationError: string,
}>;

/**
* Handle push notifications for your app, including permission handling and
* icon badge number.
Expand Down Expand Up @@ -56,6 +84,11 @@ const DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
* {
* [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
* }
* // Required for the registrationError event.
* - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
* {
* [RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
* }
* // Required for the notification event.
* - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
* {
Expand All @@ -66,10 +99,6 @@ const DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
* {
* [RCTPushNotificationManager didReceiveLocalNotification:notification];
* }
* - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
* {
* NSLog(@"%@", error);
* }
* ```
*/
class PushNotificationIOS {
Expand Down Expand Up @@ -162,11 +191,15 @@ class PushNotificationIOS {
* handler will be invoked with an instance of `PushNotificationIOS`.
* - `register`: Fired when the user registers for remote notifications. The
* handler will be invoked with a hex string representing the deviceToken.
* - `registrationError`: Fired when the user fails to register for remote
* notifications. Typically occurs when APNS is having issues, or the device
* is a simulator. The handler will be invoked with
* {message: string, code: number, details: any}.
*/
static addEventListener(type: string, handler: Function) {
static addEventListener(type: PushNotificationEventName, handler: Function) {
invariant(
type === 'notification' || type === 'register' || type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register` and `localNotification` events'
type === 'notification' || type === 'register' || type === 'registrationError' || type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events'
);
var listener;
if (type === 'notification') {
Expand All @@ -190,6 +223,13 @@ class PushNotificationIOS {
handler(registrationInfo.deviceToken);
}
);
} else if (type === 'registrationError') {
listener = PushNotificationEmitter.addListener(
NOTIF_REGISTRATION_ERROR_EVENT,
(errorInfo) => {
handler(errorInfo);
}
);
}
_notifHandlers.set(handler, listener);
}
Expand All @@ -198,10 +238,10 @@ class PushNotificationIOS {
* Removes the event listener. Do this in `componentWillUnmount` to prevent
* memory leaks
*/
static removeEventListener(type: string, handler: Function) {
static removeEventListener(type: PushNotificationEventName, handler: Function) {
invariant(
type === 'notification' || type === 'register' || type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register` and `localNotification` events'
type === 'notification' || type === 'register' || type === 'registrationError' || type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events'
);
var listener = _notifHandlers.get(handler);
if (!listener) {
Expand Down
1 change: 1 addition & 0 deletions Libraries/PushNotificationIOS/RCTPushNotificationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;
+ (void)didReceiveLocalNotification:(UILocalNotification *)notification;
+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;

@end
26 changes: 25 additions & 1 deletion Libraries/PushNotificationIOS/RCTPushNotificationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
NSString *const RCTRegisterUserNotificationSettings = @"RegisterUserNotificationSettings";

NSString *const RCTErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
NSString *const RCTErrorRemoteNotificationRegistrationFailed = @"E_FAILED_TO_REGISTER_FOR_REMOTE_NOTIFICATIONS";

@implementation RCTConvert (UILocalNotification)

Expand Down Expand Up @@ -96,6 +97,10 @@ - (void)startObserving
selector:@selector(handleRemoteNotificationsRegistered:)
name:RCTRemoteNotificationsRegistered
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationRegistrationError:)
name:RCTErrorRemoteNotificationRegistrationFailed
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRegisterUserNotificationSettings:)
name:RCTRegisterUserNotificationSettings
Expand All @@ -111,7 +116,8 @@ - (void)stopObserving
{
return @[@"localNotificationReceived",
@"remoteNotificationReceived",
@"remoteNotificationsRegistered"];
@"remoteNotificationsRegistered",
@"remoteNotificationRegistrationError"];
}

+ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
Expand All @@ -137,6 +143,13 @@ + (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
userInfo:@{@"deviceToken" : [hexString copy]}];
}

+ (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTErrorRemoteNotificationRegistrationFailed
object:self
userInfo:@{@"error": error}];
}

+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
Expand Down Expand Up @@ -168,6 +181,17 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
[self sendEventWithName:@"remoteNotificationsRegistered" body:notification.userInfo];
}

- (void)handleRemoteNotificationRegistrationError:(NSNotification *)notification
{
NSError *error = notification.userInfo[@"error"];
NSDictionary *errorDetails = @{
@"message": error.localizedDescription,
@"code": @(error.code),
@"details": error.userInfo,
};
[self sendEventWithName:@"remoteNotificationRegistrationError" body:errorDetails];
}

- (void)handleRegisterUserNotificationSettings:(NSNotification *)notification
{
if (_requestPermissionsResolveBlock == nil) {
Expand Down

0 comments on commit 6ddcbf3

Please sign in to comment.