1 |
|
2 |
|
3 | import {
|
4 | EventEmitter,
|
5 | EventSubscription,
|
6 | } from 'fbemitter';
|
7 |
|
8 | import invariant from 'invariant';
|
9 |
|
10 | import {
|
11 | DeviceEventEmitter,
|
12 | NativeModules,
|
13 | Platform,
|
14 | } from 'react-native';
|
15 |
|
16 | const {
|
17 | ExponentNotifications,
|
18 | } = NativeModules;
|
19 |
|
20 | type Notification = {
|
21 | origin: 'selected' | 'received';
|
22 | data: any;
|
23 | remote: boolean;
|
24 | isMultiple: boolean;
|
25 | }
|
26 |
|
27 | type LocalNotification = {
|
28 | title: string;
|
29 |
|
30 | body?: string;
|
31 | data?: any;
|
32 | ios?: {
|
33 | sound?: boolean;
|
34 | };
|
35 | android?: {
|
36 | sound?: boolean;
|
37 | icon?: string;
|
38 | color?: string;
|
39 | priority?: string;
|
40 | sticky?: boolean;
|
41 | vibrate?: boolean | Array<number>;
|
42 | link?: string;
|
43 | };
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 | type LocalNotificationId = string | number;
|
49 |
|
50 | let _emitter;
|
51 | let _initialNotification;
|
52 |
|
53 | function _maybeInitEmitter() {
|
54 | if (!_emitter) {
|
55 | _emitter = new EventEmitter();
|
56 | DeviceEventEmitter.addListener('Exponent.notification', _emitNotification);
|
57 | }
|
58 | }
|
59 |
|
60 | function _emitNotification(notification) {
|
61 | if (typeof notification === 'string') {
|
62 | notification = JSON.parse(notification);
|
63 | }
|
64 |
|
65 |
|
66 | notification = { ...notification };
|
67 |
|
68 | if (typeof notification.data === 'string') {
|
69 | try {
|
70 | notification.data = JSON.parse(notification.data);
|
71 | } catch(e) {
|
72 |
|
73 | }
|
74 | }
|
75 |
|
76 | _emitter.emit('notification', notification);
|
77 | }
|
78 |
|
79 | function _processNotification(notification) {
|
80 | notification = Object.assign({}, notification);
|
81 |
|
82 | if (!notification.data) {
|
83 | notification.data = {};
|
84 | }
|
85 |
|
86 | if (notification.hasOwnProperty('count')) {
|
87 | delete notification.count;
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 | if (Platform.OS === 'ios') {
|
93 | if (notification.android) {
|
94 | delete notification.android;
|
95 | }
|
96 |
|
97 | if (notification.ios) {
|
98 | notification = Object.assign(notification, notification.ios);
|
99 | delete notification.ios;
|
100 | }
|
101 | }
|
102 |
|
103 |
|
104 |
|
105 | if (Platform.OS === 'android') {
|
106 | if (notification.ios) {
|
107 | delete notification.ios;
|
108 | }
|
109 |
|
110 | if (notification.android) {
|
111 | notification = Object.assign(notification, notification.android);
|
112 | delete notification.android;
|
113 | }
|
114 | }
|
115 |
|
116 | return notification;
|
117 | }
|
118 |
|
119 | function _validateNotification(notification) {
|
120 | if (Platform.OS === 'ios') {
|
121 | invariant(
|
122 | !!notification.title && !!notification.body,
|
123 | 'Local notifications on iOS require both a title and a body'
|
124 | );
|
125 | } else if (Platform.OS === 'android') {
|
126 | invariant(
|
127 | !!notification.title,
|
128 | 'Local notifications on Android require a title'
|
129 | );
|
130 | }
|
131 | }
|
132 |
|
133 | export default {
|
134 |
|
135 | _setInitialNotification(notification: Notification) {
|
136 | _initialNotification = notification;
|
137 | },
|
138 |
|
139 |
|
140 | getExponentPushTokenAsync: ExponentNotifications.getExponentPushTokenAsync,
|
141 |
|
142 |
|
143 | presentLocalNotificationAsync(notification: LocalNotification): Promise<LocalNotificationId> {
|
144 | _validateNotification(notification);
|
145 | notification = _processNotification(notification);
|
146 |
|
147 | return ExponentNotifications.presentLocalNotification(notification);
|
148 | },
|
149 |
|
150 |
|
151 | async scheduleLocalNotificationAsync(
|
152 | notification: LocalNotification,
|
153 | options: {
|
154 | time?: Date | number;
|
155 | repeat?: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
|
156 | }
|
157 | ): Promise<LocalNotificationId> {
|
158 | _validateNotification(notification);
|
159 | notification = _processNotification(notification);
|
160 |
|
161 | if (Platform.OS === 'ios') {
|
162 | if (options.time && options.time instanceof Date) {
|
163 | options = {
|
164 | ...options,
|
165 | time: options.time.getTime(),
|
166 | };
|
167 | }
|
168 | } else {
|
169 | if (options.time && typeof options.time === 'number') {
|
170 | options = {
|
171 | ...options,
|
172 | time: new Date(options.time),
|
173 | };
|
174 | }
|
175 | }
|
176 |
|
177 | return ExponentNotifications.scheduleLocalNotification(notification, options);
|
178 | },
|
179 |
|
180 |
|
181 | async dismissNotificationAsync(notificationId: LocalNotificationId): Promise<void> {
|
182 | if (Platform.OS === 'android') {
|
183 | return ExponentNotifications.dismissNotification(notificationId);
|
184 | } else {
|
185 | return Promise.reject('Dismissing notifications is not supported on iOS');
|
186 | }
|
187 | },
|
188 |
|
189 |
|
190 | async dismissAllNotificationsAsync(): Promise<void> {
|
191 | if (Platform.OS === 'android') {
|
192 | return ExponentNotifications.dismissAllNotifications();
|
193 | } else {
|
194 | return Promise.reject('Dismissing notifications is not supported on iOS');
|
195 | }
|
196 | },
|
197 |
|
198 |
|
199 | async cancelScheduledNotificationAsync(notificationId: LocalNotificationId): Promise<void> {
|
200 | return ExponentNotifications.cancelScheduledNotification(notificationId);
|
201 | },
|
202 |
|
203 |
|
204 | async cancelAllScheduledNotificationsAsync(): Promise<void> {
|
205 | return ExponentNotifications.cancelAllScheduledNotifications();
|
206 | },
|
207 |
|
208 |
|
209 | addListener(listener: Function): EventSubscription {
|
210 | _maybeInitEmitter();
|
211 |
|
212 | if (_initialNotification) {
|
213 | const initialNotification = _initialNotification;
|
214 | _initialNotification = null;
|
215 | setTimeout(() => {
|
216 | _emitNotification(initialNotification);
|
217 | }, 0);
|
218 | }
|
219 |
|
220 | return _emitter.addListener('notification', listener);
|
221 | },
|
222 |
|
223 | async getBadgeNumberAsync(): Promise<number> {
|
224 | if (!ExponentNotifications.getBadgeNumberAsync) {
|
225 | return 0;
|
226 | }
|
227 | return ExponentNotifications.getBadgeNumberAsync();
|
228 | },
|
229 |
|
230 | async setBadgeNumberAsync(number: number): Promise<void> {
|
231 | if (!ExponentNotifications.setBadgeNumberAsync) {
|
232 | return;
|
233 | }
|
234 | return ExponentNotifications.setBadgeNumberAsync(number);
|
235 | },
|
236 | };
|