expo-notifications 0.28.1 → 0.28.2

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 CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.28.2 — 2024-05-15
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [Android] fix response handling when app in background or not running. ([#28883](https://github.com/expo/expo/pull/28883) by [@douglowder](https://github.com/douglowder))
18
+
13
19
  ## 0.28.1 — 2024-04-23
14
20
 
15
21
  _This version does not introduce any user-facing changes._
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'host.exp.exponent'
4
- version = '0.28.1'
4
+ version = '0.28.2'
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.1'
17
+ versionName '0.28.2'
18
18
  }
19
19
 
20
20
  buildFeatures {
@@ -3,22 +3,32 @@ package expo.modules.notifications;
3
3
  import android.content.Context;
4
4
 
5
5
  import java.util.Arrays;
6
+ import java.util.Collections;
6
7
  import java.util.List;
7
8
 
8
9
  import expo.modules.core.BasePackage;
9
10
  import expo.modules.core.interfaces.InternalModule;
11
+ import expo.modules.core.interfaces.ReactActivityLifecycleListener;
10
12
  import expo.modules.core.interfaces.SingletonModule;
11
13
  import expo.modules.notifications.notifications.NotificationManager;
12
14
  import expo.modules.notifications.notifications.categories.serializers.ExpoNotificationsCategoriesSerializer;
13
15
  import expo.modules.notifications.notifications.channels.AndroidXNotificationsChannelsProvider;
16
+ import expo.modules.notifications.service.delegates.ExpoNotificationLifecycleListener;
14
17
  import expo.modules.notifications.tokens.PushTokenManager;
15
18
 
16
19
  public class NotificationsPackage extends BasePackage {
20
+
21
+ private NotificationManager mNotificationManager;
22
+
23
+ public NotificationsPackage() {
24
+ mNotificationManager = new NotificationManager();
25
+ }
26
+
17
27
  @Override
18
28
  public List<SingletonModule> createSingletonModules(Context context) {
19
29
  return Arrays.asList(
20
30
  new PushTokenManager(),
21
- new NotificationManager()
31
+ mNotificationManager
22
32
  );
23
33
  }
24
34
 
@@ -29,4 +39,10 @@ public class NotificationsPackage extends BasePackage {
29
39
  new ExpoNotificationsCategoriesSerializer()
30
40
  );
31
41
  }
42
+
43
+ @Override
44
+ public List<ReactActivityLifecycleListener> createReactActivityLifecycleListeners(Context activityContext) {
45
+ return Collections.singletonList(new ExpoNotificationLifecycleListener(activityContext, mNotificationManager));
46
+ }
32
47
  }
48
+
@@ -1,5 +1,8 @@
1
1
  package expo.modules.notifications.notifications;
2
2
 
3
+ import android.os.Bundle;
4
+ import android.util.Log;
5
+
3
6
  import expo.modules.core.interfaces.SingletonModule;
4
7
 
5
8
  import java.lang.ref.WeakReference;
@@ -22,6 +25,7 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
22
25
  */
23
26
  private WeakHashMap<NotificationListener, WeakReference<NotificationListener>> mListenerReferenceMap;
24
27
  private Collection<NotificationResponse> mPendingNotificationResponses = new ArrayList<>();
28
+ private Collection<Bundle> mPendingNotificationResponsesFromExtras = new ArrayList<>();
25
29
 
26
30
  public NotificationManager() {
27
31
  mListenerReferenceMap = new WeakHashMap<>();
@@ -53,6 +57,11 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
53
57
  listener.onNotificationResponseReceived(pendingResponse);
54
58
  }
55
59
  }
60
+ if (!mPendingNotificationResponsesFromExtras.isEmpty()) {
61
+ for (Bundle extras : mPendingNotificationResponsesFromExtras) {
62
+ listener.onNotificationResponseIntentReceived(extras);
63
+ }
64
+ }
56
65
  }
57
66
  }
58
67
 
@@ -116,4 +125,17 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
116
125
  }
117
126
  }
118
127
  }
128
+
129
+ public void onNotificationResponseFromExtras(Bundle extras) {
130
+ if (mPendingNotificationResponsesFromExtras.isEmpty()) {
131
+ mPendingNotificationResponsesFromExtras.add(extras);
132
+ } else {
133
+ for (WeakReference<NotificationListener> listenerReference : mListenerReferenceMap.values()) {
134
+ NotificationListener listener = listenerReference.get();
135
+ if (listener != null) {
136
+ listener.onNotificationResponseIntentReceived(extras);
137
+ }
138
+ }
139
+ }
140
+ }
119
141
  }
@@ -3,9 +3,9 @@ package expo.modules.notifications.notifications;
3
3
  import android.os.Build;
4
4
  import android.os.Bundle;
5
5
 
6
- import androidx.annotation.NonNull;
7
6
  import androidx.annotation.Nullable;
8
7
 
8
+ import org.jetbrains.annotations.NotNull;
9
9
  import org.json.JSONArray;
10
10
  import org.json.JSONObject;
11
11
  import expo.modules.core.arguments.MapArguments;
@@ -19,16 +19,12 @@ import java.util.Set;
19
19
 
20
20
  import expo.modules.notifications.notifications.interfaces.NotificationTrigger;
21
21
  import expo.modules.notifications.notifications.model.Notification;
22
- import expo.modules.notifications.notifications.model.NotificationAction;
23
- import expo.modules.notifications.notifications.model.NotificationCategory;
24
22
  import expo.modules.notifications.notifications.model.NotificationContent;
25
23
  import expo.modules.notifications.notifications.model.NotificationRequest;
26
24
  import expo.modules.notifications.notifications.model.NotificationResponse;
27
- import expo.modules.notifications.notifications.model.TextInputNotificationAction;
28
25
  import expo.modules.notifications.notifications.model.TextInputNotificationResponse;
29
26
  import expo.modules.notifications.notifications.model.triggers.FirebaseNotificationTrigger;
30
27
 
31
- import expo.modules.notifications.notifications.triggers.ChannelAwareTrigger;
32
28
  import expo.modules.notifications.notifications.triggers.DailyTrigger;
33
29
  import expo.modules.notifications.notifications.triggers.DateTrigger;
34
30
  import expo.modules.notifications.notifications.triggers.TimeIntervalTrigger;
@@ -199,4 +195,31 @@ public class NotificationSerializer {
199
195
  }
200
196
  return null;
201
197
  }
198
+
199
+ @NotNull
200
+ public static Bundle toResponseBundleFromExtras(Bundle extras) {
201
+ Bundle serializedContent = new Bundle();
202
+ serializedContent.putString("title", extras.getString("title"));
203
+ serializedContent.putString("body", extras.getString("message"));
204
+ serializedContent.putString("dataString", extras.getString("body"));
205
+
206
+ Bundle serializedTrigger = new Bundle();
207
+ serializedTrigger.putString("type", "push");
208
+ serializedTrigger.putString("channelId", extras.getString("channelId"));
209
+
210
+ Bundle serializedRequest = new Bundle();
211
+ serializedRequest.putString("identifier", extras.getString("google.message_id"));
212
+ serializedRequest.putBundle("trigger", serializedTrigger);
213
+ serializedRequest.putBundle("content", serializedContent);
214
+
215
+ Bundle serializedNotification = new Bundle();
216
+ serializedNotification.putLong("date", extras.getLong("google.sent_time"));
217
+ serializedNotification.putBundle("request", serializedRequest);
218
+
219
+ Bundle serializedResponse = new Bundle();
220
+ serializedResponse.putString("actionIdentifier", "expo.modules.notifications.actions.DEFAULT");
221
+ serializedResponse.putBundle("notification", serializedNotification);
222
+
223
+ return serializedResponse;
224
+ }
202
225
  }
@@ -1,7 +1,6 @@
1
1
  package expo.modules.notifications.notifications.emitting
2
2
 
3
3
  import android.os.Bundle
4
- import expo.modules.core.interfaces.services.EventEmitter
5
4
  import expo.modules.kotlin.modules.Module
6
5
  import expo.modules.kotlin.modules.ModuleDefinition
7
6
  import expo.modules.notifications.notifications.NotificationSerializer
@@ -16,8 +15,7 @@ private const val MESSAGES_DELETED_EVENT_NAME = "onNotificationsDeleted"
16
15
 
17
16
  open class NotificationsEmitter : Module(), NotificationListener {
18
17
  private lateinit var notificationManager: NotificationManager
19
- private var lastNotificationResponse: NotificationResponse? = null
20
- private var eventEmitter: EventEmitter? = null
18
+ private var lastNotificationResponseBundle: Bundle? = null
21
19
 
22
20
  override fun definition() = ModuleDefinition {
23
21
  Name("ExpoNotificationsEmitter")
@@ -40,7 +38,7 @@ open class NotificationsEmitter : Module(), NotificationListener {
40
38
  }
41
39
 
42
40
  AsyncFunction<Bundle?>("getLastNotificationResponseAsync") {
43
- lastNotificationResponse?.let(NotificationSerializer::toBundle)
41
+ lastNotificationResponseBundle
44
42
  }
45
43
  }
46
44
 
@@ -62,11 +60,16 @@ open class NotificationsEmitter : Module(), NotificationListener {
62
60
  * @return Whether notification has been handled
63
61
  */
64
62
  override fun onNotificationResponseReceived(response: NotificationResponse): Boolean {
65
- lastNotificationResponse = response
66
- sendEvent(NEW_RESPONSE_EVENT_NAME, NotificationSerializer.toBundle(response))
63
+ lastNotificationResponseBundle = NotificationSerializer.toBundle(response)
64
+ sendEvent(NEW_RESPONSE_EVENT_NAME, lastNotificationResponseBundle)
67
65
  return true
68
66
  }
69
67
 
68
+ override fun onNotificationResponseIntentReceived(extras: Bundle?) {
69
+ lastNotificationResponseBundle = NotificationSerializer.toResponseBundleFromExtras(extras)
70
+ sendEvent(NEW_RESPONSE_EVENT_NAME, lastNotificationResponseBundle)
71
+ }
72
+
70
73
  /**
71
74
  * Callback called when [NotificationManager] gets informed of the fact of message dropping.
72
75
  * Emits a [MESSAGES_DELETED_EVENT_NAME] event.
@@ -1,5 +1,7 @@
1
1
  package expo.modules.notifications.notifications.interfaces;
2
2
 
3
+ import android.os.Bundle;
4
+
3
5
  import com.google.firebase.messaging.FirebaseMessagingService;
4
6
 
5
7
  import expo.modules.notifications.notifications.model.Notification;
@@ -28,6 +30,14 @@ public interface NotificationListener {
28
30
  return false;
29
31
  }
30
32
 
33
+ /**
34
+ * Callback called when notification response is received through package lifecycle listeners
35
+ *
36
+ * @param extras Bundle of extras from the lifecycle method
37
+ */
38
+ default void onNotificationResponseIntentReceived(Bundle extras) {
39
+ }
40
+
31
41
  /**
32
42
  * Callback called when some notifications are dropped.
33
43
  * See {@link FirebaseMessagingService#onDeletedMessages()}
@@ -0,0 +1,76 @@
1
+ package expo.modules.notifications.service.delegates;
2
+
3
+ import android.app.Activity;
4
+ import android.app.NotificationChannel;
5
+ import android.app.PendingIntent;
6
+ import android.content.Context;
7
+ import android.content.Intent;
8
+ import android.os.Bundle;
9
+ import android.os.Parcel;
10
+ import android.util.Log;
11
+
12
+ import androidx.core.app.NotificationCompat;
13
+
14
+ import expo.modules.core.interfaces.ReactActivityLifecycleListener;
15
+ import expo.modules.notifications.notifications.NotificationManager;
16
+ import expo.modules.notifications.notifications.model.Notification;
17
+ import expo.modules.notifications.notifications.model.NotificationResponse;
18
+
19
+ public class ExpoNotificationLifecycleListener implements ReactActivityLifecycleListener {
20
+
21
+ private NotificationManager mNotificationManager;
22
+
23
+ public ExpoNotificationLifecycleListener(Context context, NotificationManager notificationManager) {
24
+ mNotificationManager = notificationManager;
25
+ }
26
+
27
+ /**
28
+ * This will be triggered if the app is not running,
29
+ * and is started from clicking on a notification.
30
+ * <p>
31
+ * Notification data will be in activity.intent.extras
32
+ *
33
+ * @param activity
34
+ * @param savedInstanceState
35
+ */
36
+ @Override
37
+ public void onCreate(Activity activity, Bundle savedInstanceState) {
38
+ Intent intent = activity.getIntent();
39
+ String actionIdentifier = intent.getAction();
40
+ if (intent != null) {
41
+ Bundle extras = intent.getExtras();
42
+ if (extras != null) {
43
+ logExtra("onCreate", extras);
44
+ mNotificationManager.onNotificationResponseFromExtras(extras);
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * This will be triggered if the app is running and in the background,
51
+ * and the user clicks on a notification to open the app.
52
+ * <p>
53
+ * Notification data will be in intent.extras
54
+ *
55
+ * @param intent
56
+ * @return
57
+ */
58
+ @Override
59
+ public boolean onNewIntent(Intent intent) {
60
+ Bundle extras = intent.getExtras();
61
+ String actionIdentifier = intent.getAction();
62
+ if (extras != null) {
63
+ logExtra("onNewIntent", extras);
64
+ mNotificationManager.onNotificationResponseFromExtras(extras);
65
+ }
66
+ return ReactActivityLifecycleListener.super.onNewIntent(intent);
67
+ }
68
+
69
+ private void logExtra(String method, Bundle extra) {
70
+ Log.d("ExpoNotificationLifecycleListener", method + " : keys count = " + extra.keySet().size());
71
+
72
+ for (String key : extra.keySet()) {
73
+ Log.d("ExpoNotificationLifecycleListener", method + " : key = " + key + " = " + extra.get(key).toString());
74
+ }
75
+ }
76
+ }
@@ -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;AAW3E,eAAO,MAAM,yBAAyB,+CAA+C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACtC,YAAY,CAEd;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,CAKd;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,YAAY,QAExE;AAGD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAK7F"}
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;AAW3E,eAAO,MAAM,yBAAyB,+CAA+C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACtC,YAAY,CAEd;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,CAoBd;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,YAAY,QAExE;AAGD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAK7F"}
@@ -72,7 +72,21 @@ export function addNotificationsDroppedListener(listener) {
72
72
  * @header listen
73
73
  */
74
74
  export function addNotificationResponseReceivedListener(listener) {
75
- return emitter.addListener(didReceiveNotificationResponseEventName, listener);
75
+ return emitter.addListener(didReceiveNotificationResponseEventName, (response) => {
76
+ const mappedResponse = { ...response };
77
+ try {
78
+ const dataString = mappedResponse?.notification?.request?.content['dataString'];
79
+ if (typeof dataString === 'string') {
80
+ mappedResponse.notification.request.content.data = JSON.parse(dataString);
81
+ delete mappedResponse.notification.request.content.dataString;
82
+ }
83
+ }
84
+ catch (e) {
85
+ console.log(`Error in response: ${e}`);
86
+ }
87
+ console.log(`response received: ${JSON.stringify(mappedResponse, null, 2)}`);
88
+ listener(mappedResponse);
89
+ });
76
90
  }
77
91
  /**
78
92
  * Removes a notification subscription returned by an `addNotificationListener` call.
@@ -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;AAEtE,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;AAEnF,eAAe;AACf,MAAM,CAAC,MAAM,yBAAyB,GAAG,4CAA4C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAuC;IAEvC,OAAO,OAAO,CAAC,WAAW,CAAe,+BAA+B,EAAE,QAAQ,CAAC,CAAC;AACtF,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,QAAQ,CACT,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,YAA0B;IACvE,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED,eAAe;AACf;;GAEG;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,OAAO,MAAM,0BAA0B,CAAC,gCAAgC,EAAE,CAAC;AAC7E,CAAC","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';\n\nimport { Notification, NotificationResponse } from './Notifications.types';\nimport NotificationsEmitterModule from './NotificationsEmitterModule';\n\n// Web uses SyntheticEventEmitter\nconst emitter = new EventEmitter(NotificationsEmitterModule);\n\nconst didReceiveNotificationEventName = 'onDidReceiveNotification';\nconst didDropNotificationsEventName = 'onNotificationsDeleted';\nconst didReceiveNotificationResponseEventName = 'onDidReceiveNotificationResponse';\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>(didReceiveNotificationEventName, listener);\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 listener\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// @docsMissing\n/**\n * @header listen\n */\nexport async function getLastNotificationResponseAsync(): Promise<NotificationResponse | null> {\n if (!NotificationsEmitterModule.getLastNotificationResponseAsync) {\n throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');\n }\n return await NotificationsEmitterModule.getLastNotificationResponseAsync();\n}\n"]}
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;AAEtE,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;AAEnF,eAAe;AACf,MAAM,CAAC,MAAM,yBAAyB,GAAG,4CAA4C,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAuC;IAEvC,OAAO,OAAO,CAAC,WAAW,CAAe,+BAA+B,EAAE,QAAQ,CAAC,CAAC;AACtF,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,GAEhB,EAAE,GAAG,QAAQ,EAAE,CAAC;QACpB,IAAI;YACF,MAAM,UAAU,GAAG,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YAChF,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;gBAClC,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC1E,OAAO,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;aAC/D;SACF;QAAC,OAAO,CAAM,EAAE;YACf,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;SACxC;QACD,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7E,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,eAAe;AACf;;GAEG;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,OAAO,MAAM,0BAA0B,CAAC,gCAAgC,EAAE,CAAC;AAC7E,CAAC","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';\n\nimport { Notification, NotificationResponse } from './Notifications.types';\nimport NotificationsEmitterModule from './NotificationsEmitterModule';\n\n// Web uses SyntheticEventEmitter\nconst emitter = new EventEmitter(NotificationsEmitterModule);\n\nconst didReceiveNotificationEventName = 'onDidReceiveNotification';\nconst didDropNotificationsEventName = 'onNotificationsDeleted';\nconst didReceiveNotificationResponseEventName = 'onDidReceiveNotificationResponse';\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>(didReceiveNotificationEventName, listener);\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: NotificationResponse & {\n notification: { request: { content: { dataString?: string } } };\n } = { ...response };\n try {\n const dataString = mappedResponse?.notification?.request?.content['dataString'];\n if (typeof dataString === 'string') {\n mappedResponse.notification.request.content.data = JSON.parse(dataString);\n delete mappedResponse.notification.request.content.dataString;\n }\n } catch (e: any) {\n console.log(`Error in response: ${e}`);\n }\n console.log(`response received: ${JSON.stringify(mappedResponse, null, 2)}`);\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// @docsMissing\n/**\n * @header listen\n */\nexport async function getLastNotificationResponseAsync(): Promise<NotificationResponse | null> {\n if (!NotificationsEmitterModule.getLastNotificationResponseAsync) {\n throw new UnavailabilityError('ExpoNotifications', 'getLastNotificationResponseAsync');\n }\n return await NotificationsEmitterModule.getLastNotificationResponseAsync();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-notifications",
3
- "version": "0.28.1",
3
+ "version": "0.28.2",
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": "ee4f30ef3b5fa567ad1bf94794197f7683fdd481"
58
+ "gitHead": "82b5a4a7ada98ca26cd99d097400b01240cbcf99"
59
59
  }
@@ -86,7 +86,22 @@ export function addNotificationResponseReceivedListener(
86
86
  ): Subscription {
87
87
  return emitter.addListener<NotificationResponse>(
88
88
  didReceiveNotificationResponseEventName,
89
- listener
89
+ (response: NotificationResponse) => {
90
+ const mappedResponse: NotificationResponse & {
91
+ notification: { request: { content: { dataString?: string } } };
92
+ } = { ...response };
93
+ try {
94
+ const dataString = mappedResponse?.notification?.request?.content['dataString'];
95
+ if (typeof dataString === 'string') {
96
+ mappedResponse.notification.request.content.data = JSON.parse(dataString);
97
+ delete mappedResponse.notification.request.content.dataString;
98
+ }
99
+ } catch (e: any) {
100
+ console.log(`Error in response: ${e}`);
101
+ }
102
+ console.log(`response received: ${JSON.stringify(mappedResponse, null, 2)}`);
103
+ listener(mappedResponse);
104
+ }
90
105
  );
91
106
  }
92
107