expo-notifications 0.28.12 → 0.28.13

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,13 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.28.13 — 2024-07-29
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [Android] map Expo and Firebase notifications correctly. ([#30615](https://github.com/expo/expo/pull/30615) by [@douglowder](https://github.com/douglowder))
18
+ - [Android] Apply requested changes from #30615. ([#30658](https://github.com/expo/expo/pull/30615) by [@lukmccall](https://github.com/lukmccall))
19
+
13
20
  ## 0.28.12 — 2024-07-25
14
21
 
15
22
  ### 🐛 Bug fixes
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'host.exp.exponent'
4
- version = '0.28.12'
4
+ version = '0.28.13'
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.12'
17
+ versionName '0.28.13'
18
18
  }
19
19
 
20
20
  buildFeatures {
@@ -5,8 +5,11 @@ import android.os.Bundle;
5
5
 
6
6
  import androidx.annotation.Nullable;
7
7
 
8
+ import com.google.firebase.messaging.RemoteMessage;
9
+
8
10
  import org.jetbrains.annotations.NotNull;
9
11
  import org.json.JSONArray;
12
+ import org.json.JSONException;
10
13
  import org.json.JSONObject;
11
14
  import expo.modules.core.arguments.MapArguments;
12
15
 
@@ -52,11 +55,37 @@ public class NotificationSerializer {
52
55
  public static Bundle toBundle(NotificationRequest request) {
53
56
  Bundle serializedRequest = new Bundle();
54
57
  serializedRequest.putString("identifier", request.getIdentifier());
55
- serializedRequest.putBundle("content", toBundle(request.getContent()));
56
58
  serializedRequest.putBundle("trigger", toBundle(request.getTrigger()));
59
+ Bundle content = toBundle(request.getContent());
60
+ Bundle existingContentData = content.getBundle("data");
61
+ if (existingContentData == null) {
62
+ FirebaseNotificationTrigger trigger = (FirebaseNotificationTrigger) request.getTrigger();
63
+ RemoteMessage message = trigger.getRemoteMessage();
64
+ RemoteMessage.Notification notification = message.getNotification();
65
+ Map<String, String> data = message.getData();
66
+ String dataBody = data.get("body");
67
+ String notificationBody = notification != null ? notification.getBody() : null;
68
+ if (isValidJSONString(dataBody) && notificationBody != null && notificationBody.equals(data.get("message"))) {
69
+ // Expo sends notification.body as data.message, and JSON stringifies data.body
70
+ content.putString("dataString", dataBody);
71
+ } else {
72
+ // The message was sent directly from Firebase or some other service,
73
+ // and we copy the data as is
74
+ content.putBundle("data", toBundle(data));
75
+ }
76
+ }
77
+ serializedRequest.putBundle("content", content);
57
78
  return serializedRequest;
58
79
  }
59
80
 
81
+ public static Bundle toBundle(Map<String, String> map) {
82
+ Bundle result = new Bundle();
83
+ for (String key: map.keySet()) {
84
+ result.putString(key, map.get(key));
85
+ }
86
+ return result;
87
+ }
88
+
60
89
  public static Bundle toBundle(NotificationContent content) {
61
90
  Bundle serializedContent = new Bundle();
62
91
  serializedContent.putString("title", content.getTitle());
@@ -65,7 +94,7 @@ public class NotificationSerializer {
65
94
  if (content.getColor() != null) {
66
95
  serializedContent.putString("color", String.format("#%08X", content.getColor().intValue()));
67
96
  }
68
- serializedContent.putBundle("data", toBundle(content.getBody()));
97
+
69
98
  if (content.getBadgeCount() != null) {
70
99
  serializedContent.putInt("badge", content.getBadgeCount().intValue());
71
100
  } else {
@@ -192,30 +221,55 @@ public class NotificationSerializer {
192
221
  return null;
193
222
  }
194
223
 
195
- @NotNull
196
- public static Bundle toResponseBundleFromExtras(Bundle extras) {
197
- Bundle serializedContent = new Bundle();
198
- serializedContent.putString("title", extras.getString("title"));
224
+ @NotNull
225
+ public static Bundle toResponseBundleFromExtras(Bundle extras) {
226
+ Bundle serializedContent = new Bundle();
227
+ serializedContent.putString("title", extras.getString("title"));
228
+ String body = extras.getString("body");
229
+ String projectId = extras.getString("projectId");
230
+ if (projectId != null && isValidJSONString(body) ) {
231
+ // If projectId is set in the bundle, and the body is a JSON string,
232
+ // the notification was sent by the Expo notification service,
233
+ // so we do the expected remapping of fields
234
+ serializedContent.putString("dataString", body);
199
235
  serializedContent.putString("body", extras.getString("message"));
200
- serializedContent.putString("dataString", extras.getString("body"));
236
+ } else {
237
+ // The notification came directly from Firebase or some other service,
238
+ // so we copy the data as is from the extras bundle
239
+ serializedContent.putBundle("data", extras);
240
+ }
201
241
 
202
- Bundle serializedTrigger = new Bundle();
203
- serializedTrigger.putString("type", "push");
204
- serializedTrigger.putString("channelId", extras.getString("channelId"));
242
+ Bundle serializedTrigger = new Bundle();
243
+ serializedTrigger.putString("type", "push");
244
+ serializedTrigger.putString("channelId", extras.getString("channelId"));
205
245
 
206
- Bundle serializedRequest = new Bundle();
207
- serializedRequest.putString("identifier", extras.getString("google.message_id"));
208
- serializedRequest.putBundle("trigger", serializedTrigger);
209
- serializedRequest.putBundle("content", serializedContent);
246
+ Bundle serializedRequest = new Bundle();
247
+ serializedRequest.putString("identifier", extras.getString("google.message_id"));
248
+ serializedRequest.putBundle("trigger", serializedTrigger);
249
+ serializedRequest.putBundle("content", serializedContent);
210
250
 
211
- Bundle serializedNotification = new Bundle();
212
- serializedNotification.putLong("date", extras.getLong("google.sent_time"));
213
- serializedNotification.putBundle("request", serializedRequest);
251
+ Bundle serializedNotification = new Bundle();
252
+ serializedNotification.putLong("date", extras.getLong("google.sent_time"));
253
+ serializedNotification.putBundle("request", serializedRequest);
214
254
 
215
- Bundle serializedResponse = new Bundle();
216
- serializedResponse.putString("actionIdentifier", "expo.modules.notifications.actions.DEFAULT");
217
- serializedResponse.putBundle("notification", serializedNotification);
255
+ Bundle serializedResponse = new Bundle();
256
+ serializedResponse.putString("actionIdentifier", "expo.modules.notifications.actions.DEFAULT");
257
+ serializedResponse.putBundle("notification", serializedNotification);
218
258
 
219
- return serializedResponse;
259
+ return serializedResponse;
260
+ }
261
+
262
+ public static boolean isValidJSONString(String test) {
263
+ try {
264
+ new JSONObject(test);
265
+ } catch (JSONException objectEx) {
266
+ try {
267
+ new JSONArray(test);
268
+ } catch (JSONException arrayEx) {
269
+ return false;
270
+ }
220
271
  }
272
+ return true;
273
+ }
274
+
221
275
  }
@@ -0,0 +1,86 @@
1
+ package expo.modules.notifications.notifications.debug
2
+
3
+ import android.os.Build
4
+ import android.os.Bundle
5
+ import android.util.Log
6
+ import androidx.annotation.RequiresApi
7
+ import com.google.firebase.messaging.RemoteMessage
8
+ import expo.modules.notifications.BuildConfig
9
+ import expo.modules.notifications.notifications.model.Notification
10
+ import java.util.function.Consumer
11
+
12
+ object DebugLogging {
13
+ @JvmStatic
14
+ fun logBundle(caller: String, bundleToLog: Bundle) {
15
+ if (!BuildConfig.DEBUG) {
16
+ // Do not log in release/production builds
17
+ return
18
+ }
19
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
20
+ return
21
+ }
22
+ Log.i("expo-notifications", "$caller:\n${bundleString(caller, bundleToLog, 0)}")
23
+ }
24
+
25
+ @RequiresApi(Build.VERSION_CODES.N)
26
+ private fun bundleString(ignoredCaller: String, bundleToLog: Bundle, indent: Int): String {
27
+ return buildString {
28
+ bundleToLog.keySet().forEach(
29
+ Consumer { key: String ->
30
+ val value = bundleToLog[key]
31
+ if (value is Bundle) {
32
+ append("${" ".repeat(indent)}${key}\n")
33
+ append(bundleString(ignoredCaller, value, indent + 2))
34
+ } else {
35
+ val stringValue = value?.toString() ?: "(null)"
36
+ append("${" ".repeat(indent)}$key: $stringValue\n")
37
+ }
38
+ }
39
+ )
40
+ }
41
+ }
42
+
43
+ fun logRemoteMessage(caller: String, message: RemoteMessage) {
44
+ if (!BuildConfig.DEBUG) {
45
+ // Do not log for release/production builds
46
+ return
47
+ }
48
+ val logMessage =
49
+ """
50
+ $caller:
51
+ notification.channelId: ${message.notification?.channelId}
52
+ notification.vibrateTimings: ${message.notification?.vibrateTimings?.contentToString()}
53
+ notification.body: ${message.notification?.body}
54
+ notification.color: ${message.notification?.color}
55
+ notification.sound: ${message.notification?.sound}
56
+ notification.title: ${message.notification?.title}
57
+ notification.collapseKey: ${message.collapseKey}
58
+ data: ${message.data}
59
+ """.trimIndent()
60
+
61
+ Log.i("expo-notifications", logMessage)
62
+ }
63
+
64
+ @RequiresApi(Build.VERSION_CODES.O)
65
+ fun logNotification(caller: String, notification: Notification) {
66
+ if (!BuildConfig.DEBUG) {
67
+ // Do not log for release/production builds
68
+ return
69
+ }
70
+ val logMessage =
71
+ """
72
+ $caller:
73
+ notification.notificationRequest.content.title: ${notification.notificationRequest.content.title}
74
+ notification.notificationRequest.content.subtitle: ${notification.notificationRequest.content.subtitle}
75
+ notification.notificationRequest.content.text: ${notification.notificationRequest.content.text}
76
+ notification.notificationRequest.content.sound: ${notification.notificationRequest.content.sound}
77
+ notification.notificationRequest.content.body: ${notification.notificationRequest.content.body}
78
+ notification.notificationRequest.content.color: ${notification.notificationRequest.content.color}
79
+ notification.notificationRequest.content.vibrationPattern: ${notification.notificationRequest.content.vibrationPattern.contentToString()}
80
+ notification.notificationRequest.trigger.notificationChannel: ${notification.notificationRequest.trigger.notificationChannel}
81
+ notification.notificationRequest.identifier: ${notification.notificationRequest.identifier}
82
+ """.trimIndent()
83
+
84
+ Log.i("expo-notifications", logMessage)
85
+ }
86
+ }
@@ -4,6 +4,7 @@ import android.os.Bundle
4
4
  import expo.modules.kotlin.modules.Module
5
5
  import expo.modules.kotlin.modules.ModuleDefinition
6
6
  import expo.modules.notifications.notifications.NotificationSerializer
7
+ import expo.modules.notifications.notifications.debug.DebugLogging
7
8
  import expo.modules.notifications.notifications.interfaces.NotificationListener
8
9
  import expo.modules.notifications.notifications.interfaces.NotificationManager
9
10
  import expo.modules.notifications.notifications.model.Notification
@@ -49,7 +50,9 @@ open class NotificationsEmitter : Module(), NotificationListener {
49
50
  * @param notification Notification received
50
51
  */
51
52
  override fun onNotificationReceived(notification: Notification) {
52
- sendEvent(NEW_MESSAGE_EVENT_NAME, NotificationSerializer.toBundle(notification))
53
+ val bundle = NotificationSerializer.toBundle(notification)
54
+ DebugLogging.logBundle("NotificationsEmitter.onNotificationReceived", bundle)
55
+ sendEvent(NEW_MESSAGE_EVENT_NAME, bundle)
53
56
  }
54
57
 
55
58
  /**
@@ -60,13 +63,17 @@ open class NotificationsEmitter : Module(), NotificationListener {
60
63
  * @return Whether notification has been handled
61
64
  */
62
65
  override fun onNotificationResponseReceived(response: NotificationResponse): Boolean {
63
- lastNotificationResponseBundle = NotificationSerializer.toBundle(response)
66
+ val bundle = NotificationSerializer.toBundle(response)
67
+ DebugLogging.logBundle("NotificationsEmitter.onNotificationResponseReceived", bundle)
68
+ lastNotificationResponseBundle = bundle
64
69
  sendEvent(NEW_RESPONSE_EVENT_NAME, lastNotificationResponseBundle)
65
70
  return true
66
71
  }
67
72
 
68
73
  override fun onNotificationResponseIntentReceived(extras: Bundle?) {
69
- lastNotificationResponseBundle = NotificationSerializer.toResponseBundleFromExtras(extras)
74
+ val bundle = NotificationSerializer.toResponseBundleFromExtras(extras)
75
+ DebugLogging.logBundle("NotificationsEmitter.onNotificationResponseIntentReceived", bundle)
76
+ lastNotificationResponseBundle = bundle
70
77
  sendEvent(NEW_RESPONSE_EVENT_NAME, lastNotificationResponseBundle)
71
78
  }
72
79
 
@@ -10,6 +10,7 @@ import android.net.Uri
10
10
  import android.os.*
11
11
  import android.util.Log
12
12
  import androidx.core.app.RemoteInput
13
+ import expo.modules.notifications.BuildConfig
13
14
  import expo.modules.notifications.notifications.model.*
14
15
  import expo.modules.notifications.service.delegates.ExpoCategoriesDelegate
15
16
  import expo.modules.notifications.service.delegates.ExpoHandlingDelegate
@@ -644,7 +645,12 @@ open class NotificationsService : BroadcastReceiver() {
644
645
  // If we ended up here, the callbacks must have completed successfully
645
646
  receiver?.send(SUCCESS_CODE, resultData)
646
647
  } catch (e: Exception) {
647
- Log.e("expo-notifications", "Action ${intent.action} failed: ${e.message}")
648
+ if (BuildConfig.DEBUG) {
649
+ // Log stack trace for debugging
650
+ Log.e("expo-notifications", "Action ${intent.action} failed: ${e.message}\n${e.stackTraceToString()}")
651
+ } else {
652
+ Log.e("expo-notifications", "Action ${intent.action} failed: ${e.message}")
653
+ }
648
654
  e.printStackTrace()
649
655
 
650
656
  receiver?.send(ERROR_CODE, Bundle().also { it.putSerializable(EXCEPTION_KEY, e) })
@@ -1,22 +1,14 @@
1
1
  package expo.modules.notifications.service.delegates;
2
2
 
3
3
  import android.app.Activity;
4
- import android.app.NotificationChannel;
5
- import android.app.PendingIntent;
6
4
  import android.content.Context;
7
5
  import android.content.Intent;
8
6
  import android.os.Bundle;
9
- import android.os.Parcel;
10
7
  import android.util.Log;
11
8
 
12
- import androidx.core.app.NotificationCompat;
13
-
14
- import java.util.Objects;
15
-
16
9
  import expo.modules.core.interfaces.ReactActivityLifecycleListener;
17
10
  import expo.modules.notifications.notifications.NotificationManager;
18
- import expo.modules.notifications.notifications.model.Notification;
19
- import expo.modules.notifications.notifications.model.NotificationResponse;
11
+ import expo.modules.notifications.notifications.debug.DebugLogging;
20
12
 
21
13
  public class ExpoNotificationLifecycleListener implements ReactActivityLifecycleListener {
22
14
 
@@ -45,6 +37,7 @@ public class ExpoNotificationLifecycleListener implements ReactActivityLifecycle
45
37
  Log.d("ReactNativeJS", "[native] ExpoNotificationLifecycleListener contains an unmarshaled notification response. Skipping.");
46
38
  return;
47
39
  }
40
+ DebugLogging.logBundle("ExpoNotificationLifeCycleListener.onCreate:", extras);
48
41
  mNotificationManager.onNotificationResponseFromExtras(extras);
49
42
  }
50
43
  }
@@ -68,6 +61,7 @@ public class ExpoNotificationLifecycleListener implements ReactActivityLifecycle
68
61
  intent.removeExtra("notificationResponse");
69
62
  return ReactActivityLifecycleListener.super.onNewIntent(intent);
70
63
  }
64
+ DebugLogging.logBundle("ExpoNotificationLifeCycleListener.onNewIntent:", extras);
71
65
  mNotificationManager.onNotificationResponseFromExtras(extras);
72
66
  }
73
67
  return ReactActivityLifecycleListener.super.onNewIntent(intent);
@@ -1,10 +1,12 @@
1
1
  package expo.modules.notifications.service.delegates
2
2
 
3
3
  import android.content.Context
4
+ import android.os.Build
4
5
  import com.google.firebase.messaging.RemoteMessage
5
6
  import expo.modules.notifications.notifications.JSONNotificationContentBuilder
6
7
  import expo.modules.notifications.notifications.RemoteMessageSerializer
7
8
  import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer
9
+ import expo.modules.notifications.notifications.debug.DebugLogging
8
10
  import expo.modules.notifications.notifications.model.Notification
9
11
  import expo.modules.notifications.notifications.model.NotificationContent
10
12
  import expo.modules.notifications.notifications.model.NotificationRequest
@@ -90,7 +92,12 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM
90
92
  fun getBackgroundTasks() = sBackgroundTaskConsumerReferences.values.mapNotNull { it.get() }
91
93
 
92
94
  override fun onMessageReceived(remoteMessage: RemoteMessage) {
93
- NotificationsService.receive(context, createNotification(remoteMessage))
95
+ DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage)
96
+ val notification = createNotification(remoteMessage)
97
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
98
+ DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification)
99
+ }
100
+ NotificationsService.receive(context, notification)
94
101
  getBackgroundTasks().forEach {
95
102
  it.scheduleJob(RemoteMessageSerializer.toBundle(remoteMessage))
96
103
  }
@@ -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;AAY3E,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,CAQd;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,YAAY,QAExE;AAGD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAO7F"}
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;AAY3E,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;AAGD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAO7F"}
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter, UnavailabilityError } from 'expo-modules-core';
2
2
  import NotificationsEmitterModule from './NotificationsEmitterModule';
3
- import { mapNotificationResponse } from './utils/mapNotificationResponse';
3
+ import { mapNotification, mapNotificationResponse } from './utils/mapNotificationResponse';
4
4
  // Web uses SyntheticEventEmitter
5
5
  const emitter = new EventEmitter(NotificationsEmitterModule);
6
6
  const didReceiveNotificationEventName = 'onDidReceiveNotification';
@@ -33,7 +33,10 @@ export const DEFAULT_ACTION_IDENTIFIER = 'expo.modules.notifications.actions.DEF
33
33
  * @header listen
34
34
  */
35
35
  export function addNotificationReceivedListener(listener) {
36
- return emitter.addListener(didReceiveNotificationEventName, listener);
36
+ return emitter.addListener(didReceiveNotificationEventName, (notification) => {
37
+ const mappedNotification = mapNotification(notification);
38
+ listener(mappedNotification);
39
+ });
37
40
  }
38
41
  /**
39
42
  * Listeners registered by this method will be called whenever some notifications have been dropped by the server.
@@ -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,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,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,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,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,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","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';\n\nimport { Notification, NotificationResponse } from './Notifications.types';\nimport NotificationsEmitterModule from './NotificationsEmitterModule';\nimport { mapNotificationResponse } from './utils/mapNotificationResponse';\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 = 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// @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 const response = await NotificationsEmitterModule.getLastNotificationResponseAsync();\n const mappedResponse = response ? mapNotificationResponse(response) : response;\n return mappedResponse;\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;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;AAEnF,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,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,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","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';\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// @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 const response = await NotificationsEmitterModule.getLastNotificationResponseAsync();\n const mappedResponse = response ? mapNotificationResponse(response) : response;\n return mappedResponse;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { NotificationResponse } from '../Notifications.types';
1
+ import { Notification, NotificationResponse } from '../Notifications.types';
2
2
  /**
3
3
  * @hidden
4
4
  *
@@ -9,13 +9,31 @@ import { NotificationResponse } from '../Notifications.types';
9
9
  * @param response The raw response passed in from native code
10
10
  * @returns the mapped response.
11
11
  */
12
- export declare const mapNotificationResponse: (response: NotificationResponse) => NotificationResponse & {
13
- notification: {
12
+ export declare const mapNotificationResponse: (response: NotificationResponse) => {
13
+ notification: Notification & {
14
14
  request: {
15
15
  content: {
16
16
  dataString?: string;
17
17
  };
18
18
  };
19
19
  };
20
+ actionIdentifier: string;
21
+ userText?: string | undefined;
22
+ };
23
+ /**
24
+ * @hidden
25
+ *
26
+ * Does any required processing of a notification from native code
27
+ * before it is passed to a notification listener.
28
+ *
29
+ * @param notification The raw notification passed in from native code
30
+ * @returns the mapped notification.
31
+ */
32
+ export declare const mapNotification: (notification: Notification) => Notification & {
33
+ request: {
34
+ content: {
35
+ dataString?: string;
36
+ };
37
+ };
20
38
  };
21
39
  //# sourceMappingURL=mapNotificationResponse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapNotificationResponse.d.ts","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,aAAc,oBAAoB;kBAEpD;QAAE,OAAO,EAAE;YAAE,OAAO,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE;CAYlE,CAAC"}
1
+ {"version":3,"file":"mapNotificationResponse.d.ts","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE5E;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,aAAc,oBAAoB;;iBAkBzD;YAAE,OAAO,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE;;;;CAbhD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,iBAAkB,YAAY;aAE7C;QAAE,OAAO,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;CAYhD,CAAC"}
@@ -9,17 +9,32 @@
9
9
  * @returns the mapped response.
10
10
  */
11
11
  export const mapNotificationResponse = (response) => {
12
- const mappedResponse = { ...response };
12
+ return {
13
+ ...response,
14
+ notification: mapNotification(response.notification),
15
+ };
16
+ };
17
+ /**
18
+ * @hidden
19
+ *
20
+ * Does any required processing of a notification from native code
21
+ * before it is passed to a notification listener.
22
+ *
23
+ * @param notification The raw notification passed in from native code
24
+ * @returns the mapped notification.
25
+ */
26
+ export const mapNotification = (notification) => {
27
+ const mappedNotification = { ...notification };
13
28
  try {
14
- const dataString = mappedResponse?.notification?.request?.content['dataString'];
29
+ const dataString = mappedNotification?.request?.content['dataString'];
15
30
  if (typeof dataString === 'string') {
16
- mappedResponse.notification.request.content.data = JSON.parse(dataString);
17
- delete mappedResponse.notification.request.content.dataString;
31
+ mappedNotification.request.content.data = JSON.parse(dataString);
32
+ delete mappedNotification.request.content.dataString;
18
33
  }
19
34
  }
20
35
  catch (e) {
21
- console.log(`Error in response: ${e}`);
36
+ console.log(`Error in notification: ${e}`);
22
37
  }
23
- return mappedResponse;
38
+ return mappedNotification;
24
39
  };
25
40
  //# sourceMappingURL=mapNotificationResponse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapNotificationResponse.js","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,QAA8B,EAAE,EAAE;IACxE,MAAM,cAAc,GAEhB,EAAE,GAAG,QAAQ,EAAE,CAAC;IACpB,IAAI;QACF,MAAM,UAAU,GAAG,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAChF,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YAClC,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC1E,OAAO,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;SAC/D;KACF;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;KACxC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC,CAAC","sourcesContent":["import { NotificationResponse } from '../Notifications.types';\n\n/**\n * @hidden\n *\n * Does any required processing of a notification response from native code\n * before it is passed to a notification response listener, or to the\n * last notification response hook.\n *\n * @param response The raw response passed in from native code\n * @returns the mapped response.\n */\nexport const mapNotificationResponse = (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 return mappedResponse;\n};\n"]}
1
+ {"version":3,"file":"mapNotificationResponse.js","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,QAA8B,EAAE,EAAE;IACxE,OAAO;QACL,GAAG,QAAQ;QACX,YAAY,EAAE,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC;KACrD,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAA0B,EAAE,EAAE;IAC5D,MAAM,kBAAkB,GAEpB,EAAE,GAAG,YAAY,EAAE,CAAC;IACxB,IAAI;QACF,MAAM,UAAU,GAAG,kBAAkB,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QACtE,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YAClC,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACjE,OAAO,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;SACtD;KACF;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC;KAC5C;IACD,OAAO,kBAAkB,CAAC;AAC5B,CAAC,CAAC","sourcesContent":["import { Notification, NotificationResponse } from '../Notifications.types';\n\n/**\n * @hidden\n *\n * Does any required processing of a notification response from native code\n * before it is passed to a notification response listener, or to the\n * last notification response hook.\n *\n * @param response The raw response passed in from native code\n * @returns the mapped response.\n */\nexport const mapNotificationResponse = (response: NotificationResponse) => {\n return {\n ...response,\n notification: mapNotification(response.notification),\n };\n};\n\n/**\n * @hidden\n *\n * Does any required processing of a notification from native code\n * before it is passed to a notification listener.\n *\n * @param notification The raw notification passed in from native code\n * @returns the mapped notification.\n */\nexport const mapNotification = (notification: Notification) => {\n const mappedNotification: Notification & {\n request: { content: { dataString?: string } };\n } = { ...notification };\n try {\n const dataString = mappedNotification?.request?.content['dataString'];\n if (typeof dataString === 'string') {\n mappedNotification.request.content.data = JSON.parse(dataString);\n delete mappedNotification.request.content.dataString;\n }\n } catch (e: any) {\n console.log(`Error in notification: ${e}`);\n }\n return mappedNotification;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-notifications",
3
- "version": "0.28.12",
3
+ "version": "0.28.13",
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": "e4d9b651e6693856e4ffe674490f6463e34f3ecc"
58
+ "gitHead": "89cb316cd1f16193ae9841d2aec2ae39e0ee00bb"
59
59
  }
@@ -2,7 +2,7 @@ import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-co
2
2
 
3
3
  import { Notification, NotificationResponse } from './Notifications.types';
4
4
  import NotificationsEmitterModule from './NotificationsEmitterModule';
5
- import { mapNotificationResponse } from './utils/mapNotificationResponse';
5
+ import { mapNotification, mapNotificationResponse } from './utils/mapNotificationResponse';
6
6
 
7
7
  // Web uses SyntheticEventEmitter
8
8
  const emitter = new EventEmitter(NotificationsEmitterModule);
@@ -41,7 +41,13 @@ export const DEFAULT_ACTION_IDENTIFIER = 'expo.modules.notifications.actions.DEF
41
41
  export function addNotificationReceivedListener(
42
42
  listener: (event: Notification) => void
43
43
  ): Subscription {
44
- return emitter.addListener<Notification>(didReceiveNotificationEventName, listener);
44
+ return emitter.addListener<Notification>(
45
+ didReceiveNotificationEventName,
46
+ (notification: Notification) => {
47
+ const mappedNotification = mapNotification(notification);
48
+ listener(mappedNotification);
49
+ }
50
+ );
45
51
  }
46
52
 
47
53
  /**
@@ -1,4 +1,4 @@
1
- import { NotificationResponse } from '../Notifications.types';
1
+ import { Notification, NotificationResponse } from '../Notifications.types';
2
2
 
3
3
  /**
4
4
  * @hidden
@@ -11,17 +11,33 @@ import { NotificationResponse } from '../Notifications.types';
11
11
  * @returns the mapped response.
12
12
  */
13
13
  export const mapNotificationResponse = (response: NotificationResponse) => {
14
- const mappedResponse: NotificationResponse & {
15
- notification: { request: { content: { dataString?: string } } };
16
- } = { ...response };
14
+ return {
15
+ ...response,
16
+ notification: mapNotification(response.notification),
17
+ };
18
+ };
19
+
20
+ /**
21
+ * @hidden
22
+ *
23
+ * Does any required processing of a notification from native code
24
+ * before it is passed to a notification listener.
25
+ *
26
+ * @param notification The raw notification passed in from native code
27
+ * @returns the mapped notification.
28
+ */
29
+ export const mapNotification = (notification: Notification) => {
30
+ const mappedNotification: Notification & {
31
+ request: { content: { dataString?: string } };
32
+ } = { ...notification };
17
33
  try {
18
- const dataString = mappedResponse?.notification?.request?.content['dataString'];
34
+ const dataString = mappedNotification?.request?.content['dataString'];
19
35
  if (typeof dataString === 'string') {
20
- mappedResponse.notification.request.content.data = JSON.parse(dataString);
21
- delete mappedResponse.notification.request.content.dataString;
36
+ mappedNotification.request.content.data = JSON.parse(dataString);
37
+ delete mappedNotification.request.content.dataString;
22
38
  }
23
39
  } catch (e: any) {
24
- console.log(`Error in response: ${e}`);
40
+ console.log(`Error in notification: ${e}`);
25
41
  }
26
- return mappedResponse;
42
+ return mappedNotification;
27
43
  };