expo-notifications 1.0.0-canary-20240814-ce0f7d5 → 1.0.0-canary-20240904-69100c1
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 +3 -0
- package/android/build.gradle +11 -0
- package/android/src/main/java/expo/modules/notifications/Exceptions.kt +0 -13
- package/android/src/main/java/expo/modules/notifications/notifications/JSONNotificationContentBuilder.java +1 -1
- package/android/src/main/java/expo/modules/notifications/notifications/NotificationSerializer.java +25 -13
- package/android/src/main/java/expo/modules/notifications/notifications/debug/DebugLogging.kt +1 -0
- package/android/src/main/java/expo/modules/notifications/notifications/handling/NotificationsHandler.kt +1 -2
- package/android/src/main/java/expo/modules/notifications/notifications/handling/SingleNotificationHandlerTask.java +2 -2
- package/android/src/main/java/expo/modules/notifications/notifications/model/triggers/FirebaseNotificationTrigger.kt +43 -0
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ChannelAwareNotificationBuilder.java +6 -7
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.java +0 -3
- package/android/src/main/java/expo/modules/notifications/service/NotificationsService.kt +48 -44
- package/android/src/main/java/expo/modules/notifications/service/delegates/ExpoPresentationDelegate.kt +17 -3
- package/build/getAllScheduledNotificationsAsync.d.ts.map +1 -1
- package/build/getAllScheduledNotificationsAsync.js +2 -1
- package/build/getAllScheduledNotificationsAsync.js.map +1 -1
- package/build/getPresentedNotificationsAsync.d.ts.map +1 -1
- package/build/getPresentedNotificationsAsync.js +2 -1
- package/build/getPresentedNotificationsAsync.js.map +1 -1
- package/build/utils/mapNotificationResponse.d.ts +40 -7
- package/build/utils/mapNotificationResponse.d.ts.map +1 -1
- package/build/utils/mapNotificationResponse.js +31 -6
- package/build/utils/mapNotificationResponse.js.map +1 -1
- package/package.json +6 -6
- package/src/getAllScheduledNotificationsAsync.ts +4 -1
- package/src/getPresentedNotificationsAsync.ts +4 -1
- package/src/utils/mapNotificationResponse.ts +39 -9
- package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationPresentationEffect.java +0 -11
- package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationPresentationEffectsManager.java +0 -7
- package/android/src/main/java/expo/modules/notifications/notifications/model/triggers/FirebaseNotificationTrigger.java +0 -61
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/ExpoNotificationPresentationEffectsManager.java +0 -63
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/effects/BaseNotificationEffect.java +0 -53
package/CHANGELOG.md
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
### 🐛 Bug fixes
|
|
12
12
|
|
|
13
|
+
- [Android] Take `channelId` into account when presenting notifications. ([#31201](https://github.com/expo/expo/pull/31201) by [@vonovak](https://github.com/vonovak))
|
|
13
14
|
- Add missing `react` and `react-native` peer dependencies for isolated modules. ([#30478](https://github.com/expo/expo/pull/30478) by [@byCedric](https://github.com/byCedric))
|
|
14
15
|
- [Android] Eliminate unsupported types when processing notification intents from onCreate/onNewIntent. ([#30750](https://github.com/expo/expo/pull/30750) by [@douglowder](https://github.com/douglowder))
|
|
16
|
+
- [Android] Fix content.data in scheduled notifications surfaced to JS. ([#31048](https://github.com/expo/expo/pull/31048) by [@douglowder](https://github.com/douglowder))
|
|
17
|
+
- [Android] fix local notifications with null trigger. ([#31157](https://github.com/expo/expo/pull/31157) by [@douglowder](https://github.com/douglowder))
|
|
15
18
|
|
|
16
19
|
### 💡 Others
|
|
17
20
|
|
package/android/build.gradle
CHANGED
|
@@ -20,6 +20,17 @@ android {
|
|
|
20
20
|
buildFeatures {
|
|
21
21
|
buildConfig true
|
|
22
22
|
}
|
|
23
|
+
testOptions {
|
|
24
|
+
unitTests.all { test ->
|
|
25
|
+
testLogging {
|
|
26
|
+
outputs.upToDateWhen { false }
|
|
27
|
+
events "passed", "failed", "skipped", "standardError"
|
|
28
|
+
showCauses true
|
|
29
|
+
showExceptions true
|
|
30
|
+
showStandardStreams true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
dependencies {
|
|
@@ -7,16 +7,3 @@ class ModuleNotFoundException(moduleClass: KClass<*>) :
|
|
|
7
7
|
CodedException(message = "$moduleClass module not found")
|
|
8
8
|
|
|
9
9
|
class NotificationWasAlreadyHandledException(val id: String) : CodedException("Failed to handle notification $id, it has already been handled.")
|
|
10
|
-
|
|
11
|
-
fun expo.modules.kotlin.Promise.toLegacyPromise(): expo.modules.core.Promise {
|
|
12
|
-
val newPromise = this
|
|
13
|
-
return object : expo.modules.core.Promise {
|
|
14
|
-
override fun resolve(value: Any?) {
|
|
15
|
-
newPromise.resolve(value)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
override fun reject(c: String?, m: String?, e: Throwable?) {
|
|
19
|
-
newPromise.reject(c ?: "unknown", m, e)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -100,7 +100,7 @@ public class JSONNotificationContentBuilder extends NotificationContent.Builder
|
|
|
100
100
|
// do nothing
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
//
|
|
103
|
+
// play a default sound only if the value is NOT a valid Uri
|
|
104
104
|
return getSound(payload) == null;
|
|
105
105
|
}
|
|
106
106
|
|
package/android/src/main/java/expo/modules/notifications/notifications/NotificationSerializer.java
CHANGED
|
@@ -23,6 +23,7 @@ import java.util.Map;
|
|
|
23
23
|
import java.util.Set;
|
|
24
24
|
|
|
25
25
|
import expo.modules.notifications.notifications.interfaces.NotificationTrigger;
|
|
26
|
+
import expo.modules.notifications.notifications.interfaces.SchedulableNotificationTrigger;
|
|
26
27
|
import expo.modules.notifications.notifications.model.Notification;
|
|
27
28
|
import expo.modules.notifications.notifications.model.NotificationContent;
|
|
28
29
|
import expo.modules.notifications.notifications.model.NotificationRequest;
|
|
@@ -60,19 +61,30 @@ public class NotificationSerializer {
|
|
|
60
61
|
serializedRequest.putBundle("trigger", toBundle(request.getTrigger()));
|
|
61
62
|
Bundle content = toBundle(request.getContent());
|
|
62
63
|
Bundle existingContentData = content.getBundle("data");
|
|
63
|
-
if (existingContentData == null
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
if (existingContentData == null) {
|
|
65
|
+
if(request.getTrigger() instanceof FirebaseNotificationTrigger trigger) {
|
|
66
|
+
RemoteMessage message = trigger.getRemoteMessage();
|
|
67
|
+
RemoteMessage.Notification notification = message.getNotification();
|
|
68
|
+
Map<String, String> data = message.getData();
|
|
69
|
+
String dataBody = data.get("body");
|
|
70
|
+
String notificationBody = notification != null ? notification.getBody() : null;
|
|
71
|
+
if (isValidJSONString(dataBody) && notificationBody != null && notificationBody.equals(data.get("message"))) {
|
|
72
|
+
// Expo sends notification.body as data.message, and JSON stringifies data.body
|
|
73
|
+
content.putString("dataString", dataBody);
|
|
74
|
+
} else {
|
|
75
|
+
// The message was sent directly from Firebase or some other service,
|
|
76
|
+
// and we copy the data as is
|
|
77
|
+
content.putBundle("data", toBundle(data));
|
|
78
|
+
}
|
|
79
|
+
} else if(
|
|
80
|
+
request.getTrigger() instanceof SchedulableNotificationTrigger ||
|
|
81
|
+
request.getTrigger() == null
|
|
82
|
+
) {
|
|
83
|
+
JSONObject body = request.getContent().getBody();
|
|
84
|
+
if (body != null) {
|
|
85
|
+
// Expo sends notification.body as data.message, and JSON stringifies data.body
|
|
86
|
+
content.putString("dataString", body.toString());
|
|
87
|
+
}
|
|
76
88
|
}
|
|
77
89
|
}
|
|
78
90
|
serializedRequest.putBundle("content", content);
|
package/android/src/main/java/expo/modules/notifications/notifications/debug/DebugLogging.kt
CHANGED
|
@@ -74,6 +74,7 @@ object DebugLogging {
|
|
|
74
74
|
notification.notificationRequest.content.subtitle: ${notification.notificationRequest.content.subtitle}
|
|
75
75
|
notification.notificationRequest.content.text: ${notification.notificationRequest.content.text}
|
|
76
76
|
notification.notificationRequest.content.sound: ${notification.notificationRequest.content.sound}
|
|
77
|
+
notification.notificationRequest.content.channelID: ${notification.notificationRequest.trigger.notificationChannel}
|
|
77
78
|
notification.notificationRequest.content.body: ${notification.notificationRequest.content.body}
|
|
78
79
|
notification.notificationRequest.content.color: ${notification.notificationRequest.content.color}
|
|
79
80
|
notification.notificationRequest.content.vibrationPattern: ${notification.notificationRequest.content.vibrationPattern.contentToString()}
|
|
@@ -13,7 +13,6 @@ import expo.modules.notifications.notifications.interfaces.NotificationListener
|
|
|
13
13
|
import expo.modules.notifications.notifications.interfaces.NotificationManager
|
|
14
14
|
import expo.modules.notifications.notifications.model.Notification
|
|
15
15
|
import expo.modules.notifications.notifications.model.NotificationBehavior
|
|
16
|
-
import expo.modules.notifications.toLegacyPromise
|
|
17
16
|
|
|
18
17
|
class NotificationBehaviourRecord : Record {
|
|
19
18
|
@Field
|
|
@@ -102,7 +101,7 @@ open class NotificationsHandler : Module(), NotificationListener {
|
|
|
102
101
|
with(behavior) {
|
|
103
102
|
task.handleResponse(
|
|
104
103
|
NotificationBehavior(shouldShowAlert, shouldPlaySound, shouldSetBadge, priority),
|
|
105
|
-
promise
|
|
104
|
+
promise
|
|
106
105
|
)
|
|
107
106
|
}
|
|
108
107
|
}
|
|
@@ -5,7 +5,7 @@ import android.os.Bundle;
|
|
|
5
5
|
import android.os.Handler;
|
|
6
6
|
import android.os.ResultReceiver;
|
|
7
7
|
|
|
8
|
-
import expo.modules.
|
|
8
|
+
import expo.modules.kotlin.Promise;
|
|
9
9
|
import expo.modules.core.interfaces.services.EventEmitter;
|
|
10
10
|
import expo.modules.notifications.notifications.NotificationSerializer;
|
|
11
11
|
import expo.modules.notifications.notifications.model.Notification;
|
|
@@ -98,7 +98,7 @@ public class SingleNotificationHandlerTask {
|
|
|
98
98
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
|
99
99
|
super.onReceiveResult(resultCode, resultData);
|
|
100
100
|
if (resultCode == NotificationsService.SUCCESS_CODE) {
|
|
101
|
-
promise.resolve(
|
|
101
|
+
promise.resolve();
|
|
102
102
|
} else {
|
|
103
103
|
Exception e = (Exception) resultData.getSerializable(NotificationsService.EXCEPTION_KEY);
|
|
104
104
|
promise.reject("ERR_NOTIFICATION_PRESENTATION_FAILED", "Notification presentation failed.", e);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package expo.modules.notifications.notifications.model.triggers
|
|
2
|
+
|
|
3
|
+
import android.os.Build
|
|
4
|
+
import android.os.Parcel
|
|
5
|
+
import android.os.Parcelable
|
|
6
|
+
import androidx.annotation.RequiresApi
|
|
7
|
+
import com.google.firebase.messaging.RemoteMessage
|
|
8
|
+
import expo.modules.notifications.notifications.interfaces.NotificationTrigger
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A trigger representing an incoming remote Firebase notification.
|
|
12
|
+
*/
|
|
13
|
+
class FirebaseNotificationTrigger(private val remoteMessage: RemoteMessage) : NotificationTrigger {
|
|
14
|
+
|
|
15
|
+
private constructor(parcel: Parcel) : this(
|
|
16
|
+
parcel.readParcelable(FirebaseNotificationTrigger::class.java.classLoader)
|
|
17
|
+
?: throw IllegalArgumentException("RemoteMessage from readParcelable must not be null")
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
fun getRemoteMessage(): RemoteMessage = remoteMessage
|
|
21
|
+
|
|
22
|
+
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
23
|
+
override fun getNotificationChannel(): String? {
|
|
24
|
+
val channelId = remoteMessage.notification?.channelId ?: remoteMessage.data["channelId"]
|
|
25
|
+
return channelId ?: super.getNotificationChannel()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun describeContents(): Int {
|
|
29
|
+
return 0
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override fun writeToParcel(dest: Parcel, flags: Int) {
|
|
33
|
+
dest.writeParcelable(remoteMessage, 0)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
companion object {
|
|
37
|
+
@JvmField
|
|
38
|
+
val CREATOR = object : Parcelable.Creator<FirebaseNotificationTrigger> {
|
|
39
|
+
override fun createFromParcel(parcel: Parcel) = FirebaseNotificationTrigger(parcel)
|
|
40
|
+
override fun newArray(size: Int) = arrayOfNulls<FirebaseNotificationTrigger>(size)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -53,19 +53,18 @@ public abstract class ChannelAwareNotificationBuilder extends BaseNotificationBu
|
|
|
53
53
|
return getFallbackNotificationChannel().getId();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
String
|
|
57
|
-
if (
|
|
56
|
+
String requestedChannelId = trigger.getNotificationChannel();
|
|
57
|
+
if (requestedChannelId == null) {
|
|
58
58
|
return getFallbackNotificationChannel().getId();
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Log.e("notifications", String.format("Channel '%s' doesn't exists. Fallback to '%s' channel", channelId, FALLBACK_CHANNEL_ID));
|
|
61
|
+
NotificationChannel channelForRequestedId = getNotificationsChannelManager().getNotificationChannel(requestedChannelId);
|
|
62
|
+
if (channelForRequestedId == null) {
|
|
63
|
+
Log.e("notifications", String.format("Channel '%s' doesn't exists. Fallback to '%s' channel", requestedChannelId, FALLBACK_CHANNEL_ID));
|
|
65
64
|
return getFallbackNotificationChannel().getId();
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
return
|
|
67
|
+
return channelForRequestedId.getId();
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
@NonNull
|
|
@@ -7,7 +7,6 @@ import android.content.pm.PackageManager;
|
|
|
7
7
|
import android.content.res.Resources;
|
|
8
8
|
import android.graphics.Bitmap;
|
|
9
9
|
import android.graphics.BitmapFactory;
|
|
10
|
-
import android.os.Build;
|
|
11
10
|
import android.os.Bundle;
|
|
12
11
|
import android.os.Parcel;
|
|
13
12
|
import android.provider.Settings;
|
|
@@ -34,8 +33,6 @@ public class ExpoNotificationBuilder extends ChannelAwareNotificationBuilder {
|
|
|
34
33
|
public static final String EXTRAS_MARSHALLED_NOTIFICATION_REQUEST_KEY = "expo.notification_request";
|
|
35
34
|
private static final String EXTRAS_BODY_KEY = "body";
|
|
36
35
|
|
|
37
|
-
private static final long[] NO_VIBRATE_PATTERN = new long[]{0, 0};
|
|
38
|
-
|
|
39
36
|
public ExpoNotificationBuilder(Context context) {
|
|
40
37
|
super(context);
|
|
41
38
|
}
|
|
@@ -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.core.interfaces.DoNotStrip
|
|
13
14
|
import expo.modules.notifications.BuildConfig
|
|
14
15
|
import expo.modules.notifications.notifications.model.*
|
|
15
16
|
import expo.modules.notifications.service.delegates.ExpoCategoriesDelegate
|
|
@@ -86,9 +87,9 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
86
87
|
fun getAllPresented(context: Context, receiver: ResultReceiver? = null) {
|
|
87
88
|
doWork(
|
|
88
89
|
context,
|
|
89
|
-
Intent(NOTIFICATION_EVENT_ACTION, getUriBuilder().build()).
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
Intent(NOTIFICATION_EVENT_ACTION, getUriBuilder().build()).apply {
|
|
91
|
+
putExtra(EVENT_TYPE_KEY, GET_ALL_DISPLAYED_TYPE)
|
|
92
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
92
93
|
}
|
|
93
94
|
)
|
|
94
95
|
}
|
|
@@ -105,11 +106,11 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
105
106
|
val data = getUriBuilderForIdentifier(notification.notificationRequest.identifier).appendPath("present").build()
|
|
106
107
|
doWork(
|
|
107
108
|
context,
|
|
108
|
-
Intent(NOTIFICATION_EVENT_ACTION, data).
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
Intent(NOTIFICATION_EVENT_ACTION, data).apply {
|
|
110
|
+
putExtra(EVENT_TYPE_KEY, PRESENT_TYPE)
|
|
111
|
+
putExtra(NOTIFICATION_KEY, notification)
|
|
112
|
+
putExtra(NOTIFICATION_BEHAVIOR_KEY, behavior)
|
|
113
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
113
114
|
}
|
|
114
115
|
)
|
|
115
116
|
}
|
|
@@ -125,10 +126,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
125
126
|
val data = getUriBuilderForIdentifier(notification.notificationRequest.identifier).appendPath("receive").build()
|
|
126
127
|
doWork(
|
|
127
128
|
context,
|
|
128
|
-
Intent(NOTIFICATION_EVENT_ACTION, data).
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
Intent(NOTIFICATION_EVENT_ACTION, data).apply {
|
|
130
|
+
putExtra(EVENT_TYPE_KEY, RECEIVE_TYPE)
|
|
131
|
+
putExtra(NOTIFICATION_KEY, notification)
|
|
132
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
132
133
|
}
|
|
133
134
|
)
|
|
134
135
|
}
|
|
@@ -144,10 +145,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
144
145
|
val data = getUriBuilder().appendPath("dismiss").build()
|
|
145
146
|
doWork(
|
|
146
147
|
context,
|
|
147
|
-
Intent(NOTIFICATION_EVENT_ACTION, data).
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
Intent(NOTIFICATION_EVENT_ACTION, data).apply {
|
|
149
|
+
putExtra(EVENT_TYPE_KEY, DISMISS_SELECTED_TYPE)
|
|
150
|
+
putExtra(IDENTIFIERS_KEY, identifiers)
|
|
151
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
151
152
|
}
|
|
152
153
|
)
|
|
153
154
|
}
|
|
@@ -162,9 +163,9 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
162
163
|
val data = getUriBuilder().appendPath("dismiss").build()
|
|
163
164
|
doWork(
|
|
164
165
|
context,
|
|
165
|
-
Intent(NOTIFICATION_EVENT_ACTION, data).
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
Intent(NOTIFICATION_EVENT_ACTION, data).apply {
|
|
167
|
+
putExtra(EVENT_TYPE_KEY, DISMISS_ALL_TYPE)
|
|
168
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
168
169
|
}
|
|
169
170
|
)
|
|
170
171
|
}
|
|
@@ -177,8 +178,8 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
177
178
|
fun handleDropped(context: Context) {
|
|
178
179
|
doWork(
|
|
179
180
|
context,
|
|
180
|
-
Intent(NOTIFICATION_EVENT_ACTION).
|
|
181
|
-
|
|
181
|
+
Intent(NOTIFICATION_EVENT_ACTION).apply {
|
|
182
|
+
putExtra(EVENT_TYPE_KEY, DROPPED_TYPE)
|
|
182
183
|
}
|
|
183
184
|
)
|
|
184
185
|
}
|
|
@@ -196,9 +197,9 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
196
197
|
getUriBuilder()
|
|
197
198
|
.appendPath("categories")
|
|
198
199
|
.build()
|
|
199
|
-
).
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
).apply {
|
|
201
|
+
putExtra(EVENT_TYPE_KEY, GET_CATEGORIES_TYPE)
|
|
202
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
202
203
|
}
|
|
203
204
|
)
|
|
204
205
|
}
|
|
@@ -218,10 +219,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
218
219
|
.appendPath("categories")
|
|
219
220
|
.appendPath(category.identifier)
|
|
220
221
|
.build()
|
|
221
|
-
).
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
).apply {
|
|
223
|
+
putExtra(EVENT_TYPE_KEY, SET_CATEGORY_TYPE)
|
|
224
|
+
putExtra(NOTIFICATION_CATEGORY_KEY, category as Parcelable)
|
|
225
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
225
226
|
}
|
|
226
227
|
)
|
|
227
228
|
}
|
|
@@ -241,10 +242,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
241
242
|
.appendPath("categories")
|
|
242
243
|
.appendPath(identifier)
|
|
243
244
|
.build()
|
|
244
|
-
).
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
).apply {
|
|
246
|
+
putExtra(EVENT_TYPE_KEY, DELETE_CATEGORY_TYPE)
|
|
247
|
+
putExtra(IDENTIFIER_KEY, identifier)
|
|
248
|
+
putExtra(RECEIVER_KEY, receiver)
|
|
248
249
|
}
|
|
249
250
|
)
|
|
250
251
|
}
|
|
@@ -266,12 +267,13 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
/**
|
|
269
|
-
* Fetches scheduled notification asynchronously.
|
|
270
|
+
* Fetches scheduled notification asynchronously. Used in Expo Go's ScopedNotificationScheduler.kt
|
|
270
271
|
*
|
|
271
272
|
* @param context Context this is being called from
|
|
272
273
|
* @param identifier Identifier of the notification to be fetched
|
|
273
274
|
* @param resultReceiver Receiver to be called with the results
|
|
274
275
|
*/
|
|
276
|
+
@DoNotStrip
|
|
275
277
|
fun getScheduledNotification(context: Context, identifier: String, resultReceiver: ResultReceiver? = null) {
|
|
276
278
|
doWork(
|
|
277
279
|
context,
|
|
@@ -305,10 +307,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
305
307
|
.appendPath("scheduled")
|
|
306
308
|
.appendPath(notificationRequest.identifier)
|
|
307
309
|
.build()
|
|
308
|
-
).
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
).apply {
|
|
311
|
+
putExtra(EVENT_TYPE_KEY, SCHEDULE_TYPE)
|
|
312
|
+
putExtra(NOTIFICATION_REQUEST_KEY, notificationRequest as Parcelable)
|
|
313
|
+
putExtra(RECEIVER_KEY, resultReceiver)
|
|
312
314
|
}
|
|
313
315
|
)
|
|
314
316
|
}
|
|
@@ -338,10 +340,10 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
338
340
|
getUriBuilder()
|
|
339
341
|
.appendPath("scheduled")
|
|
340
342
|
.build()
|
|
341
|
-
).
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
).apply {
|
|
344
|
+
putExtra(EVENT_TYPE_KEY, REMOVE_SELECTED_TYPE)
|
|
345
|
+
putExtra(IDENTIFIERS_KEY, identifiers.toTypedArray())
|
|
346
|
+
putExtra(RECEIVER_KEY, resultReceiver)
|
|
345
347
|
}
|
|
346
348
|
)
|
|
347
349
|
}
|
|
@@ -355,9 +357,9 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
355
357
|
fun removeAllScheduledNotifications(context: Context, resultReceiver: ResultReceiver? = null) {
|
|
356
358
|
doWork(
|
|
357
359
|
context,
|
|
358
|
-
Intent(NOTIFICATION_EVENT_ACTION).
|
|
359
|
-
|
|
360
|
-
|
|
360
|
+
Intent(NOTIFICATION_EVENT_ACTION).apply {
|
|
361
|
+
putExtra(EVENT_TYPE_KEY, REMOVE_ALL_TYPE)
|
|
362
|
+
putExtra(RECEIVER_KEY, resultReceiver)
|
|
361
363
|
}
|
|
362
364
|
)
|
|
363
365
|
}
|
|
@@ -511,6 +513,8 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
511
513
|
return response
|
|
512
514
|
}
|
|
513
515
|
|
|
516
|
+
// this is used by Expo Go's Kernel.kt
|
|
517
|
+
@DoNotStrip
|
|
514
518
|
fun getNotificationResponseFromOpenIntent(intent: Intent): NotificationResponse? {
|
|
515
519
|
intent.getByteArrayExtra(NOTIFICATION_RESPONSE_KEY)?.let { return unmarshalObject(NotificationResponse.CREATOR, it) }
|
|
516
520
|
intent.getByteArrayExtra(TEXT_INPUT_NOTIFICATION_RESPONSE_KEY)?.let { return unmarshalObject(TextInputNotificationResponse.CREATOR, it) }
|
|
@@ -4,6 +4,7 @@ import android.app.NotificationManager
|
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.media.RingtoneManager
|
|
6
6
|
import android.net.Uri
|
|
7
|
+
import android.os.Build
|
|
7
8
|
import android.os.Bundle
|
|
8
9
|
import android.os.Parcel
|
|
9
10
|
import android.provider.Settings
|
|
@@ -21,11 +22,13 @@ import expo.modules.notifications.notifications.presentation.builders.ExpoNotifi
|
|
|
21
22
|
import expo.modules.notifications.service.interfaces.PresentationDelegate
|
|
22
23
|
import org.json.JSONException
|
|
23
24
|
import org.json.JSONObject
|
|
24
|
-
import java.util
|
|
25
|
+
import java.util.Date
|
|
25
26
|
|
|
26
27
|
open class ExpoPresentationDelegate(
|
|
27
|
-
protected val context: Context
|
|
28
|
+
protected val context: Context,
|
|
29
|
+
private val notificationManager: NotificationManagerCompat = NotificationManagerCompat.from(context)
|
|
28
30
|
) : PresentationDelegate {
|
|
31
|
+
|
|
29
32
|
companion object {
|
|
30
33
|
protected const val ANDROID_NOTIFICATION_ID = 0
|
|
31
34
|
|
|
@@ -87,9 +90,10 @@ open class ExpoPresentationDelegate(
|
|
|
87
90
|
override fun presentNotification(notification: Notification, behavior: NotificationBehavior?) {
|
|
88
91
|
if (behavior != null && !behavior.shouldShowAlert()) {
|
|
89
92
|
if (behavior.shouldPlaySound()) {
|
|
93
|
+
val sound = getNotificationSoundUri(notification) ?: Settings.System.DEFAULT_NOTIFICATION_URI
|
|
90
94
|
RingtoneManager.getRingtone(
|
|
91
95
|
context,
|
|
92
|
-
|
|
96
|
+
sound
|
|
93
97
|
).play()
|
|
94
98
|
}
|
|
95
99
|
return
|
|
@@ -101,6 +105,16 @@ open class ExpoPresentationDelegate(
|
|
|
101
105
|
)
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
private fun getNotificationSoundUri(notification: Notification): Uri? {
|
|
109
|
+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
110
|
+
notification.notificationRequest.trigger.notificationChannel?.let {
|
|
111
|
+
notificationManager.getNotificationChannel(it)?.sound
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
notification.notificationRequest.content.sound
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
protected open fun getNotifyId(request: NotificationRequest?): Int {
|
|
105
119
|
return ANDROID_NOTIFICATION_ID
|
|
106
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAllScheduledNotificationsAsync.d.ts","sourceRoot":"","sources":["../src/getAllScheduledNotificationsAsync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"getAllScheduledNotificationsAsync.d.ts","sourceRoot":"","sources":["../src/getAllScheduledNotificationsAsync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5D;;;;GAIG;AACH,wBAA8B,iCAAiC,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAQhG"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
2
|
import NotificationScheduler from './NotificationScheduler';
|
|
3
|
+
import { mapNotificationRequest } from './utils/mapNotificationResponse';
|
|
3
4
|
/**
|
|
4
5
|
* Fetches information about all scheduled notifications.
|
|
5
6
|
* @return Returns a Promise resolving to an array of objects conforming to the [`Notification`](#notification) interface.
|
|
@@ -9,6 +10,6 @@ export default async function getAllScheduledNotificationsAsync() {
|
|
|
9
10
|
if (!NotificationScheduler.getAllScheduledNotificationsAsync) {
|
|
10
11
|
throw new UnavailabilityError('Notifications', 'getAllScheduledNotificationsAsync');
|
|
11
12
|
}
|
|
12
|
-
return await NotificationScheduler.getAllScheduledNotificationsAsync();
|
|
13
|
+
return (await NotificationScheduler.getAllScheduledNotificationsAsync()).map((request) => mapNotificationRequest(request));
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=getAllScheduledNotificationsAsync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAllScheduledNotificationsAsync.js","sourceRoot":"","sources":["../src/getAllScheduledNotificationsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"getAllScheduledNotificationsAsync.js","sourceRoot":"","sources":["../src/getAllScheduledNotificationsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEzE;;;;GAIG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,iCAAiC;IAC7D,IAAI,CAAC,qBAAqB,CAAC,iCAAiC,EAAE;QAC5D,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,mCAAmC,CAAC,CAAC;KACrF;IAED,OAAO,CAAC,MAAM,qBAAqB,CAAC,iCAAiC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACvF,sBAAsB,CAAC,OAAO,CAAC,CAChC,CAAC;AACJ,CAAC","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\n\nimport NotificationScheduler from './NotificationScheduler';\nimport { NotificationRequest } from './Notifications.types';\nimport { mapNotificationRequest } from './utils/mapNotificationResponse';\n\n/**\n * Fetches information about all scheduled notifications.\n * @return Returns a Promise resolving to an array of objects conforming to the [`Notification`](#notification) interface.\n * @header schedule\n */\nexport default async function getAllScheduledNotificationsAsync(): Promise<NotificationRequest[]> {\n if (!NotificationScheduler.getAllScheduledNotificationsAsync) {\n throw new UnavailabilityError('Notifications', 'getAllScheduledNotificationsAsync');\n }\n\n return (await NotificationScheduler.getAllScheduledNotificationsAsync()).map((request) =>\n mapNotificationRequest(request)\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPresentedNotificationsAsync.d.ts","sourceRoot":"","sources":["../src/getPresentedNotificationsAsync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"getPresentedNotificationsAsync.d.ts","sourceRoot":"","sources":["../src/getPresentedNotificationsAsync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGrD;;;;;GAKG;AACH,wBAA8B,8BAA8B,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAQtF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UnavailabilityError } from 'expo-modules-core';
|
|
2
2
|
import NotificationPresenter from './NotificationPresenterModule';
|
|
3
|
+
import { mapNotification } from './utils/mapNotificationResponse';
|
|
3
4
|
/**
|
|
4
5
|
* Fetches information about all notifications present in the notification tray (Notification Center).
|
|
5
6
|
* > This method is not supported on Android below 6.0 (API level 23) – on these devices it will resolve to an empty array.
|
|
@@ -10,6 +11,6 @@ export default async function getPresentedNotificationsAsync() {
|
|
|
10
11
|
if (!NotificationPresenter.getPresentedNotificationsAsync) {
|
|
11
12
|
throw new UnavailabilityError('Notifications', 'getPresentedNotificationsAsync');
|
|
12
13
|
}
|
|
13
|
-
return await NotificationPresenter.getPresentedNotificationsAsync();
|
|
14
|
+
return (await NotificationPresenter.getPresentedNotificationsAsync()).map((notification) => mapNotification(notification));
|
|
14
15
|
}
|
|
15
16
|
//# sourceMappingURL=getPresentedNotificationsAsync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPresentedNotificationsAsync.js","sourceRoot":"","sources":["../src/getPresentedNotificationsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"getPresentedNotificationsAsync.js","sourceRoot":"","sources":["../src/getPresentedNotificationsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,8BAA8B;IAC1D,IAAI,CAAC,qBAAqB,CAAC,8BAA8B,EAAE;QACzD,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,gCAAgC,CAAC,CAAC;KAClF;IAED,OAAO,CAAC,MAAM,qBAAqB,CAAC,8BAA8B,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CACzF,eAAe,CAAC,YAAY,CAAC,CAC9B,CAAC;AACJ,CAAC","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\n\nimport NotificationPresenter from './NotificationPresenterModule';\nimport { Notification } from './Notifications.types';\nimport { mapNotification } from './utils/mapNotificationResponse';\n\n/**\n * Fetches information about all notifications present in the notification tray (Notification Center).\n * > This method is not supported on Android below 6.0 (API level 23) – on these devices it will resolve to an empty array.\n * @return A Promise which resolves with a list of notifications ([`Notification`](#notification)) currently present in the notification tray (Notification Center).\n * @header dismiss\n */\nexport default async function getPresentedNotificationsAsync(): Promise<Notification[]> {\n if (!NotificationPresenter.getPresentedNotificationsAsync) {\n throw new UnavailabilityError('Notifications', 'getPresentedNotificationsAsync');\n }\n\n return (await NotificationPresenter.getPresentedNotificationsAsync()).map((notification) =>\n mapNotification(notification)\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Notification, NotificationResponse } from '../Notifications.types';
|
|
1
|
+
import { Notification, NotificationContent, NotificationRequest, NotificationResponse } from '../Notifications.types';
|
|
2
2
|
/**
|
|
3
3
|
* @hidden
|
|
4
4
|
*
|
|
@@ -10,12 +10,15 @@ import { Notification, NotificationResponse } from '../Notifications.types';
|
|
|
10
10
|
* @returns the mapped response.
|
|
11
11
|
*/
|
|
12
12
|
export declare const mapNotificationResponse: (response: NotificationResponse) => {
|
|
13
|
-
notification:
|
|
13
|
+
notification: {
|
|
14
14
|
request: {
|
|
15
|
-
content: {
|
|
16
|
-
dataString?: string;
|
|
15
|
+
content: NotificationContent & {
|
|
16
|
+
dataString?: string | undefined;
|
|
17
17
|
};
|
|
18
|
+
identifier: string;
|
|
19
|
+
trigger: import("../Notifications.types").NotificationTrigger;
|
|
18
20
|
};
|
|
21
|
+
date: number;
|
|
19
22
|
};
|
|
20
23
|
actionIdentifier: string;
|
|
21
24
|
userText?: string | undefined;
|
|
@@ -29,11 +32,41 @@ export declare const mapNotificationResponse: (response: NotificationResponse) =
|
|
|
29
32
|
* @param notification The raw notification passed in from native code
|
|
30
33
|
* @returns the mapped notification.
|
|
31
34
|
*/
|
|
32
|
-
export declare const mapNotification: (notification: Notification) =>
|
|
35
|
+
export declare const mapNotification: (notification: Notification) => {
|
|
33
36
|
request: {
|
|
34
|
-
content: {
|
|
35
|
-
dataString?: string;
|
|
37
|
+
content: NotificationContent & {
|
|
38
|
+
dataString?: string | undefined;
|
|
36
39
|
};
|
|
40
|
+
identifier: string;
|
|
41
|
+
trigger: import("../Notifications.types").NotificationTrigger;
|
|
37
42
|
};
|
|
43
|
+
date: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* @hidden
|
|
47
|
+
*
|
|
48
|
+
* Does any required processing of a notification request from native code
|
|
49
|
+
* before it is passed to other JS code.
|
|
50
|
+
*
|
|
51
|
+
* @param request The raw request passed in from native code
|
|
52
|
+
* @returns the mapped request.
|
|
53
|
+
*/
|
|
54
|
+
export declare const mapNotificationRequest: (request: NotificationRequest) => {
|
|
55
|
+
content: NotificationContent & {
|
|
56
|
+
dataString?: string | undefined;
|
|
57
|
+
};
|
|
58
|
+
identifier: string;
|
|
59
|
+
trigger: import("../Notifications.types").NotificationTrigger;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* @hidden
|
|
63
|
+
* Does any required processing of notification content from native code
|
|
64
|
+
* before being passed to other JS code.
|
|
65
|
+
*
|
|
66
|
+
* @param content The raw content passed in from native code
|
|
67
|
+
* @returns the mapped content.
|
|
68
|
+
*/
|
|
69
|
+
export declare const mapNotificationContent: (content: NotificationContent) => NotificationContent & {
|
|
70
|
+
dataString?: string | undefined;
|
|
38
71
|
};
|
|
39
72
|
//# sourceMappingURL=mapNotificationResponse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapNotificationResponse.d.ts","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"mapNotificationResponse.d.ts","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,aAAc,oBAAoB;;;;;;;;;;;;;CAKrE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,iBAAkB,YAAY;;;;;;;;;CAGxD,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,YAAa,mBAAmB;;;;;;CAGjE,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,YAAa,mBAAmB;;CAYlE,CAAC"}
|
|
@@ -23,18 +23,43 @@ export const mapNotificationResponse = (response) => {
|
|
|
23
23
|
* @param notification The raw notification passed in from native code
|
|
24
24
|
* @returns the mapped notification.
|
|
25
25
|
*/
|
|
26
|
-
export const mapNotification = (notification) => {
|
|
27
|
-
|
|
26
|
+
export const mapNotification = (notification) => ({
|
|
27
|
+
...notification,
|
|
28
|
+
request: mapNotificationRequest(notification.request),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* @hidden
|
|
32
|
+
*
|
|
33
|
+
* Does any required processing of a notification request from native code
|
|
34
|
+
* before it is passed to other JS code.
|
|
35
|
+
*
|
|
36
|
+
* @param request The raw request passed in from native code
|
|
37
|
+
* @returns the mapped request.
|
|
38
|
+
*/
|
|
39
|
+
export const mapNotificationRequest = (request) => ({
|
|
40
|
+
...request,
|
|
41
|
+
content: mapNotificationContent(request.content),
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* @hidden
|
|
45
|
+
* Does any required processing of notification content from native code
|
|
46
|
+
* before being passed to other JS code.
|
|
47
|
+
*
|
|
48
|
+
* @param content The raw content passed in from native code
|
|
49
|
+
* @returns the mapped content.
|
|
50
|
+
*/
|
|
51
|
+
export const mapNotificationContent = (content) => {
|
|
52
|
+
const mappedContent = { ...content };
|
|
28
53
|
try {
|
|
29
|
-
const dataString =
|
|
54
|
+
const dataString = mappedContent['dataString'];
|
|
30
55
|
if (typeof dataString === 'string') {
|
|
31
|
-
|
|
32
|
-
delete
|
|
56
|
+
mappedContent.data = JSON.parse(dataString);
|
|
57
|
+
delete mappedContent.dataString;
|
|
33
58
|
}
|
|
34
59
|
}
|
|
35
60
|
catch (e) {
|
|
36
61
|
console.log(`Error in notification: ${e}`);
|
|
37
62
|
}
|
|
38
|
-
return
|
|
63
|
+
return mappedContent;
|
|
39
64
|
};
|
|
40
65
|
//# sourceMappingURL=mapNotificationResponse.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapNotificationResponse.js","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mapNotificationResponse.js","sourceRoot":"","sources":["../../src/utils/mapNotificationResponse.ts"],"names":[],"mappings":"AAOA;;;;;;;;;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,CAAC,CAAC;IAC9D,GAAG,YAAY;IACf,OAAO,EAAE,sBAAsB,CAAC,YAAY,CAAC,OAAO,CAAC;CACtD,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAA4B,EAAE,EAAE,CAAC,CAAC;IACvE,GAAG,OAAO;IACV,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,OAAO,CAAC;CACjD,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAA4B,EAAE,EAAE;IACrE,MAAM,aAAa,GAAkD,EAAE,GAAG,OAAO,EAAE,CAAC;IACpF,IAAI;QACF,MAAM,UAAU,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YAClC,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC5C,OAAO,aAAa,CAAC,UAAU,CAAC;SACjC;KACF;IAAC,OAAO,CAAM,EAAE;QACf,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC;KAC5C;IACD,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC","sourcesContent":["import {\n Notification,\n NotificationContent,\n NotificationRequest,\n NotificationResponse,\n} 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 ...notification,\n request: mapNotificationRequest(notification.request),\n});\n\n/**\n * @hidden\n *\n * Does any required processing of a notification request from native code\n * before it is passed to other JS code.\n *\n * @param request The raw request passed in from native code\n * @returns the mapped request.\n */\nexport const mapNotificationRequest = (request: NotificationRequest) => ({\n ...request,\n content: mapNotificationContent(request.content),\n});\n\n/**\n * @hidden\n * Does any required processing of notification content from native code\n * before being passed to other JS code.\n *\n * @param content The raw content passed in from native code\n * @returns the mapped content.\n */\nexport const mapNotificationContent = (content: NotificationContent) => {\n const mappedContent: NotificationContent & { dataString?: string } = { ...content };\n try {\n const dataString = mappedContent['dataString'];\n if (typeof dataString === 'string') {\n mappedContent.data = JSON.parse(dataString);\n delete mappedContent.dataString;\n }\n } catch (e: any) {\n console.log(`Error in notification: ${e}`);\n }\n return mappedContent;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-notifications",
|
|
3
|
-
"version": "1.0.0-canary-
|
|
3
|
+
"version": "1.0.0-canary-20240904-69100c1",
|
|
4
4
|
"description": "Provides an API to fetch push notification tokens and to present, schedule, receive, and respond to notifications.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -38,18 +38,18 @@
|
|
|
38
38
|
"preset": "expo-module-scripts/ios"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@expo/image-utils": "0.5.2-canary-
|
|
41
|
+
"@expo/image-utils": "0.5.2-canary-20240904-69100c1",
|
|
42
42
|
"@ide/backoff": "^1.0.0",
|
|
43
43
|
"abort-controller": "^3.0.0",
|
|
44
44
|
"assert": "^2.0.0",
|
|
45
45
|
"badgin": "^1.1.5",
|
|
46
|
-
"expo-application": "6.0.0-canary-
|
|
47
|
-
"expo-constants": "17.0.0-canary-
|
|
46
|
+
"expo-application": "6.0.0-canary-20240904-69100c1",
|
|
47
|
+
"expo-constants": "17.0.0-canary-20240904-69100c1",
|
|
48
48
|
"fs-extra": "^9.1.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node-fetch": "^2.5.7",
|
|
52
|
-
"expo-module-scripts": "3.6.0-canary-
|
|
52
|
+
"expo-module-scripts": "3.6.0-canary-20240904-69100c1",
|
|
53
53
|
"memfs": "^3.2.0",
|
|
54
54
|
"node-fetch": "^2.6.7"
|
|
55
55
|
},
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"react": "*",
|
|
59
59
|
"react-native": "*"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "69100c1b099b707057c052ed8096e06cb208aca1"
|
|
62
62
|
}
|
|
@@ -2,6 +2,7 @@ import { UnavailabilityError } from 'expo-modules-core';
|
|
|
2
2
|
|
|
3
3
|
import NotificationScheduler from './NotificationScheduler';
|
|
4
4
|
import { NotificationRequest } from './Notifications.types';
|
|
5
|
+
import { mapNotificationRequest } from './utils/mapNotificationResponse';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Fetches information about all scheduled notifications.
|
|
@@ -13,5 +14,7 @@ export default async function getAllScheduledNotificationsAsync(): Promise<Notif
|
|
|
13
14
|
throw new UnavailabilityError('Notifications', 'getAllScheduledNotificationsAsync');
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
return await NotificationScheduler.getAllScheduledNotificationsAsync()
|
|
17
|
+
return (await NotificationScheduler.getAllScheduledNotificationsAsync()).map((request) =>
|
|
18
|
+
mapNotificationRequest(request)
|
|
19
|
+
);
|
|
17
20
|
}
|
|
@@ -2,6 +2,7 @@ import { UnavailabilityError } from 'expo-modules-core';
|
|
|
2
2
|
|
|
3
3
|
import NotificationPresenter from './NotificationPresenterModule';
|
|
4
4
|
import { Notification } from './Notifications.types';
|
|
5
|
+
import { mapNotification } from './utils/mapNotificationResponse';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Fetches information about all notifications present in the notification tray (Notification Center).
|
|
@@ -14,5 +15,7 @@ export default async function getPresentedNotificationsAsync(): Promise<Notifica
|
|
|
14
15
|
throw new UnavailabilityError('Notifications', 'getPresentedNotificationsAsync');
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
return await NotificationPresenter.getPresentedNotificationsAsync()
|
|
18
|
+
return (await NotificationPresenter.getPresentedNotificationsAsync()).map((notification) =>
|
|
19
|
+
mapNotification(notification)
|
|
20
|
+
);
|
|
18
21
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Notification,
|
|
3
|
+
NotificationContent,
|
|
4
|
+
NotificationRequest,
|
|
5
|
+
NotificationResponse,
|
|
6
|
+
} from '../Notifications.types';
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* @hidden
|
|
@@ -26,18 +31,43 @@ export const mapNotificationResponse = (response: NotificationResponse) => {
|
|
|
26
31
|
* @param notification The raw notification passed in from native code
|
|
27
32
|
* @returns the mapped notification.
|
|
28
33
|
*/
|
|
29
|
-
export const mapNotification = (notification: Notification) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
export const mapNotification = (notification: Notification) => ({
|
|
35
|
+
...notification,
|
|
36
|
+
request: mapNotificationRequest(notification.request),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @hidden
|
|
41
|
+
*
|
|
42
|
+
* Does any required processing of a notification request from native code
|
|
43
|
+
* before it is passed to other JS code.
|
|
44
|
+
*
|
|
45
|
+
* @param request The raw request passed in from native code
|
|
46
|
+
* @returns the mapped request.
|
|
47
|
+
*/
|
|
48
|
+
export const mapNotificationRequest = (request: NotificationRequest) => ({
|
|
49
|
+
...request,
|
|
50
|
+
content: mapNotificationContent(request.content),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @hidden
|
|
55
|
+
* Does any required processing of notification content from native code
|
|
56
|
+
* before being passed to other JS code.
|
|
57
|
+
*
|
|
58
|
+
* @param content The raw content passed in from native code
|
|
59
|
+
* @returns the mapped content.
|
|
60
|
+
*/
|
|
61
|
+
export const mapNotificationContent = (content: NotificationContent) => {
|
|
62
|
+
const mappedContent: NotificationContent & { dataString?: string } = { ...content };
|
|
33
63
|
try {
|
|
34
|
-
const dataString =
|
|
64
|
+
const dataString = mappedContent['dataString'];
|
|
35
65
|
if (typeof dataString === 'string') {
|
|
36
|
-
|
|
37
|
-
delete
|
|
66
|
+
mappedContent.data = JSON.parse(dataString);
|
|
67
|
+
delete mappedContent.dataString;
|
|
38
68
|
}
|
|
39
69
|
} catch (e: any) {
|
|
40
70
|
console.log(`Error in notification: ${e}`);
|
|
41
71
|
}
|
|
42
|
-
return
|
|
72
|
+
return mappedContent;
|
|
43
73
|
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
package expo.modules.notifications.notifications.interfaces;
|
|
2
|
-
|
|
3
|
-
import android.app.Notification;
|
|
4
|
-
|
|
5
|
-
import androidx.annotation.Nullable;
|
|
6
|
-
|
|
7
|
-
public interface NotificationPresentationEffect {
|
|
8
|
-
boolean onNotificationPresented(@Nullable String tag, int id, Notification notification);
|
|
9
|
-
|
|
10
|
-
boolean onNotificationPresentationFailed(@Nullable String tag, int id, Notification notification);
|
|
11
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
package expo.modules.notifications.notifications.interfaces;
|
|
2
|
-
|
|
3
|
-
public interface NotificationPresentationEffectsManager extends NotificationPresentationEffect {
|
|
4
|
-
void addEffect(NotificationPresentationEffect effector);
|
|
5
|
-
|
|
6
|
-
void removeEffect(NotificationPresentationEffect effector);
|
|
7
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
package expo.modules.notifications.notifications.model.triggers;
|
|
2
|
-
|
|
3
|
-
import android.os.Build;
|
|
4
|
-
import android.os.Parcel;
|
|
5
|
-
|
|
6
|
-
import com.google.firebase.messaging.RemoteMessage;
|
|
7
|
-
|
|
8
|
-
import androidx.annotation.Nullable;
|
|
9
|
-
import androidx.annotation.RequiresApi;
|
|
10
|
-
import expo.modules.notifications.notifications.interfaces.NotificationTrigger;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A trigger representing an incoming remote Firebase notification.
|
|
14
|
-
*/
|
|
15
|
-
public class FirebaseNotificationTrigger implements NotificationTrigger {
|
|
16
|
-
private RemoteMessage mRemoteMessage;
|
|
17
|
-
|
|
18
|
-
public FirebaseNotificationTrigger(RemoteMessage remoteMessage) {
|
|
19
|
-
mRemoteMessage = remoteMessage;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
private FirebaseNotificationTrigger(Parcel in) {
|
|
23
|
-
mRemoteMessage = in.readParcelable(getClass().getClassLoader());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public RemoteMessage getRemoteMessage() {
|
|
27
|
-
return mRemoteMessage;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@Override
|
|
31
|
-
public int describeContents() {
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@Override
|
|
36
|
-
public void writeToParcel(Parcel dest, int flags) {
|
|
37
|
-
dest.writeParcelable(mRemoteMessage, 0);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
public static final Creator<FirebaseNotificationTrigger> CREATOR = new Creator<FirebaseNotificationTrigger>() {
|
|
41
|
-
@Override
|
|
42
|
-
public FirebaseNotificationTrigger createFromParcel(Parcel in) {
|
|
43
|
-
return new FirebaseNotificationTrigger(in);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@Override
|
|
47
|
-
public FirebaseNotificationTrigger[] newArray(int size) {
|
|
48
|
-
return new FirebaseNotificationTrigger[size];
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
@Nullable
|
|
53
|
-
@Override
|
|
54
|
-
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
55
|
-
public String getNotificationChannel() {
|
|
56
|
-
if (getRemoteMessage().getData().containsKey("channelId")) {
|
|
57
|
-
return getRemoteMessage().getData().get("channelId");
|
|
58
|
-
}
|
|
59
|
-
return NotificationTrigger.super.getNotificationChannel();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
package expo.modules.notifications.notifications.presentation;
|
|
2
|
-
|
|
3
|
-
import android.app.Notification;
|
|
4
|
-
import android.util.Log;
|
|
5
|
-
|
|
6
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
7
|
-
|
|
8
|
-
import java.util.ArrayList;
|
|
9
|
-
import java.util.Collection;
|
|
10
|
-
import java.util.Collections;
|
|
11
|
-
import java.util.List;
|
|
12
|
-
|
|
13
|
-
import androidx.annotation.Nullable;
|
|
14
|
-
import expo.modules.notifications.notifications.interfaces.NotificationPresentationEffect;
|
|
15
|
-
import expo.modules.notifications.notifications.interfaces.NotificationPresentationEffectsManager;
|
|
16
|
-
|
|
17
|
-
public class ExpoNotificationPresentationEffectsManager implements InternalModule, NotificationPresentationEffectsManager {
|
|
18
|
-
private Collection<NotificationPresentationEffect> mEffects = new ArrayList<>();
|
|
19
|
-
|
|
20
|
-
@Override
|
|
21
|
-
public List<? extends Class> getExportedInterfaces() {
|
|
22
|
-
return Collections.singletonList(NotificationPresentationEffectsManager.class);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@Override
|
|
26
|
-
public void addEffect(NotificationPresentationEffect effect) {
|
|
27
|
-
removeEffect(effect);
|
|
28
|
-
mEffects.add(effect);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@Override
|
|
32
|
-
public void removeEffect(NotificationPresentationEffect effect) {
|
|
33
|
-
mEffects.remove(effect);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@Override
|
|
37
|
-
public boolean onNotificationPresented(@Nullable String tag, int id, Notification notification) {
|
|
38
|
-
boolean anyActed = false;
|
|
39
|
-
for (NotificationPresentationEffect effect : mEffects) {
|
|
40
|
-
try {
|
|
41
|
-
anyActed = effect.onNotificationPresented(tag, id, notification) || anyActed;
|
|
42
|
-
} catch (Exception e) {
|
|
43
|
-
Log.w("expo-notifications", String.format("Notification presentation effector %s threw an exception for notification (%s, %d): %s", effect.getClass(), tag, id, e.getMessage()));
|
|
44
|
-
e.printStackTrace();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return anyActed;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@Override
|
|
51
|
-
public boolean onNotificationPresentationFailed(@Nullable String tag, int id, Notification notification) {
|
|
52
|
-
boolean anyActed = false;
|
|
53
|
-
for (NotificationPresentationEffect effect : mEffects) {
|
|
54
|
-
try {
|
|
55
|
-
anyActed = effect.onNotificationPresentationFailed(tag, id, notification) || anyActed;
|
|
56
|
-
} catch (Exception e) {
|
|
57
|
-
Log.w("expo-notifications", String.format("Notification presentation effector %s threw an exception for notification (%s, %d): %s", effect.getClass(), tag, id, e.getMessage()));
|
|
58
|
-
e.printStackTrace();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return anyActed;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
package expo.modules.notifications.notifications.presentation.effects;
|
|
2
|
-
|
|
3
|
-
import android.app.Notification;
|
|
4
|
-
import android.content.Context;
|
|
5
|
-
|
|
6
|
-
import expo.modules.core.ModuleRegistry;
|
|
7
|
-
import expo.modules.core.interfaces.InternalModule;
|
|
8
|
-
|
|
9
|
-
import java.util.Collections;
|
|
10
|
-
import java.util.List;
|
|
11
|
-
|
|
12
|
-
import androidx.annotation.Nullable;
|
|
13
|
-
import expo.modules.notifications.notifications.interfaces.NotificationPresentationEffect;
|
|
14
|
-
import expo.modules.notifications.notifications.interfaces.NotificationPresentationEffectsManager;
|
|
15
|
-
|
|
16
|
-
public abstract class BaseNotificationEffect implements InternalModule, NotificationPresentationEffect {
|
|
17
|
-
private Context mContext;
|
|
18
|
-
private NotificationPresentationEffectsManager mManager;
|
|
19
|
-
|
|
20
|
-
public BaseNotificationEffect(Context context) {
|
|
21
|
-
mContext = context;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
protected Context getContext() {
|
|
25
|
-
return mContext;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@Override
|
|
29
|
-
public List<? extends Class> getExportedInterfaces() {
|
|
30
|
-
return Collections.singletonList(getClass());
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@Override
|
|
34
|
-
public void onCreate(ModuleRegistry moduleRegistry) {
|
|
35
|
-
mManager = moduleRegistry.getModule(NotificationPresentationEffectsManager.class);
|
|
36
|
-
mManager.addEffect(this);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@Override
|
|
40
|
-
public void onDestroy() {
|
|
41
|
-
mManager.removeEffect(this);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@Override
|
|
45
|
-
public boolean onNotificationPresented(@Nullable String tag, int id, Notification notification) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@Override
|
|
50
|
-
public boolean onNotificationPresentationFailed(@Nullable String tag, int id, Notification notification) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|