expo-notifications 0.28.17 → 0.28.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/notifications/notifications/emitting/NotificationsEmitter.kt +5 -0
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +1 -1
- package/build/NotificationsEmitter.d.ts +11 -1
- package/build/NotificationsEmitter.d.ts.map +1 -1
- package/build/NotificationsEmitter.js +31 -2
- package/build/NotificationsEmitter.js.map +1 -1
- package/build/useLastNotificationResponse.d.ts.map +1 -1
- package/build/useLastNotificationResponse.js +5 -1
- package/build/useLastNotificationResponse.js.map +1 -1
- package/ios/EXNotifications/Notifications/Emitter/EXNotificationsEmitter.h +1 -0
- package/ios/EXNotifications/Notifications/Emitter/EXNotificationsEmitter.m +8 -1
- package/package.json +2 -2
- package/src/NotificationsEmitter.ts +33 -2
- package/src/useLastNotificationResponse.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.28.18 — 2024-10-01
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- Add clearLastNotificationResponseAsync to API. ([#31607](https://github.com/expo/expo/pull/31607) by [@douglowder](https://github.com/douglowder))
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug fixes
|
|
20
|
+
|
|
21
|
+
- [android] fix notifications actions not being presented ([#31795](https://github.com/expo/expo/pull/31795) by [@vonovak](https://github.com/vonovak))
|
|
22
|
+
|
|
13
23
|
## 0.28.17 — 2024-09-17
|
|
14
24
|
|
|
15
25
|
### 🐛 Bug fixes
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'host.exp.exponent'
|
|
4
|
-
version = '0.28.
|
|
4
|
+
version = '0.28.18'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -14,7 +14,7 @@ android {
|
|
|
14
14
|
namespace "expo.modules.notifications"
|
|
15
15
|
defaultConfig {
|
|
16
16
|
versionCode 21
|
|
17
|
-
versionName '0.28.
|
|
17
|
+
versionName '0.28.18'
|
|
18
18
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -41,6 +41,11 @@ open class NotificationsEmitter : Module(), NotificationListener {
|
|
|
41
41
|
AsyncFunction<Bundle?>("getLastNotificationResponseAsync") {
|
|
42
42
|
lastNotificationResponseBundle
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
AsyncFunction("clearLastNotificationResponseAsync") {
|
|
46
|
+
lastNotificationResponseBundle = null
|
|
47
|
+
null
|
|
48
|
+
}
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
/**
|
|
@@ -24,7 +24,7 @@ import kotlin.math.min
|
|
|
24
24
|
*/
|
|
25
25
|
open class ExpoNotificationBuilder(context: Context?) : ChannelAwareNotificationBuilder(context) {
|
|
26
26
|
override suspend fun build(): Notification {
|
|
27
|
-
val builder =
|
|
27
|
+
val builder = createBuilder()
|
|
28
28
|
builder.setSmallIcon(icon)
|
|
29
29
|
builder.setPriority(priority)
|
|
30
30
|
|
|
@@ -69,7 +69,17 @@ export declare function addNotificationResponseReceivedListener(listener: (event
|
|
|
69
69
|
*/
|
|
70
70
|
export declare function removeNotificationSubscription(subscription: Subscription): void;
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
72
|
+
* Gets the notification response that was received most recently
|
|
73
|
+
* (a notification response designates an interaction with a notification, such as tapping on it).
|
|
74
|
+
*
|
|
75
|
+
* - `null` - if no notification response has been received yet
|
|
76
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received
|
|
77
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received.
|
|
73
78
|
*/
|
|
74
79
|
export declare function getLastNotificationResponseAsync(): Promise<NotificationResponse | null>;
|
|
80
|
+
export declare function clearLastNotificationResponseAsync(): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* @hidden
|
|
83
|
+
*/
|
|
84
|
+
export declare function addNotificationResponseClearedListener(listener: () => void): Subscription;
|
|
75
85
|
//# sourceMappingURL=NotificationsEmitter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsEmitter.d.ts","sourceRoot":"","sources":["../src/NotificationsEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEpF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"NotificationsEmitter.d.ts","sourceRoot":"","sources":["../src/NotificationsEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEpF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAa3E,eAAO,MAAM,yBAAyB,+CAA+C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACtC,YAAY,CAQd;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,YAAY,CAElF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAC9C,YAAY,CAQd;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,YAAY,QAExE;AAED;;;;;;;GAOG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAO7F;AAYD,wBAAsB,kCAAkC,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxE;AAED;;GAEG;AACH,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,YAAY,CAEzF"}
|
|
@@ -6,6 +6,7 @@ const emitter = new EventEmitter(NotificationsEmitterModule);
|
|
|
6
6
|
const didReceiveNotificationEventName = 'onDidReceiveNotification';
|
|
7
7
|
const didDropNotificationsEventName = 'onNotificationsDeleted';
|
|
8
8
|
const didReceiveNotificationResponseEventName = 'onDidReceiveNotificationResponse';
|
|
9
|
+
const didClearNotificationResponseEventName = 'onDidClearNotificationResponse';
|
|
9
10
|
// @docsMissing
|
|
10
11
|
export const DEFAULT_ACTION_IDENTIFIER = 'expo.modules.notifications.actions.DEFAULT';
|
|
11
12
|
/**
|
|
@@ -89,9 +90,13 @@ export function addNotificationResponseReceivedListener(listener) {
|
|
|
89
90
|
export function removeNotificationSubscription(subscription) {
|
|
90
91
|
emitter.removeSubscription(subscription);
|
|
91
92
|
}
|
|
92
|
-
// @docsMissing
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
94
|
+
* Gets the notification response that was received most recently
|
|
95
|
+
* (a notification response designates an interaction with a notification, such as tapping on it).
|
|
96
|
+
*
|
|
97
|
+
* - `null` - if no notification response has been received yet
|
|
98
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received
|
|
99
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received.
|
|
95
100
|
*/
|
|
96
101
|
export async function getLastNotificationResponseAsync() {
|
|
97
102
|
if (!NotificationsEmitterModule.getLastNotificationResponseAsync) {
|
|
@@ -101,4 +106,28 @@ export async function getLastNotificationResponseAsync() {
|
|
|
101
106
|
const mappedResponse = response ? mapNotificationResponse(response) : response;
|
|
102
107
|
return mappedResponse;
|
|
103
108
|
}
|
|
109
|
+
/* Clears the notification response that was received most recently. May be used
|
|
110
|
+
* when an app selects a route based on the notification response, and it is undesirable
|
|
111
|
+
* to continue selecting the route after the response has already been handled.
|
|
112
|
+
* to continue to select the route after the response has already been handled.
|
|
113
|
+
*
|
|
114
|
+
* If a component is using the [`useLastNotificationResponse`](#useLastNotificationResponse) hook,
|
|
115
|
+
* this call will also clear the value returned by the hook.
|
|
116
|
+
*
|
|
117
|
+
* @return A promise that resolves if the native call was successful.
|
|
118
|
+
*/
|
|
119
|
+
export async function clearLastNotificationResponseAsync() {
|
|
120
|
+
if (!NotificationsEmitterModule.clearLastNotificationResponseAsync) {
|
|
121
|
+
throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');
|
|
122
|
+
}
|
|
123
|
+
await NotificationsEmitterModule.clearLastNotificationResponseAsync();
|
|
124
|
+
// Emit event to clear any useLastNotificationResponse hooks, after native call succeeds
|
|
125
|
+
emitter.emit(didClearNotificationResponseEventName, []);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* @hidden
|
|
129
|
+
*/
|
|
130
|
+
export function addNotificationResponseClearedListener(listener) {
|
|
131
|
+
return emitter.addListener(didClearNotificationResponseEventName, listener);
|
|
132
|
+
}
|
|
104
133
|
//# sourceMappingURL=NotificationsEmitter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsEmitter.js","sourceRoot":"","sources":["../src/NotificationsEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,0BAA0B,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE3F,iCAAiC;AACjC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,0BAA0B,CAAC,CAAC;AAE7D,MAAM,+BAA+B,GAAG,0BAA0B,CAAC;AACnE,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AAC/D,MAAM,uCAAuC,GAAG,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"NotificationsEmitter.js","sourceRoot":"","sources":["../src/NotificationsEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,0BAA0B,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE3F,iCAAiC;AACjC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,0BAA0B,CAAC,CAAC;AAE7D,MAAM,+BAA+B,GAAG,0BAA0B,CAAC;AACnE,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AAC/D,MAAM,uCAAuC,GAAG,kCAAkC,CAAC;AACnF,MAAM,qCAAqC,GAAG,gCAAgC,CAAC;AAE/E,eAAe;AACf,MAAM,CAAC,MAAM,yBAAyB,GAAG,4CAA4C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAuC;IAEvC,OAAO,OAAO,CAAC,WAAW,CACxB,+BAA+B,EAC/B,CAAC,YAA0B,EAAE,EAAE;QAC7B,MAAM,kBAAkB,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;QACzD,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC/B,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,QAAoB;IAClE,OAAO,OAAO,CAAC,WAAW,CAAO,6BAA6B,EAAE,QAAQ,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,uCAAuC,CACrD,QAA+C;IAE/C,OAAO,OAAO,CAAC,WAAW,CACxB,uCAAuC,EACvC,CAAC,QAA8B,EAAE,EAAE;QACjC,MAAM,cAAc,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACzD,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC3B,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,YAA0B;IACvE,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC;IACpD,IAAI,CAAC,0BAA0B,CAAC,gCAAgC,EAAE;QAChE,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,EAAE,kCAAkC,CAAC,CAAC;KACxF;IACD,MAAM,QAAQ,GAAG,MAAM,0BAA0B,CAAC,gCAAgC,EAAE,CAAC;IACrF,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/E,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kCAAkC;IACtD,IAAI,CAAC,0BAA0B,CAAC,kCAAkC,EAAE;QAClE,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,EAAE,kCAAkC,CAAC,CAAC;KACxF;IACD,MAAM,0BAA0B,CAAC,kCAAkC,EAAE,CAAC;IACtE,wFAAwF;IACxF,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sCAAsC,CAAC,QAAoB;IACzE,OAAO,OAAO,CAAC,WAAW,CAAO,qCAAqC,EAAE,QAAQ,CAAC,CAAC;AACpF,CAAC","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';\n\nimport { Notification, NotificationResponse } from './Notifications.types';\nimport NotificationsEmitterModule from './NotificationsEmitterModule';\nimport { mapNotification, mapNotificationResponse } from './utils/mapNotificationResponse';\n\n// Web uses SyntheticEventEmitter\nconst emitter = new EventEmitter(NotificationsEmitterModule);\n\nconst didReceiveNotificationEventName = 'onDidReceiveNotification';\nconst didDropNotificationsEventName = 'onNotificationsDeleted';\nconst didReceiveNotificationResponseEventName = 'onDidReceiveNotificationResponse';\nconst didClearNotificationResponseEventName = 'onDidClearNotificationResponse';\n\n// @docsMissing\nexport const DEFAULT_ACTION_IDENTIFIER = 'expo.modules.notifications.actions.DEFAULT';\n\n/**\n * Listeners registered by this method will be called whenever a notification is received while the app is running.\n * @param listener A function accepting a notification ([`Notification`](#notification)) as an argument.\n * @return A [`Subscription`](#subscription) object represents the subscription of the provided listener.\n * @example Registering a notification listener using a React hook:\n * ```jsx\n * import React from 'react';\n * import * as Notifications from 'expo-notifications';\n *\n * export default function App() {\n * React.useEffect(() => {\n * const subscription = Notifications.addNotificationReceivedListener(notification => {\n * console.log(notification);\n * });\n * return () => subscription.remove();\n * }, []);\n *\n * return (\n * // Your app content\n * );\n * }\n * ```\n * @header listen\n */\nexport function addNotificationReceivedListener(\n listener: (event: Notification) => void\n): Subscription {\n return emitter.addListener<Notification>(\n didReceiveNotificationEventName,\n (notification: Notification) => {\n const mappedNotification = mapNotification(notification);\n listener(mappedNotification);\n }\n );\n}\n\n/**\n * Listeners registered by this method will be called whenever some notifications have been dropped by the server.\n * Applicable only to Firebase Cloud Messaging which we use as a notifications service on Android. It corresponds to `onDeletedMessages()` callback.\n * More information can be found in [Firebase docs](https://firebase.google.com/docs/cloud-messaging/android/receive#override-ondeletedmessages).\n * @param listener A callback function.\n * @return A [`Subscription`](#subscription) object represents the subscription of the provided listener.\n * @header listen\n */\nexport function addNotificationsDroppedListener(listener: () => void): Subscription {\n return emitter.addListener<void>(didDropNotificationsEventName, listener);\n}\n\n/**\n * Listeners registered by this method will be called whenever a user interacts with a notification (for example, taps on it).\n * @param listener A function accepting notification response ([`NotificationResponse`](#notificationresponse)) as an argument.\n * @return A [`Subscription`](#subscription) object represents the subscription of the provided listener.\n * @example Register a notification responder listener:\n * ```jsx\n * import React from 'react';\n * import { Linking } from 'react-native';\n * import * as Notifications from 'expo-notifications';\n *\n * export default function Container() {\n * React.useEffect(() => {\n * const subscription = Notifications.addNotificationResponseReceivedListener(response => {\n * const url = response.notification.request.content.data.url;\n * Linking.openURL(url);\n * });\n * return () => subscription.remove();\n * }, []);\n *\n * return (\n * // Your app content\n * );\n * }\n * ```\n * @header listen\n */\nexport function addNotificationResponseReceivedListener(\n listener: (event: NotificationResponse) => void\n): Subscription {\n return emitter.addListener<NotificationResponse>(\n didReceiveNotificationResponseEventName,\n (response: NotificationResponse) => {\n const mappedResponse = mapNotificationResponse(response);\n listener(mappedResponse);\n }\n );\n}\n\n/**\n * Removes a notification subscription returned by an `addNotificationListener` call.\n * @param subscription A subscription returned by `addNotificationListener` method.\n * @header listen\n */\nexport function removeNotificationSubscription(subscription: Subscription) {\n emitter.removeSubscription(subscription);\n}\n\n/**\n * Gets the notification response that was received most recently\n * (a notification response designates an interaction with a notification, such as tapping on it).\n *\n * - `null` - if no notification response has been received yet\n * - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received\n * - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received.\n */\nexport async function getLastNotificationResponseAsync(): Promise<NotificationResponse | null> {\n if (!NotificationsEmitterModule.getLastNotificationResponseAsync) {\n throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');\n }\n const response = await NotificationsEmitterModule.getLastNotificationResponseAsync();\n const mappedResponse = response ? mapNotificationResponse(response) : response;\n return mappedResponse;\n}\n\n/* Clears the notification response that was received most recently. May be used\n * when an app selects a route based on the notification response, and it is undesirable\n * to continue selecting the route after the response has already been handled.\n * to continue to select the route after the response has already been handled.\n *\n * If a component is using the [`useLastNotificationResponse`](#useLastNotificationResponse) hook,\n * this call will also clear the value returned by the hook.\n *\n * @return A promise that resolves if the native call was successful.\n */\nexport async function clearLastNotificationResponseAsync(): Promise<void> {\n if (!NotificationsEmitterModule.clearLastNotificationResponseAsync) {\n throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');\n }\n await NotificationsEmitterModule.clearLastNotificationResponseAsync();\n // Emit event to clear any useLastNotificationResponse hooks, after native call succeeds\n emitter.emit(didClearNotificationResponseEventName, []);\n}\n\n/**\n * @hidden\n */\nexport function addNotificationResponseClearedListener(listener: () => void): Subscription {\n return emitter.addListener<void>(didClearNotificationResponseEventName, listener);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLastNotificationResponse.d.ts","sourceRoot":"","sources":["../src/useLastNotificationResponse.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"useLastNotificationResponse.d.ts","sourceRoot":"","sources":["../src/useLastNotificationResponse.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAO7D,KAAK,yBAAyB,GAAG,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B,8BA8ClD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useLayoutEffect, useState } from 'react';
|
|
2
|
-
import { addNotificationResponseReceivedListener, getLastNotificationResponseAsync, } from './NotificationsEmitter';
|
|
2
|
+
import { addNotificationResponseReceivedListener, addNotificationResponseClearedListener, getLastNotificationResponseAsync, } from './NotificationsEmitter';
|
|
3
3
|
/**
|
|
4
4
|
* A React hook always returns the notification response that was received most recently
|
|
5
5
|
* (a notification response designates an interaction with a notification, such as tapping on it).
|
|
@@ -61,8 +61,12 @@ export default function useLastNotificationResponse() {
|
|
|
61
61
|
getLastNotificationResponseAsync?.().then((response) => setLastNotificationResponse((prevResponse) => newResponseIfNeeded(prevResponse, response)));
|
|
62
62
|
// Set up listener for responses that come in, and set the last response if needed
|
|
63
63
|
const subscription = addNotificationResponseReceivedListener((response) => setLastNotificationResponse((prevResponse) => newResponseIfNeeded(prevResponse, response)));
|
|
64
|
+
const clearResponseSubscription = addNotificationResponseClearedListener(() => {
|
|
65
|
+
setLastNotificationResponse(undefined);
|
|
66
|
+
});
|
|
64
67
|
return () => {
|
|
65
68
|
subscription.remove();
|
|
69
|
+
clearResponseSubscription.remove();
|
|
66
70
|
};
|
|
67
71
|
}, []);
|
|
68
72
|
return lastNotificationResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLastNotificationResponse.js","sourceRoot":"","sources":["../src/useLastNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGlD,OAAO,EACL,uCAAuC,EACvC,gCAAgC,GACjC,MAAM,wBAAwB,CAAC;AAIhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B;IACjD,MAAM,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,GAC3D,QAAQ,CAA4B,SAAS,CAAC,CAAC;IAEjD,oFAAoF;IACpF,yCAAyC;IACzC,MAAM,mBAAmB,GAAG,CAC1B,YAAuC,EACvC,WAAsC,EACtC,EAAE;QACF,+DAA+D;QAC/D,IAAI,CAAC,WAAW,EAAE;YAChB,OAAO,YAAY,CAAC;SACrB;QACD,8FAA8F;QAC9F,IAAI,CAAC,YAAY,EAAE;YACjB,OAAO,WAAW,CAAC;SACpB;QACD,OAAO,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU;YACjD,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU;YAC3C,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,YAAY,CAAC;IACnB,CAAC,CAAC;IAEF,yEAAyE;IACzE,eAAe,CAAC,GAAG,EAAE;QACnB,2FAA2F;QAC3F,sBAAsB;QACtB,gCAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CACrD,2BAA2B,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAC3F,CAAC;QAEF,kFAAkF;QAClF,MAAM,YAAY,GAAG,uCAAuC,CAAC,CAAC,QAAQ,EAAE,EAAE,CACxE,2BAA2B,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAC3F,CAAC;QACF,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"useLastNotificationResponse.js","sourceRoot":"","sources":["../src/useLastNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGlD,OAAO,EACL,uCAAuC,EACvC,sCAAsC,EACtC,gCAAgC,GACjC,MAAM,wBAAwB,CAAC;AAIhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B;IACjD,MAAM,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,GAC3D,QAAQ,CAA4B,SAAS,CAAC,CAAC;IAEjD,oFAAoF;IACpF,yCAAyC;IACzC,MAAM,mBAAmB,GAAG,CAC1B,YAAuC,EACvC,WAAsC,EACtC,EAAE;QACF,+DAA+D;QAC/D,IAAI,CAAC,WAAW,EAAE;YAChB,OAAO,YAAY,CAAC;SACrB;QACD,8FAA8F;QAC9F,IAAI,CAAC,YAAY,EAAE;YACjB,OAAO,WAAW,CAAC;SACpB;QACD,OAAO,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU;YACjD,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU;YAC3C,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,YAAY,CAAC;IACnB,CAAC,CAAC;IAEF,yEAAyE;IACzE,eAAe,CAAC,GAAG,EAAE;QACnB,2FAA2F;QAC3F,sBAAsB;QACtB,gCAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CACrD,2BAA2B,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAC3F,CAAC;QAEF,kFAAkF;QAClF,MAAM,YAAY,GAAG,uCAAuC,CAAC,CAAC,QAAQ,EAAE,EAAE,CACxE,2BAA2B,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAC3F,CAAC;QACF,MAAM,yBAAyB,GAAG,sCAAsC,CAAC,GAAG,EAAE;YAC5E,2BAA2B,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,MAAM,EAAE,CAAC;YACtB,yBAAyB,CAAC,MAAM,EAAE,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,wBAAwB,CAAC;AAClC,CAAC","sourcesContent":["import { useLayoutEffect, useState } from 'react';\n\nimport { NotificationResponse } from './Notifications.types';\nimport {\n addNotificationResponseReceivedListener,\n addNotificationResponseClearedListener,\n getLastNotificationResponseAsync,\n} from './NotificationsEmitter';\n\ntype MaybeNotificationResponse = NotificationResponse | null | undefined;\n\n/**\n * A React hook always returns the notification response that was received most recently\n * (a notification response designates an interaction with a notification, such as tapping on it).\n *\n * > If you don't want to use a hook, you can use `Notifications.getLastNotificationResponseAsync()` instead.\n *\n * @return The hook may return one of these three types/values:\n * - `undefined` - until we're sure of what to return,\n * - `null` - if no notification response has been received yet,\n * - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received.\n *\n * @example\n * Responding to a notification tap by opening a URL that could be put into the notification's `data`\n * (opening the URL is your responsibility and is not a part of the `expo-notifications` API):\n * ```jsx\n * import * as Notifications from 'expo-notifications';\n * import { Linking } from 'react-native';\n *\n * export default function App() {\n * const lastNotificationResponse = Notifications.useLastNotificationResponse();\n * React.useEffect(() => {\n * if (\n * lastNotificationResponse &&\n * lastNotificationResponse.notification.request.content.data.url &&\n * lastNotificationResponse.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER\n * ) {\n * Linking.openURL(lastNotificationResponse.notification.request.content.data.url);\n * }\n * }, [lastNotificationResponse]);\n * return (\n * // Your app content\n * );\n * }\n * ```\n * @header listen\n */\nexport default function useLastNotificationResponse() {\n const [lastNotificationResponse, setLastNotificationResponse] =\n useState<MaybeNotificationResponse>(undefined);\n\n // Pure function that returns the new response if it is different from the previous,\n // otherwise return the previous response\n const newResponseIfNeeded = (\n prevResponse: MaybeNotificationResponse,\n newResponse: MaybeNotificationResponse\n ) => {\n // If the new response is undefined or null, no need for update\n if (!newResponse) {\n return prevResponse;\n }\n // If the previous response is undefined or null and the new response is not, we should update\n if (!prevResponse) {\n return newResponse;\n }\n return prevResponse.notification.request.identifier !==\n newResponse.notification.request.identifier\n ? newResponse\n : prevResponse;\n };\n\n // useLayoutEffect ensures the listener is registered as soon as possible\n useLayoutEffect(() => {\n // Get the last response first, in case it was set earlier (even in native code on startup)\n // before this renders\n getLastNotificationResponseAsync?.().then((response) =>\n setLastNotificationResponse((prevResponse) => newResponseIfNeeded(prevResponse, response))\n );\n\n // Set up listener for responses that come in, and set the last response if needed\n const subscription = addNotificationResponseReceivedListener((response) =>\n setLastNotificationResponse((prevResponse) => newResponseIfNeeded(prevResponse, response))\n );\n const clearResponseSubscription = addNotificationResponseClearedListener(() => {\n setLastNotificationResponse(undefined);\n });\n return () => {\n subscription.remove();\n clearResponseSubscription.remove();\n };\n }, []);\n\n return lastNotificationResponse;\n}\n"]}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
static NSString * const onDidReceiveNotification = @"onDidReceiveNotification";
|
|
11
11
|
static NSString * const onDidReceiveNotificationResponse = @"onDidReceiveNotificationResponse";
|
|
12
|
+
static NSString * const onDidClearNotificationResponse = @"onDidClearNotificationResponse";
|
|
12
13
|
|
|
13
14
|
@interface EXNotificationsEmitter : EXExportedModule <EXEventEmitter, EXModuleRegistryConsumer, EXNotificationsDelegate>
|
|
14
15
|
|
|
@@ -28,6 +28,13 @@ EX_EXPORT_METHOD_AS(getLastNotificationResponseAsync,
|
|
|
28
28
|
resolve(lastResponse ? [self serializedNotificationResponse:lastResponse] : [NSNull null]);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
EX_EXPORT_METHOD_AS(clearLastNotificationResponseAsync,
|
|
32
|
+
clearLastNotificationResponseAsyncWithResolver:(EXPromiseResolveBlock)resolve reject:(EXPromiseRejectBlock)reject)
|
|
33
|
+
{
|
|
34
|
+
_notificationCenterDelegate.lastNotificationResponse = nil;
|
|
35
|
+
resolve([NSNull null]);
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
# pragma mark - EXModuleRegistryConsumer
|
|
32
39
|
|
|
33
40
|
- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
|
|
@@ -40,7 +47,7 @@ EX_EXPORT_METHOD_AS(getLastNotificationResponseAsync,
|
|
|
40
47
|
|
|
41
48
|
- (NSArray<NSString *> *)supportedEvents
|
|
42
49
|
{
|
|
43
|
-
return @[onDidReceiveNotification, onDidReceiveNotificationResponse];
|
|
50
|
+
return @[onDidReceiveNotification, onDidReceiveNotificationResponse, onDidClearNotificationResponse];
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
- (void)startObserving
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-notifications",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.18",
|
|
4
4
|
"description": "Notifications module",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"expo": "*"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "04e325d4fc3b8a7ff20ac21f74dcf92da6294b40"
|
|
59
59
|
}
|
|
@@ -10,6 +10,7 @@ const emitter = new EventEmitter(NotificationsEmitterModule);
|
|
|
10
10
|
const didReceiveNotificationEventName = 'onDidReceiveNotification';
|
|
11
11
|
const didDropNotificationsEventName = 'onNotificationsDeleted';
|
|
12
12
|
const didReceiveNotificationResponseEventName = 'onDidReceiveNotificationResponse';
|
|
13
|
+
const didClearNotificationResponseEventName = 'onDidClearNotificationResponse';
|
|
13
14
|
|
|
14
15
|
// @docsMissing
|
|
15
16
|
export const DEFAULT_ACTION_IDENTIFIER = 'expo.modules.notifications.actions.DEFAULT';
|
|
@@ -109,9 +110,13 @@ export function removeNotificationSubscription(subscription: Subscription) {
|
|
|
109
110
|
emitter.removeSubscription(subscription);
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
// @docsMissing
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
114
|
+
* Gets the notification response that was received most recently
|
|
115
|
+
* (a notification response designates an interaction with a notification, such as tapping on it).
|
|
116
|
+
*
|
|
117
|
+
* - `null` - if no notification response has been received yet
|
|
118
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received
|
|
119
|
+
* - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received.
|
|
115
120
|
*/
|
|
116
121
|
export async function getLastNotificationResponseAsync(): Promise<NotificationResponse | null> {
|
|
117
122
|
if (!NotificationsEmitterModule.getLastNotificationResponseAsync) {
|
|
@@ -121,3 +126,29 @@ export async function getLastNotificationResponseAsync(): Promise<NotificationRe
|
|
|
121
126
|
const mappedResponse = response ? mapNotificationResponse(response) : response;
|
|
122
127
|
return mappedResponse;
|
|
123
128
|
}
|
|
129
|
+
|
|
130
|
+
/* Clears the notification response that was received most recently. May be used
|
|
131
|
+
* when an app selects a route based on the notification response, and it is undesirable
|
|
132
|
+
* to continue selecting the route after the response has already been handled.
|
|
133
|
+
* to continue to select the route after the response has already been handled.
|
|
134
|
+
*
|
|
135
|
+
* If a component is using the [`useLastNotificationResponse`](#useLastNotificationResponse) hook,
|
|
136
|
+
* this call will also clear the value returned by the hook.
|
|
137
|
+
*
|
|
138
|
+
* @return A promise that resolves if the native call was successful.
|
|
139
|
+
*/
|
|
140
|
+
export async function clearLastNotificationResponseAsync(): Promise<void> {
|
|
141
|
+
if (!NotificationsEmitterModule.clearLastNotificationResponseAsync) {
|
|
142
|
+
throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');
|
|
143
|
+
}
|
|
144
|
+
await NotificationsEmitterModule.clearLastNotificationResponseAsync();
|
|
145
|
+
// Emit event to clear any useLastNotificationResponse hooks, after native call succeeds
|
|
146
|
+
emitter.emit(didClearNotificationResponseEventName, []);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @hidden
|
|
151
|
+
*/
|
|
152
|
+
export function addNotificationResponseClearedListener(listener: () => void): Subscription {
|
|
153
|
+
return emitter.addListener<void>(didClearNotificationResponseEventName, listener);
|
|
154
|
+
}
|
|
@@ -3,6 +3,7 @@ import { useLayoutEffect, useState } from 'react';
|
|
|
3
3
|
import { NotificationResponse } from './Notifications.types';
|
|
4
4
|
import {
|
|
5
5
|
addNotificationResponseReceivedListener,
|
|
6
|
+
addNotificationResponseClearedListener,
|
|
6
7
|
getLastNotificationResponseAsync,
|
|
7
8
|
} from './NotificationsEmitter';
|
|
8
9
|
|
|
@@ -80,8 +81,12 @@ export default function useLastNotificationResponse() {
|
|
|
80
81
|
const subscription = addNotificationResponseReceivedListener((response) =>
|
|
81
82
|
setLastNotificationResponse((prevResponse) => newResponseIfNeeded(prevResponse, response))
|
|
82
83
|
);
|
|
84
|
+
const clearResponseSubscription = addNotificationResponseClearedListener(() => {
|
|
85
|
+
setLastNotificationResponse(undefined);
|
|
86
|
+
});
|
|
83
87
|
return () => {
|
|
84
88
|
subscription.remove();
|
|
89
|
+
clearResponseSubscription.remove();
|
|
85
90
|
};
|
|
86
91
|
}, []);
|
|
87
92
|
|