react-native/Libraries/PushNotificationIOS/PushNotificationIOS.js

456 lines
14 KiB
JavaScript
Raw Normal View History

/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
const NativeEventEmitter = require('NativeEventEmitter');
const RCTPushNotificationManager = require('NativeModules')
.PushNotificationManager;
const invariant = require('fbjs/lib/invariant');
const PushNotificationEmitter = new NativeEventEmitter(
RCTPushNotificationManager,
);
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';
Expose content-available APS key for iOS silent push Summary: <details> Thanks for submitting a PR! Please read these instructions carefully: - [ ] Explain the **motivation** for making this change. - [ ] Provide a **test plan** demonstrating that the code is solid. - [ ] Match the **code formatting** of the rest of the codebase. - [ ] Target the `master` branch, NOT a "stable" branch. Please read the [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to learn more about contributing to React Native. </details> _What existing problem does the pull request solve? In iOS when sending a silent push notification you need to configure the 'content-available' APS key to the value of 1 (When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate, see [apple docs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)). This PR exposes this property to the notification event handler so app code can handle silent push scenario specifically. Currently this property is not available. I've updated the PushNotificationIOSExample in the RNTester. 1. Open RNTester in xcode 2. Enable the push notifications capability 3. run on device 4. Go to PushNotificationIOS 5. click on "send fake notification" 6. verify alert message contains 'content-available' with a value of 1. Closes https://github.com/facebook/react-native/pull/14584 Differential Revision: D5279181 Pulled By: shergin fbshipit-source-id: d2288e147d89ba267f54265d819aa0a9969095e7
2017-06-19 23:37:31 +00:00
export type ContentAvailable = 1 | null | void;
export type FetchResult = {
NewData: string,
NoData: string,
ResultFailed: string,
};
/**
* 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,
}>;
2015-03-26 16:28:03 +00:00
/**
Include Create React Native App in Getting Started Summary: cc hramos Create React Native App was designed to reduce "time to hello world" to 5-10 minutes for React Native apps. This PR would make CRNA the first way to get started that new users encounter. Included also is some text to help advanced users navigate the question of whether to use CRNA or whether to go straight to `react-native init`. It also includes a new banner for the iOS and Android guides, since they do not apply to CRNA users. Changes are only to the website, screenshots below. This branch was created from the last CI-passing master commit this morning, dependencies were freshly installed and these screenshots are from a clean build. [The Getting Started page](https://www.dropbox.com/s/1s7f3wu3oxr6gpo/Screenshot%202017-04-04%2015.12.29.png?dl=0) [The "native builds only" banner](https://www.dropbox.com/s/nyv51xdiibdkn57/Screenshot%202017-04-04%2015.13.25.png?dl=0) [Pages which still apply to CRNApps have no banner](https://www.dropbox.com/s/qgl0h6uzynqkmy2/Screenshot%202017-04-04%2015.14.10.png?dl=0) <details> * [x] Decide how to handle native code & react-native-cli references outside of the `banner: ejected` guides * [x] [Debugging: Accessing Console Logs](https://facebook.github.io/react-native/docs/debugging.html#accessing-console-logs) isn't needed in CRNA (logs are forwarded alongside packager output) * [x] [Debugging: With Stetho](https://facebook.github.io/react-native/docs/debugging.html#debugging-with-stetho-http-facebook-github-io-stetho-on-android) requires native code * [x] [Debugging: Debugging Native Code](https://facebook.github.io/react-native/docs/debugging.html#debugging-native-code) is native-only * [x] [AppRegistry](https://facebook.github.io/react-native/docs/appregistry.html) only applies to ejected apps, since this is generated from code, I don't think we can set `banner: ejected`? * [x] [Linking](https://facebook.github.io/react-native/docs/linking.html) involves changing Android manifests and other native-side things * [x] [PermissionsAndroid](https://facebook.github.io/react-native/docs/permissionsandroid.html) may be flaky in the Expo client, I can't recall (cc jesseruder) * [x] [PushNotificationIOS](https://facebook.github.io/react-native/docs/pushnotificationios.html) won't work inside Expo, as it has to [handle its own push notifs](https://docs.expo.io/versions/v15.0.0/guides/push-notifications.html) * [x] [Geolocation](https://facebook.github.io/react-native/docs/geolocation.html) requires a polyfill that will most likely ship with next week's release, but that won't have any manifest changes necessary * [ ] Figure out a strategy to handle the fact that CRNA will lag stable RN releases by ~1 week * [x] Confirm linking out to CRNA docs is an OK strategy as opposed to moving ejecting, etc. docs in-tree * [ ] Answer questions (I'll add some review comments to call out a few things) </details> Closes https://github.com/facebook/react-native/pull/13303 Differential Revision: D4950661 Pulled By: hramos fbshipit-source-id: 3dd43828f38ca6ede3f2b0683608c56420dc6525
2017-04-26 14:09:36 +00:00
*
2015-03-26 16:28:03 +00:00
* Handle push notifications for your app, including permission handling and
* icon badge number.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html
2015-03-26 16:28:03 +00:00
*/
class PushNotificationIOS {
_data: Object;
_alert: string | Object;
_sound: string;
_category: string;
Expose content-available APS key for iOS silent push Summary: <details> Thanks for submitting a PR! Please read these instructions carefully: - [ ] Explain the **motivation** for making this change. - [ ] Provide a **test plan** demonstrating that the code is solid. - [ ] Match the **code formatting** of the rest of the codebase. - [ ] Target the `master` branch, NOT a "stable" branch. Please read the [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to learn more about contributing to React Native. </details> _What existing problem does the pull request solve? In iOS when sending a silent push notification you need to configure the 'content-available' APS key to the value of 1 (When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate, see [apple docs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)). This PR exposes this property to the notification event handler so app code can handle silent push scenario specifically. Currently this property is not available. I've updated the PushNotificationIOSExample in the RNTester. 1. Open RNTester in xcode 2. Enable the push notifications capability 3. run on device 4. Go to PushNotificationIOS 5. click on "send fake notification" 6. verify alert message contains 'content-available' with a value of 1. Closes https://github.com/facebook/react-native/pull/14584 Differential Revision: D5279181 Pulled By: shergin fbshipit-source-id: d2288e147d89ba267f54265d819aa0a9969095e7
2017-06-19 23:37:31 +00:00
_contentAvailable: ContentAvailable;
_badgeCount: number;
_notificationId: string;
_isRemote: boolean;
_remoteNotificationCompleteCallbackCalled: boolean;
_threadID: string;
static FetchResult: FetchResult = {
NewData: 'UIBackgroundFetchResultNewData',
NoData: 'UIBackgroundFetchResultNoData',
ResultFailed: 'UIBackgroundFetchResultFailed',
};
/**
* Schedules the localNotification for immediate presentation.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#presentlocalnotification
*/
static presentLocalNotification(details: Object) {
RCTPushNotificationManager.presentLocalNotification(details);
}
/**
* Schedules the localNotification for future presentation.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#schedulelocalnotification
*/
static scheduleLocalNotification(details: Object) {
RCTPushNotificationManager.scheduleLocalNotification(details);
}
/**
* Cancels all scheduled localNotifications.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#cancelalllocalnotifications
*/
static cancelAllLocalNotifications() {
RCTPushNotificationManager.cancelAllLocalNotifications();
}
/**
* Remove all delivered notifications from Notification Center.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#removealldeliverednotifications
*/
static removeAllDeliveredNotifications(): void {
RCTPushNotificationManager.removeAllDeliveredNotifications();
}
/**
* Provides you with a list of the apps notifications that are still displayed in Notification Center.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getdeliverednotifications
*/
static getDeliveredNotifications(
callback: (notifications: Array<Object>) => void,
): void {
RCTPushNotificationManager.getDeliveredNotifications(callback);
}
/**
* Removes the specified notifications from Notification Center
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#removedeliverednotifications
*/
static removeDeliveredNotifications(identifiers: Array<string>): void {
RCTPushNotificationManager.removeDeliveredNotifications(identifiers);
}
2015-03-26 16:28:03 +00:00
/**
* Sets the badge number for the app icon on the home screen.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#setapplicationiconbadgenumber
2015-03-26 16:28:03 +00:00
*/
static setApplicationIconBadgeNumber(number: number) {
RCTPushNotificationManager.setApplicationIconBadgeNumber(number);
}
2015-03-26 16:28:03 +00:00
/**
* Gets the current badge number for the app icon on the home screen.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getapplicationiconbadgenumber
2015-03-26 16:28:03 +00:00
*/
static getApplicationIconBadgeNumber(callback: Function) {
RCTPushNotificationManager.getApplicationIconBadgeNumber(callback);
}
/**
* Cancel local notifications.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#cancellocalnotification
*/
static cancelLocalNotifications(userInfo: Object) {
RCTPushNotificationManager.cancelLocalNotifications(userInfo);
}
/**
* Gets the local notifications that are currently scheduled.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getscheduledlocalnotifications
*/
static getScheduledLocalNotifications(callback: Function) {
RCTPushNotificationManager.getScheduledLocalNotifications(callback);
}
2015-03-26 16:28:03 +00:00
/**
* Attaches a listener to remote or local notification events while the app
* is running in the foreground or the background.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#addeventlistener
2015-03-26 16:28:03 +00:00
*/
static addEventListener(type: PushNotificationEventName, handler: Function) {
2015-03-26 16:28:03 +00:00
invariant(
type === 'notification' ||
type === 'register' ||
type === 'registrationError' ||
type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
);
let listener;
if (type === 'notification') {
listener = PushNotificationEmitter.addListener(
DEVICE_NOTIF_EVENT,
notifData => {
handler(new PushNotificationIOS(notifData));
},
);
} else if (type === 'localNotification') {
listener = PushNotificationEmitter.addListener(
DEVICE_LOCAL_NOTIF_EVENT,
notifData => {
handler(new PushNotificationIOS(notifData));
},
);
} else if (type === 'register') {
listener = PushNotificationEmitter.addListener(
NOTIF_REGISTER_EVENT,
registrationInfo => {
handler(registrationInfo.deviceToken);
},
);
} else if (type === 'registrationError') {
listener = PushNotificationEmitter.addListener(
NOTIF_REGISTRATION_ERROR_EVENT,
errorInfo => {
handler(errorInfo);
},
);
}
_notifHandlers.set(type, listener);
}
/**
* Removes the event listener. Do this in `componentWillUnmount` to prevent
* memory leaks.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#removeeventlistener
*/
static removeEventListener(
type: PushNotificationEventName,
handler: Function,
) {
invariant(
type === 'notification' ||
type === 'register' ||
type === 'registrationError' ||
type === 'localNotification',
'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
);
const listener = _notifHandlers.get(type);
if (!listener) {
return;
}
listener.remove();
_notifHandlers.delete(type);
}
2015-03-26 16:28:03 +00:00
/**
* Requests notification permissions from iOS, prompting the user's
* dialog box. By default, it will request all notification permissions, but
* a subset of these can be requested by passing a map of requested
* permissions.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#requestpermissions
2015-03-26 16:28:03 +00:00
*/
static requestPermissions(permissions?: {
alert?: boolean,
badge?: boolean,
sound?: boolean,
}): Promise<{
alert: boolean,
badge: boolean,
sound: boolean,
}> {
let requestedPermissions = {};
if (permissions) {
requestedPermissions = {
alert: !!permissions.alert,
badge: !!permissions.badge,
sound: !!permissions.sound,
};
} else {
requestedPermissions = {
alert: true,
badge: true,
sound: true,
};
}
return RCTPushNotificationManager.requestPermissions(requestedPermissions);
}
/**
* Unregister for all remote notifications received via Apple Push Notification service.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#abandonpermissions
*/
static abandonPermissions() {
RCTPushNotificationManager.abandonPermissions();
}
2015-03-26 16:28:03 +00:00
/**
* See what push permissions are currently enabled. `callback` will be
* invoked with a `permissions` object.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#checkpermissions
2015-03-26 16:28:03 +00:00
*/
static checkPermissions(callback: Function) {
invariant(typeof callback === 'function', 'Must provide a valid callback');
RCTPushNotificationManager.checkPermissions(callback);
}
/**
* This method returns a promise that resolves to either the notification
* object if the app was launched by a push notification, or `null` otherwise.
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getinitialnotification
*/
static getInitialNotification(): Promise<?PushNotificationIOS> {
return RCTPushNotificationManager.getInitialNotification().then(
notification => {
return notification && new PushNotificationIOS(notification);
},
);
}
2015-03-26 16:28:03 +00:00
/**
* You will never need to instantiate `PushNotificationIOS` yourself.
2015-03-26 16:28:03 +00:00
* Listening to the `notification` event and invoking
* `getInitialNotification` is sufficient
*
2015-03-26 16:28:03 +00:00
*/
constructor(nativeNotif: Object) {
this._data = {};
this._remoteNotificationCompleteCallbackCalled = false;
this._isRemote = nativeNotif.remote;
if (this._isRemote) {
this._notificationId = nativeNotif.notificationId;
}
if (nativeNotif.remote) {
// Extract data from Apple's `aps` dict as defined:
// https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
Object.keys(nativeNotif).forEach(notifKey => {
const notifVal = nativeNotif[notifKey];
if (notifKey === 'aps') {
this._alert = notifVal.alert;
this._sound = notifVal.sound;
this._badgeCount = notifVal.badge;
this._category = notifVal.category;
Expose content-available APS key for iOS silent push Summary: <details> Thanks for submitting a PR! Please read these instructions carefully: - [ ] Explain the **motivation** for making this change. - [ ] Provide a **test plan** demonstrating that the code is solid. - [ ] Match the **code formatting** of the rest of the codebase. - [ ] Target the `master` branch, NOT a "stable" branch. Please read the [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to learn more about contributing to React Native. </details> _What existing problem does the pull request solve? In iOS when sending a silent push notification you need to configure the 'content-available' APS key to the value of 1 (When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate, see [apple docs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)). This PR exposes this property to the notification event handler so app code can handle silent push scenario specifically. Currently this property is not available. I've updated the PushNotificationIOSExample in the RNTester. 1. Open RNTester in xcode 2. Enable the push notifications capability 3. run on device 4. Go to PushNotificationIOS 5. click on "send fake notification" 6. verify alert message contains 'content-available' with a value of 1. Closes https://github.com/facebook/react-native/pull/14584 Differential Revision: D5279181 Pulled By: shergin fbshipit-source-id: d2288e147d89ba267f54265d819aa0a9969095e7
2017-06-19 23:37:31 +00:00
this._contentAvailable = notifVal['content-available'];
this._threadID = notifVal['thread-id'];
} else {
this._data[notifKey] = notifVal;
}
});
} else {
// Local notifications aren't being sent down with `aps` dict.
this._badgeCount = nativeNotif.applicationIconBadgeNumber;
this._sound = nativeNotif.soundName;
this._alert = nativeNotif.alertBody;
this._data = nativeNotif.userInfo;
this._category = nativeNotif.category;
}
}
/**
* This method is available for remote notifications that have been received via:
* `application:didReceiveRemoteNotification:fetchCompletionHandler:`
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#finish
*/
finish(fetchResult: string) {
if (
!this._isRemote ||
!this._notificationId ||
this._remoteNotificationCompleteCallbackCalled
) {
return;
}
this._remoteNotificationCompleteCallbackCalled = true;
RCTPushNotificationManager.onFinishRemoteNotification(
this._notificationId,
fetchResult,
);
}
2015-03-26 16:28:03 +00:00
/**
* An alias for `getAlert` to get the notification's main message string
*/
getMessage(): ?string | ?Object {
// alias because "alert" is an ambiguous name
return this._alert;
}
2015-03-26 16:28:03 +00:00
/**
* Gets the sound string from the `aps` object
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getsound
2015-03-26 16:28:03 +00:00
*/
getSound(): ?string {
return this._sound;
}
/**
* Gets the category string from the `aps` object
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getcategory
*/
getCategory(): ?string {
return this._category;
}
2015-03-26 16:28:03 +00:00
/**
* Gets the notification's main message from the `aps` object
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getalert
2015-03-26 16:28:03 +00:00
*/
getAlert(): ?string | ?Object {
return this._alert;
}
Expose content-available APS key for iOS silent push Summary: <details> Thanks for submitting a PR! Please read these instructions carefully: - [ ] Explain the **motivation** for making this change. - [ ] Provide a **test plan** demonstrating that the code is solid. - [ ] Match the **code formatting** of the rest of the codebase. - [ ] Target the `master` branch, NOT a "stable" branch. Please read the [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to learn more about contributing to React Native. </details> _What existing problem does the pull request solve? In iOS when sending a silent push notification you need to configure the 'content-available' APS key to the value of 1 (When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate, see [apple docs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)). This PR exposes this property to the notification event handler so app code can handle silent push scenario specifically. Currently this property is not available. I've updated the PushNotificationIOSExample in the RNTester. 1. Open RNTester in xcode 2. Enable the push notifications capability 3. run on device 4. Go to PushNotificationIOS 5. click on "send fake notification" 6. verify alert message contains 'content-available' with a value of 1. Closes https://github.com/facebook/react-native/pull/14584 Differential Revision: D5279181 Pulled By: shergin fbshipit-source-id: d2288e147d89ba267f54265d819aa0a9969095e7
2017-06-19 23:37:31 +00:00
/**
* Gets the content-available number from the `aps` object
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getcontentavailable
Expose content-available APS key for iOS silent push Summary: <details> Thanks for submitting a PR! Please read these instructions carefully: - [ ] Explain the **motivation** for making this change. - [ ] Provide a **test plan** demonstrating that the code is solid. - [ ] Match the **code formatting** of the rest of the codebase. - [ ] Target the `master` branch, NOT a "stable" branch. Please read the [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md) to learn more about contributing to React Native. </details> _What existing problem does the pull request solve? In iOS when sending a silent push notification you need to configure the 'content-available' APS key to the value of 1 (When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate, see [apple docs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1)). This PR exposes this property to the notification event handler so app code can handle silent push scenario specifically. Currently this property is not available. I've updated the PushNotificationIOSExample in the RNTester. 1. Open RNTester in xcode 2. Enable the push notifications capability 3. run on device 4. Go to PushNotificationIOS 5. click on "send fake notification" 6. verify alert message contains 'content-available' with a value of 1. Closes https://github.com/facebook/react-native/pull/14584 Differential Revision: D5279181 Pulled By: shergin fbshipit-source-id: d2288e147d89ba267f54265d819aa0a9969095e7
2017-06-19 23:37:31 +00:00
*/
getContentAvailable(): ContentAvailable {
return this._contentAvailable;
}
2015-03-26 16:28:03 +00:00
/**
* Gets the badge count number from the `aps` object
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getbadgecount
2015-03-26 16:28:03 +00:00
*/
getBadgeCount(): ?number {
return this._badgeCount;
}
2015-03-26 16:28:03 +00:00
/**
* Gets the data object on the notif
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getdata
2015-03-26 16:28:03 +00:00
*/
getData(): ?Object {
return this._data;
}
/**
* Gets the thread ID on the notif
*
* See https://facebook.github.io/react-native/docs/pushnotificationios.html#getthreadid
*/
getThreadID(): ?string {
return this._threadID;
}
}
module.exports = PushNotificationIOS;