PushNotificationIOS.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. */
  10. 'use strict';
  11. const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
  12. import NativePushNotificationManagerIOS from './NativePushNotificationManagerIOS';
  13. const invariant = require('invariant');
  14. const PushNotificationEmitter = new NativeEventEmitter(
  15. NativePushNotificationManagerIOS,
  16. );
  17. const _notifHandlers = new Map();
  18. const DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
  19. const NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
  20. const NOTIF_REGISTRATION_ERROR_EVENT = 'remoteNotificationRegistrationError';
  21. const DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
  22. export type ContentAvailable = 1 | null | void;
  23. export type FetchResult = {
  24. NewData: string,
  25. NoData: string,
  26. ResultFailed: string,
  27. ...
  28. };
  29. /**
  30. * An event emitted by PushNotificationIOS.
  31. */
  32. export type PushNotificationEventName = $Keys<{
  33. /**
  34. * Fired when a remote notification is received. The handler will be invoked
  35. * with an instance of `PushNotificationIOS`.
  36. */
  37. notification: string,
  38. /**
  39. * Fired when a local notification is received. The handler will be invoked
  40. * with an instance of `PushNotificationIOS`.
  41. */
  42. localNotification: string,
  43. /**
  44. * Fired when the user registers for remote notifications. The handler will be
  45. * invoked with a hex string representing the deviceToken.
  46. */
  47. register: string,
  48. /**
  49. * Fired when the user fails to register for remote notifications. Typically
  50. * occurs when APNS is having issues, or the device is a simulator. The
  51. * handler will be invoked with {message: string, code: number, details: any}.
  52. */
  53. registrationError: string,
  54. ...
  55. }>;
  56. /**
  57. *
  58. * Handle push notifications for your app, including permission handling and
  59. * icon badge number.
  60. *
  61. * See https://reactnative.dev/docs/pushnotificationios.html
  62. */
  63. class PushNotificationIOS {
  64. _data: Object;
  65. _alert: string | Object;
  66. _sound: string;
  67. _category: string;
  68. _contentAvailable: ContentAvailable;
  69. _badgeCount: number;
  70. _notificationId: string;
  71. _isRemote: boolean;
  72. _remoteNotificationCompleteCallbackCalled: boolean;
  73. _threadID: string;
  74. static FetchResult: FetchResult = {
  75. NewData: 'UIBackgroundFetchResultNewData',
  76. NoData: 'UIBackgroundFetchResultNoData',
  77. ResultFailed: 'UIBackgroundFetchResultFailed',
  78. };
  79. /**
  80. * Schedules the localNotification for immediate presentation.
  81. *
  82. * See https://reactnative.dev/docs/pushnotificationios.html#presentlocalnotification
  83. */
  84. static presentLocalNotification(details: Object) {
  85. invariant(
  86. NativePushNotificationManagerIOS,
  87. 'PushNotificationManager is not available.',
  88. );
  89. NativePushNotificationManagerIOS.presentLocalNotification(details);
  90. }
  91. /**
  92. * Schedules the localNotification for future presentation.
  93. *
  94. * See https://reactnative.dev/docs/pushnotificationios.html#schedulelocalnotification
  95. */
  96. static scheduleLocalNotification(details: Object) {
  97. invariant(
  98. NativePushNotificationManagerIOS,
  99. 'PushNotificationManager is not available.',
  100. );
  101. NativePushNotificationManagerIOS.scheduleLocalNotification(details);
  102. }
  103. /**
  104. * Cancels all scheduled localNotifications.
  105. *
  106. * See https://reactnative.dev/docs/pushnotificationios.html#cancelalllocalnotifications
  107. */
  108. static cancelAllLocalNotifications() {
  109. invariant(
  110. NativePushNotificationManagerIOS,
  111. 'PushNotificationManager is not available.',
  112. );
  113. NativePushNotificationManagerIOS.cancelAllLocalNotifications();
  114. }
  115. /**
  116. * Remove all delivered notifications from Notification Center.
  117. *
  118. * See https://reactnative.dev/docs/pushnotificationios.html#removealldeliverednotifications
  119. */
  120. static removeAllDeliveredNotifications(): void {
  121. invariant(
  122. NativePushNotificationManagerIOS,
  123. 'PushNotificationManager is not available.',
  124. );
  125. NativePushNotificationManagerIOS.removeAllDeliveredNotifications();
  126. }
  127. /**
  128. * Provides you with a list of the app’s notifications that are still displayed in Notification Center.
  129. *
  130. * See https://reactnative.dev/docs/pushnotificationios.html#getdeliverednotifications
  131. */
  132. static getDeliveredNotifications(
  133. callback: (notifications: Array<Object>) => void,
  134. ): void {
  135. invariant(
  136. NativePushNotificationManagerIOS,
  137. 'PushNotificationManager is not available.',
  138. );
  139. NativePushNotificationManagerIOS.getDeliveredNotifications(callback);
  140. }
  141. /**
  142. * Removes the specified notifications from Notification Center
  143. *
  144. * See https://reactnative.dev/docs/pushnotificationios.html#removedeliverednotifications
  145. */
  146. static removeDeliveredNotifications(identifiers: Array<string>): void {
  147. invariant(
  148. NativePushNotificationManagerIOS,
  149. 'PushNotificationManager is not available.',
  150. );
  151. NativePushNotificationManagerIOS.removeDeliveredNotifications(identifiers);
  152. }
  153. /**
  154. * Sets the badge number for the app icon on the home screen.
  155. *
  156. * See https://reactnative.dev/docs/pushnotificationios.html#setapplicationiconbadgenumber
  157. */
  158. static setApplicationIconBadgeNumber(number: number) {
  159. invariant(
  160. NativePushNotificationManagerIOS,
  161. 'PushNotificationManager is not available.',
  162. );
  163. NativePushNotificationManagerIOS.setApplicationIconBadgeNumber(number);
  164. }
  165. /**
  166. * Gets the current badge number for the app icon on the home screen.
  167. *
  168. * See https://reactnative.dev/docs/pushnotificationios.html#getapplicationiconbadgenumber
  169. */
  170. static getApplicationIconBadgeNumber(callback: Function) {
  171. invariant(
  172. NativePushNotificationManagerIOS,
  173. 'PushNotificationManager is not available.',
  174. );
  175. NativePushNotificationManagerIOS.getApplicationIconBadgeNumber(callback);
  176. }
  177. /**
  178. * Cancel local notifications.
  179. *
  180. * See https://reactnative.dev/docs/pushnotificationios.html#cancellocalnotification
  181. */
  182. static cancelLocalNotifications(userInfo: Object) {
  183. invariant(
  184. NativePushNotificationManagerIOS,
  185. 'PushNotificationManager is not available.',
  186. );
  187. NativePushNotificationManagerIOS.cancelLocalNotifications(userInfo);
  188. }
  189. /**
  190. * Gets the local notifications that are currently scheduled.
  191. *
  192. * See https://reactnative.dev/docs/pushnotificationios.html#getscheduledlocalnotifications
  193. */
  194. static getScheduledLocalNotifications(callback: Function) {
  195. invariant(
  196. NativePushNotificationManagerIOS,
  197. 'PushNotificationManager is not available.',
  198. );
  199. NativePushNotificationManagerIOS.getScheduledLocalNotifications(callback);
  200. }
  201. /**
  202. * Attaches a listener to remote or local notification events while the app
  203. * is running in the foreground or the background.
  204. *
  205. * See https://reactnative.dev/docs/pushnotificationios.html#addeventlistener
  206. */
  207. static addEventListener(type: PushNotificationEventName, handler: Function) {
  208. invariant(
  209. type === 'notification' ||
  210. type === 'register' ||
  211. type === 'registrationError' ||
  212. type === 'localNotification',
  213. 'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
  214. );
  215. let listener;
  216. if (type === 'notification') {
  217. listener = PushNotificationEmitter.addListener(
  218. DEVICE_NOTIF_EVENT,
  219. notifData => {
  220. handler(new PushNotificationIOS(notifData));
  221. },
  222. );
  223. } else if (type === 'localNotification') {
  224. listener = PushNotificationEmitter.addListener(
  225. DEVICE_LOCAL_NOTIF_EVENT,
  226. notifData => {
  227. handler(new PushNotificationIOS(notifData));
  228. },
  229. );
  230. } else if (type === 'register') {
  231. listener = PushNotificationEmitter.addListener(
  232. NOTIF_REGISTER_EVENT,
  233. registrationInfo => {
  234. handler(registrationInfo.deviceToken);
  235. },
  236. );
  237. } else if (type === 'registrationError') {
  238. listener = PushNotificationEmitter.addListener(
  239. NOTIF_REGISTRATION_ERROR_EVENT,
  240. errorInfo => {
  241. handler(errorInfo);
  242. },
  243. );
  244. }
  245. _notifHandlers.set(type, listener);
  246. }
  247. /**
  248. * Removes the event listener. Do this in `componentWillUnmount` to prevent
  249. * memory leaks.
  250. *
  251. * See https://reactnative.dev/docs/pushnotificationios.html#removeeventlistener
  252. */
  253. static removeEventListener(
  254. type: PushNotificationEventName,
  255. handler: Function,
  256. ) {
  257. invariant(
  258. type === 'notification' ||
  259. type === 'register' ||
  260. type === 'registrationError' ||
  261. type === 'localNotification',
  262. 'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events',
  263. );
  264. const listener = _notifHandlers.get(type);
  265. if (!listener) {
  266. return;
  267. }
  268. listener.remove();
  269. _notifHandlers.delete(type);
  270. }
  271. /**
  272. * Requests notification permissions from iOS, prompting the user's
  273. * dialog box. By default, it will request all notification permissions, but
  274. * a subset of these can be requested by passing a map of requested
  275. * permissions.
  276. *
  277. * See https://reactnative.dev/docs/pushnotificationios.html#requestpermissions
  278. */
  279. static requestPermissions(permissions?: {
  280. alert?: boolean,
  281. badge?: boolean,
  282. sound?: boolean,
  283. ...
  284. }): Promise<{
  285. alert: boolean,
  286. badge: boolean,
  287. sound: boolean,
  288. ...
  289. }> {
  290. let requestedPermissions = {
  291. alert: true,
  292. badge: true,
  293. sound: true,
  294. };
  295. if (permissions) {
  296. requestedPermissions = {
  297. alert: !!permissions.alert,
  298. badge: !!permissions.badge,
  299. sound: !!permissions.sound,
  300. };
  301. }
  302. invariant(
  303. NativePushNotificationManagerIOS,
  304. 'PushNotificationManager is not available.',
  305. );
  306. return NativePushNotificationManagerIOS.requestPermissions(
  307. requestedPermissions,
  308. );
  309. }
  310. /**
  311. * Unregister for all remote notifications received via Apple Push Notification service.
  312. *
  313. * See https://reactnative.dev/docs/pushnotificationios.html#abandonpermissions
  314. */
  315. static abandonPermissions() {
  316. invariant(
  317. NativePushNotificationManagerIOS,
  318. 'PushNotificationManager is not available.',
  319. );
  320. NativePushNotificationManagerIOS.abandonPermissions();
  321. }
  322. /**
  323. * See what push permissions are currently enabled. `callback` will be
  324. * invoked with a `permissions` object.
  325. *
  326. * See https://reactnative.dev/docs/pushnotificationios.html#checkpermissions
  327. */
  328. static checkPermissions(callback: Function) {
  329. invariant(typeof callback === 'function', 'Must provide a valid callback');
  330. invariant(
  331. NativePushNotificationManagerIOS,
  332. 'PushNotificationManager is not available.',
  333. );
  334. NativePushNotificationManagerIOS.checkPermissions(callback);
  335. }
  336. /**
  337. * This method returns a promise that resolves to either the notification
  338. * object if the app was launched by a push notification, or `null` otherwise.
  339. *
  340. * See https://reactnative.dev/docs/pushnotificationios.html#getinitialnotification
  341. */
  342. static getInitialNotification(): Promise<?PushNotificationIOS> {
  343. invariant(
  344. NativePushNotificationManagerIOS,
  345. 'PushNotificationManager is not available.',
  346. );
  347. return NativePushNotificationManagerIOS.getInitialNotification().then(
  348. notification => {
  349. return notification && new PushNotificationIOS(notification);
  350. },
  351. );
  352. }
  353. /**
  354. * You will never need to instantiate `PushNotificationIOS` yourself.
  355. * Listening to the `notification` event and invoking
  356. * `getInitialNotification` is sufficient
  357. *
  358. */
  359. constructor(nativeNotif: Object) {
  360. this._data = {};
  361. this._remoteNotificationCompleteCallbackCalled = false;
  362. this._isRemote = nativeNotif.remote;
  363. if (this._isRemote) {
  364. this._notificationId = nativeNotif.notificationId;
  365. }
  366. if (nativeNotif.remote) {
  367. // Extract data from Apple's `aps` dict as defined:
  368. // https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
  369. Object.keys(nativeNotif).forEach(notifKey => {
  370. const notifVal = nativeNotif[notifKey];
  371. if (notifKey === 'aps') {
  372. this._alert = notifVal.alert;
  373. this._sound = notifVal.sound;
  374. this._badgeCount = notifVal.badge;
  375. this._category = notifVal.category;
  376. this._contentAvailable = notifVal['content-available'];
  377. this._threadID = notifVal['thread-id'];
  378. } else {
  379. this._data[notifKey] = notifVal;
  380. }
  381. });
  382. } else {
  383. // Local notifications aren't being sent down with `aps` dict.
  384. this._badgeCount = nativeNotif.applicationIconBadgeNumber;
  385. this._sound = nativeNotif.soundName;
  386. this._alert = nativeNotif.alertBody;
  387. this._data = nativeNotif.userInfo;
  388. this._category = nativeNotif.category;
  389. }
  390. }
  391. /**
  392. * This method is available for remote notifications that have been received via:
  393. * `application:didReceiveRemoteNotification:fetchCompletionHandler:`
  394. *
  395. * See https://reactnative.dev/docs/pushnotificationios.html#finish
  396. */
  397. finish(fetchResult: string) {
  398. if (
  399. !this._isRemote ||
  400. !this._notificationId ||
  401. this._remoteNotificationCompleteCallbackCalled
  402. ) {
  403. return;
  404. }
  405. this._remoteNotificationCompleteCallbackCalled = true;
  406. invariant(
  407. NativePushNotificationManagerIOS,
  408. 'PushNotificationManager is not available.',
  409. );
  410. NativePushNotificationManagerIOS.onFinishRemoteNotification(
  411. this._notificationId,
  412. fetchResult,
  413. );
  414. }
  415. /**
  416. * An alias for `getAlert` to get the notification's main message string
  417. */
  418. getMessage(): ?string | ?Object {
  419. // alias because "alert" is an ambiguous name
  420. return this._alert;
  421. }
  422. /**
  423. * Gets the sound string from the `aps` object
  424. *
  425. * See https://reactnative.dev/docs/pushnotificationios.html#getsound
  426. */
  427. getSound(): ?string {
  428. return this._sound;
  429. }
  430. /**
  431. * Gets the category string from the `aps` object
  432. *
  433. * See https://reactnative.dev/docs/pushnotificationios.html#getcategory
  434. */
  435. getCategory(): ?string {
  436. return this._category;
  437. }
  438. /**
  439. * Gets the notification's main message from the `aps` object
  440. *
  441. * See https://reactnative.dev/docs/pushnotificationios.html#getalert
  442. */
  443. getAlert(): ?string | ?Object {
  444. return this._alert;
  445. }
  446. /**
  447. * Gets the content-available number from the `aps` object
  448. *
  449. * See https://reactnative.dev/docs/pushnotificationios.html#getcontentavailable
  450. */
  451. getContentAvailable(): ContentAvailable {
  452. return this._contentAvailable;
  453. }
  454. /**
  455. * Gets the badge count number from the `aps` object
  456. *
  457. * See https://reactnative.dev/docs/pushnotificationios.html#getbadgecount
  458. */
  459. getBadgeCount(): ?number {
  460. return this._badgeCount;
  461. }
  462. /**
  463. * Gets the data object on the notif
  464. *
  465. * See https://reactnative.dev/docs/pushnotificationios.html#getdata
  466. */
  467. getData(): ?Object {
  468. return this._data;
  469. }
  470. /**
  471. * Gets the thread ID on the notif
  472. *
  473. * See https://reactnative.dev/docs/pushnotificationios.html#getthreadid
  474. */
  475. getThreadID(): ?string {
  476. return this._threadID;
  477. }
  478. }
  479. module.exports = PushNotificationIOS;