expo-notifications 0.15.3 → 0.16.1
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 +11 -7
- package/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/CategoryAwareNotificationBuilder.java +4 -0
- package/android/src/main/java/expo/modules/notifications/service/NotificationForwarderActivity.kt +3 -0
- package/android/src/main/java/expo/modules/notifications/service/NotificationsService.kt +1 -1
- package/android/src/main/java/expo/modules/notifications/service/delegates/ExpoHandlingDelegate.kt +15 -17
- package/build/getDevicePushTokenAsync.web.js +3 -11
- package/build/getDevicePushTokenAsync.web.js.map +1 -1
- package/build/getExpoPushTokenAsync.d.ts.map +1 -1
- package/build/getExpoPushTokenAsync.js +1 -4
- package/build/getExpoPushTokenAsync.js.map +1 -1
- package/ios/EXNotifications.xcframework/ios-arm64/EXNotifications.framework/EXNotifications +0 -0
- package/ios/EXNotifications.xcframework/ios-arm64/EXNotifications.framework/Info.plist +0 -0
- package/ios/EXNotifications.xcframework/ios-arm64_x86_64-simulator/EXNotifications.framework/EXNotifications +0 -0
- package/ios/EXNotifications.xcframework/ios-arm64_x86_64-simulator/EXNotifications.framework/Info.plist +0 -0
- package/package.json +5 -5
- package/plugin/build/withNotifications.d.ts +6 -3
- package/plugin/src/withNotifications.ts +6 -3
- package/src/getDevicePushTokenAsync.web.ts +5 -15
- package/src/getExpoPushTokenAsync.ts +1 -4
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,20 +10,24 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
-
## 0.
|
|
13
|
+
## 0.16.1 — 2022-07-16
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
- Fixed Android data-only FCM notifications (i.e. notifications without a title and message) appearing in the notification drawer ([#17707](https://github.com/expo/expo/pull/17707) by [@sausti](https://github.com/sausti))
|
|
19
|
-
- Add support for unregistering from push notifications on Android and iOS ([#17812](https://github.com/expo/expo/pull/17812) by [@sausti](https://github.com/sausti))
|
|
20
|
-
- Fix another Android 12+ trampoline issue from push notifications. ([#17871](https://github.com/expo/expo/pull/17871) by [@kudo](https://github.com/kudo))
|
|
17
|
+
## 0.16.0 — 2022-07-07
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
### 🛠 Breaking changes
|
|
20
|
+
|
|
21
|
+
- [android] Set the "notification number" (sometimes used to increment badge count on some launchers) from the notification payload `badge` field. ([#17171](https://github.com/expo/expo/pull/17171) by [@danstepanov](https://github.com/danstepanov))
|
|
23
22
|
|
|
24
23
|
### 🐛 Bug fixes
|
|
25
24
|
|
|
26
25
|
- Fixed Android 12+ runtime crash caused by `PendingIntent` misconfiguration. ([#17333](https://github.com/expo/expo/pull/17333) by [@kudo](https://github.com/kudo))
|
|
26
|
+
- Fix app not bringing to foreground when clicking notification on Android 12+. ([#17686](https://github.com/expo/expo/pull/17686) by [@kudo](https://github.com/kudo))
|
|
27
|
+
- Fixed Android data-only FCM notifications (i.e. notifications without a title and message) appearing in the notification drawer ([#17707](https://github.com/expo/expo/pull/17707) by [@sausti](https://github.com/sausti))
|
|
28
|
+
- Add support for unregistering from push notifications on Android and iOS ([#17812](https://github.com/expo/expo/pull/17812) by [@sausti](https://github.com/sausti))
|
|
29
|
+
- Fix another Android 12+ trampoline issue from push notifications. ([#17871](https://github.com/expo/expo/pull/17871) by [@kudo](https://github.com/kudo))
|
|
30
|
+
- Fixed `useLastNotificationResponse` returns latest received notification but not the clicked notification on Android. ([#17974](https://github.com/expo/expo/pull/17974) by [@kudo](https://github.com/kudo))
|
|
27
31
|
|
|
28
32
|
### ⚠️ Notices
|
|
29
33
|
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '0.
|
|
6
|
+
version = '0.16.1'
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
9
9
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -74,7 +74,7 @@ android {
|
|
|
74
74
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
75
75
|
targetSdkVersion safeExtGet("targetSdkVersion", 31)
|
|
76
76
|
versionCode 21
|
|
77
|
-
versionName '0.
|
|
77
|
+
versionName '0.16.1'
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
lintOptions {
|
|
@@ -36,6 +36,10 @@ public class CategoryAwareNotificationBuilder extends ExpoNotificationBuilder {
|
|
|
36
36
|
if (categoryIdentifier != null) {
|
|
37
37
|
addActionsToBuilder(builder, categoryIdentifier);
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
if (content.getBadgeCount() != null) {
|
|
41
|
+
builder.setNumber(content.getBadgeCount().intValue());
|
|
42
|
+
}
|
|
39
43
|
|
|
40
44
|
return builder;
|
|
41
45
|
}
|
package/android/src/main/java/expo/modules/notifications/service/NotificationForwarderActivity.kt
CHANGED
|
@@ -4,6 +4,7 @@ import android.app.Activity
|
|
|
4
4
|
import android.content.Intent
|
|
5
5
|
import android.os.Bundle
|
|
6
6
|
import expo.modules.notifications.BuildConfig
|
|
7
|
+
import expo.modules.notifications.service.delegates.ExpoHandlingDelegate
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* An internal Activity that passes given Intent extras from
|
|
@@ -15,6 +16,8 @@ class NotificationForwarderActivity : Activity() {
|
|
|
15
16
|
super.onCreate(savedInstanceState)
|
|
16
17
|
val broadcastIntent =
|
|
17
18
|
NotificationsService.createNotificationResponseBroadcastIntent(applicationContext, intent.extras)
|
|
19
|
+
val notificationResponse = NotificationsService.getNotificationResponseFromBroadcastIntent(broadcastIntent)
|
|
20
|
+
ExpoHandlingDelegate.openAppToForeground(this, notificationResponse)
|
|
18
21
|
sendBroadcast(broadcastIntent)
|
|
19
22
|
finish()
|
|
20
23
|
}
|
|
@@ -454,7 +454,7 @@ open class NotificationsService : BroadcastReceiver() {
|
|
|
454
454
|
// [notification trampolines](https://developer.android.com/about/versions/12/behavior-changes-12#identify-notification-trampolines)
|
|
455
455
|
// are not allowed. If the notification wants to open foreground app,
|
|
456
456
|
// we should use the dedicated Activity pendingIntent.
|
|
457
|
-
if (
|
|
457
|
+
if (action.opensAppToForeground()) {
|
|
458
458
|
val notificationResponse = getNotificationResponseFromBroadcastIntent(intent)
|
|
459
459
|
return ExpoHandlingDelegate.createPendingIntentForOpeningApp(context, intent, notificationResponse)
|
|
460
460
|
}
|
package/android/src/main/java/expo/modules/notifications/service/delegates/ExpoHandlingDelegate.kt
CHANGED
|
@@ -67,15 +67,23 @@ class ExpoHandlingDelegate(protected val context: Context) : HandlingDelegate {
|
|
|
67
67
|
// For intent with RemoteInput, it should be mutable.
|
|
68
68
|
intentFlags = intentFlags or PendingIntent.FLAG_MUTABLE
|
|
69
69
|
}
|
|
70
|
-
|
|
71
|
-
Log.w("expo-notifications", "No launch intent found for application. Interacting with the notification won't open the app. The implementation uses `getLaunchIntentForPackage` to find appropriate activity.")
|
|
72
|
-
Intent()
|
|
73
|
-
}
|
|
74
|
-
foregroundActivityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
|
75
|
-
NotificationsService.setNotificationResponseToIntent(foregroundActivityIntent, notificationResponse)
|
|
70
|
+
|
|
76
71
|
val backgroundActivityIntent = Intent(context, NotificationForwarderActivity::class.java)
|
|
72
|
+
backgroundActivityIntent.data = broadcastIntent.data
|
|
73
|
+
backgroundActivityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
|
77
74
|
backgroundActivityIntent.putExtras(broadcastIntent)
|
|
78
|
-
|
|
75
|
+
val requestCode = broadcastIntent.component?.className?.hashCode() ?: NotificationsService::class.java.hashCode()
|
|
76
|
+
return PendingIntent.getActivity(context, requestCode, backgroundActivityIntent, intentFlags)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fun openAppToForeground(context: Context, notificationResponse: NotificationResponse) {
|
|
80
|
+
(getNotificationActionLauncher(context) ?: getMainActivityLauncher(context))?.let { intent ->
|
|
81
|
+
NotificationsService.setNotificationResponseToIntent(intent, notificationResponse)
|
|
82
|
+
context.startActivity(intent)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Log.w("expo-notifications", "No launch intent found for application. Interacting with the notification won't open the app. The implementation uses `getLaunchIntentForPackage` to find appropriate activity.")
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
private fun getNotificationActionLauncher(context: Context): Intent? {
|
|
@@ -130,16 +138,6 @@ class ExpoHandlingDelegate(protected val context: Context) : HandlingDelegate {
|
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
protected fun openAppToForeground(context: Context, notificationResponse: NotificationResponse) {
|
|
134
|
-
(getNotificationActionLauncher(context) ?: getMainActivityLauncher(context))?.let { intent ->
|
|
135
|
-
NotificationsService.setNotificationResponseToIntent(intent, notificationResponse)
|
|
136
|
-
context.startActivity(intent)
|
|
137
|
-
return
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
Log.w("expo-notifications", "No launch intent found for application. Interacting with the notification won't open the app. The implementation uses `getLaunchIntentForPackage` to find appropriate activity.")
|
|
141
|
-
}
|
|
142
|
-
|
|
143
141
|
override fun handleNotificationsDropped() {
|
|
144
142
|
getListeners().forEach {
|
|
145
143
|
it.onNotificationsDropped()
|
|
@@ -17,19 +17,13 @@ function guardPermission() {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
async function _subscribeDeviceToPushNotificationsAsync() {
|
|
20
|
-
const vapidPublicKey =
|
|
21
20
|
// @ts-expect-error: TODO: not on the schema
|
|
22
|
-
Constants.
|
|
23
|
-
// @ts-expect-error: TODO: not on the schema
|
|
24
|
-
Constants.manifest2?.extra?.expoClient?.notification?.vapidPublicKey;
|
|
21
|
+
const vapidPublicKey = Constants.expoConfig?.notification?.vapidPublicKey;
|
|
25
22
|
if (!vapidPublicKey) {
|
|
26
23
|
throw new CodedError('ERR_NOTIFICATIONS_PUSH_WEB_MISSING_CONFIG', 'You must provide `notification.vapidPublicKey` in `app.json` to use push notifications on web. Learn more: https://docs.expo.dev/versions/latest/guides/using-vapid/.');
|
|
27
24
|
}
|
|
28
|
-
const serviceWorkerPath =
|
|
29
25
|
// @ts-expect-error: TODO: not on the schema
|
|
30
|
-
Constants.
|
|
31
|
-
// @ts-expect-error: TODO: not on the schema
|
|
32
|
-
Constants.manifest2?.extra?.expoClient?.notification?.serviceWorkerPath;
|
|
26
|
+
const serviceWorkerPath = Constants.expoConfig?.notification?.serviceWorkerPath;
|
|
33
27
|
if (!serviceWorkerPath) {
|
|
34
28
|
throw new CodedError('ERR_NOTIFICATIONS_PUSH_MISSING_CONFIGURATION', 'You must specify `notification.serviceWorkerPath` in `app.json` to use push notifications on the web. Please provide the path to the service worker that will handle notifications.');
|
|
35
29
|
}
|
|
@@ -71,9 +65,7 @@ async function _subscribeDeviceToPushNotificationsAsync() {
|
|
|
71
65
|
// We wrap it with `fromExpoWebClient` to make sure other message
|
|
72
66
|
// will not override content such as `notificationIcon`.
|
|
73
67
|
// https://stackoverflow.com/a/35729334/2603230
|
|
74
|
-
const notificationIcon = (Constants.
|
|
75
|
-
Constants.manifest2?.extra?.expoClient?.notification ??
|
|
76
|
-
{}).icon;
|
|
68
|
+
const notificationIcon = (Constants.expoConfig?.notification ?? {}).icon;
|
|
77
69
|
await registration.active.postMessage(JSON.stringify({ fromExpoWebClient: { notificationIcon } }));
|
|
78
70
|
return subscriptionObject;
|
|
79
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDevicePushTokenAsync.web.js","sourceRoot":"","sources":["../src/getDevicePushTokenAsync.web.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAInF,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,uBAAuB;IACnD,MAAM,IAAI,GAAG,MAAM,wCAAwC,EAAE,CAAC;IAC9D,wBAAwB,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC,CAAC,cAAc,IAAI,MAAM,CAAC,EAAE;QAC/B,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,4DAA4D,CAC7D,CAAC;KACH;IACD,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE;QAC5B,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,mKAAmK,CACpK,CAAC;KACH;IACD,IAAI,YAAY,CAAC,UAAU,KAAK,SAAS,EAAE;QACzC,MAAM,IAAI,UAAU,CAClB,qCAAqC,EACrC,wGAAwG,CACzG,CAAC;KACH;AACH,CAAC;AAED,KAAK,UAAU,wCAAwC;IACrD,
|
|
1
|
+
{"version":3,"file":"getDevicePushTokenAsync.web.js","sourceRoot":"","sources":["../src/getDevicePushTokenAsync.web.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants from 'expo-constants';\nimport { CodedError, Platform, SyntheticPlatformEmitter } from 'expo-modules-core';\n\nimport { DevicePushToken } from './Tokens.types';\n\nexport default async function getDevicePushTokenAsync(): Promise<DevicePushToken> {\n const data = await _subscribeDeviceToPushNotificationsAsync();\n SyntheticPlatformEmitter.emit('onDevicePushToken', { devicePushToken: data });\n return { type: Platform.OS, data };\n}\n\nfunction guardPermission() {\n if (!('Notification' in window)) {\n throw new CodedError(\n 'ERR_UNAVAILABLE',\n 'The Web Notifications API is not available on this device.'\n );\n }\n if (!navigator.serviceWorker) {\n throw new CodedError(\n 'ERR_UNAVAILABLE',\n 'Notifications cannot be used because the service worker API is not supported on this device. This might also happen because your web page does not support HTTPS.'\n );\n }\n if (Notification.permission !== 'granted') {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PERMISSION_DENIED',\n `Cannot use web notifications without permissions granted. Request permissions with \"expo-permissions\".`\n );\n }\n}\n\nasync function _subscribeDeviceToPushNotificationsAsync(): Promise<DevicePushToken['data']> {\n // @ts-expect-error: TODO: not on the schema\n const vapidPublicKey: string | null = Constants.expoConfig?.notification?.vapidPublicKey;\n if (!vapidPublicKey) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PUSH_WEB_MISSING_CONFIG',\n 'You must provide `notification.vapidPublicKey` in `app.json` to use push notifications on web. Learn more: https://docs.expo.dev/versions/latest/guides/using-vapid/.'\n );\n }\n\n // @ts-expect-error: TODO: not on the schema\n const serviceWorkerPath = Constants.expoConfig?.notification?.serviceWorkerPath;\n if (!serviceWorkerPath) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PUSH_MISSING_CONFIGURATION',\n 'You must specify `notification.serviceWorkerPath` in `app.json` to use push notifications on the web. Please provide the path to the service worker that will handle notifications.'\n );\n }\n guardPermission();\n\n let registration: ServiceWorkerRegistration | null = null;\n try {\n registration = await navigator.serviceWorker.register(serviceWorkerPath);\n } catch (error) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PUSH_REGISTRATION_FAILED',\n `Could not register this device for push notifications because the service worker (${serviceWorkerPath}) could not be registered: ${error}`\n );\n }\n await navigator.serviceWorker.ready;\n\n if (!registration.active) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PUSH_REGISTRATION_FAILED',\n 'Could not register this device for push notifications because the service worker is not active.'\n );\n }\n\n const subscribeOptions = {\n userVisibleOnly: true,\n applicationServerKey: _urlBase64ToUint8Array(vapidPublicKey),\n };\n let pushSubscription: PushSubscription | null = null;\n try {\n pushSubscription = await registration.pushManager.subscribe(subscribeOptions);\n } catch (error) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_PUSH_REGISTRATION_FAILED',\n 'The device was unable to register for remote notifications with the browser endpoint. (' +\n error +\n ')'\n );\n }\n const pushSubscriptionJson = pushSubscription.toJSON();\n\n const subscriptionObject = {\n endpoint: pushSubscriptionJson.endpoint,\n keys: {\n p256dh: pushSubscriptionJson.keys!.p256dh,\n auth: pushSubscriptionJson.keys!.auth,\n },\n };\n\n // Store notification icon string in service worker.\n // This message is received by `/expo-service-worker.js`.\n // We wrap it with `fromExpoWebClient` to make sure other message\n // will not override content such as `notificationIcon`.\n // https://stackoverflow.com/a/35729334/2603230\n const notificationIcon = (Constants.expoConfig?.notification ?? {}).icon;\n await registration.active.postMessage(\n JSON.stringify({ fromExpoWebClient: { notificationIcon } })\n );\n\n return subscriptionObject;\n}\n\n// https://github.com/web-push-libs/web-push#using-vapid-key-for-applicationserverkey\nfunction _urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n\n const rawData = window.atob(base64);\n const outputArray = new Uint8Array(rawData.length);\n\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i);\n }\n return outputArray;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getExpoPushTokenAsync.d.ts","sourceRoot":"","sources":["../src/getExpoPushTokenAsync.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAKhE,UAAU,OAAO;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,GAAG,CAAC,EAAE,MAAM,CAAC;IAGb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,wBAA8B,qBAAqB,CAAC,OAAO,GAAE,OAAY,GAAG,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"getExpoPushTokenAsync.d.ts","sourceRoot":"","sources":["../src/getExpoPushTokenAsync.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAKhE,UAAU,OAAO;IAEf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,GAAG,CAAC,EAAE,MAAM,CAAC;IAGb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,wBAA8B,qBAAqB,CAAC,OAAO,GAAE,OAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CA0FjG"}
|
|
@@ -8,10 +8,7 @@ const productionBaseUrl = 'https://exp.host/--/api/v2/';
|
|
|
8
8
|
export default async function getExpoPushTokenAsync(options = {}) {
|
|
9
9
|
const devicePushToken = options.devicePushToken || (await getDevicePushTokenAsync());
|
|
10
10
|
const deviceId = options.deviceId || (await getDeviceIdAsync());
|
|
11
|
-
const experienceId = options.experienceId ||
|
|
12
|
-
Constants.manifest?.originalFullName ||
|
|
13
|
-
Constants.manifest2?.extra?.expoClient?.originalFullName ||
|
|
14
|
-
Constants.manifest?.id;
|
|
11
|
+
const experienceId = options.experienceId || Constants.expoConfig?.originalFullName || Constants.manifest?.id;
|
|
15
12
|
const projectId = options.projectId ||
|
|
16
13
|
Constants.manifest2?.extra?.eas?.projectId ||
|
|
17
14
|
Constants.manifest?.projectId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getExpoPushTokenAsync.js","sourceRoot":"","sources":["../src/getExpoPushTokenAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Application from 'expo-application';\nimport Constants from 'expo-constants';\nimport { Platform, CodedError, UnavailabilityError } from 'expo-modules-core';\n\nimport { setAutoServerRegistrationEnabledAsync } from './DevicePushTokenAutoRegistration.fx';\nimport ServerRegistrationModule from './ServerRegistrationModule';\nimport { DevicePushToken, ExpoPushToken } from './Tokens.types';\nimport getDevicePushTokenAsync from './getDevicePushTokenAsync';\n\nconst productionBaseUrl = 'https://exp.host/--/api/v2/';\n\ninterface Options {\n // Endpoint URL override\n baseUrl?: string;\n\n // Request URL override\n url?: string;\n\n // Request body overrides\n type?: string;\n deviceId?: string;\n development?: boolean;\n experienceId?: string;\n projectId?: string;\n applicationId?: string;\n devicePushToken?: DevicePushToken;\n}\n\nexport default async function getExpoPushTokenAsync(options: Options = {}): Promise<ExpoPushToken> {\n const devicePushToken = options.devicePushToken || (await getDevicePushTokenAsync());\n\n const deviceId = options.deviceId || (await getDeviceIdAsync());\n\n const experienceId =\n options.experienceId ||\n Constants.manifest?.originalFullName ||\n Constants.manifest2?.extra?.expoClient?.originalFullName ||\n Constants.manifest?.id;\n\n const projectId =\n options.projectId ||\n Constants.manifest2?.extra?.eas?.projectId ||\n Constants.manifest?.projectId;\n\n if (!experienceId && !projectId) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NO_EXPERIENCE_ID',\n \"No experienceId or projectId found. If one or the other can't be inferred from the manifest (eg. in bare workflow), you have to pass one in yourself.\"\n );\n }\n\n const applicationId = options.applicationId || Application.applicationId;\n if (!applicationId) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NO_APPLICATION_ID',\n \"No applicationId found. If it can't be inferred from native configuration by expo-application, you have to pass it in yourself.\"\n );\n }\n const type = options.type || getTypeOfToken(devicePushToken);\n const development = options.development || (await shouldUseDevelopmentNotificationService());\n\n const baseUrl = options.baseUrl ?? productionBaseUrl;\n const url = options.url ?? `${baseUrl}push/getExpoPushToken`;\n\n const body = {\n type,\n deviceId: deviceId.toLowerCase(),\n development,\n appId: applicationId,\n deviceToken: getDeviceToken(devicePushToken),\n ...(projectId ? { projectId } : { experienceId }),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n }).catch((error) => {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NETWORK_ERROR',\n `Error encountered while fetching Expo token: ${error}.`\n );\n });\n\n if (!response.ok) {\n const statusInfo = response.statusText || response.status;\n let body: string | undefined = undefined;\n try {\n body = await response.text();\n } catch {\n // do nothing\n }\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Error encountered while fetching Expo token, expected an OK response, received: ${statusInfo} (body: \"${body}\").`\n );\n }\n\n const expoPushToken = getExpoPushToken(await parseResponse(response));\n\n try {\n if (options.url || options.baseUrl) {\n console.debug(\n `[expo-notifications] Since the URL endpoint to register in has been customized in the options, expo-notifications won't try to auto-update the device push token on the server.`\n );\n } else {\n await setAutoServerRegistrationEnabledAsync(true);\n }\n } catch (e) {\n console.warn(\n '[expo-notifications] Could not enable automatically registering new device tokens with the Expo notification service',\n e\n );\n }\n\n return {\n type: 'expo',\n data: expoPushToken,\n };\n}\n\nasync function parseResponse(response: Response) {\n try {\n return await response.json();\n } catch {\n try {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Expected a JSON response from server when fetching Expo token, received body: ${JSON.stringify(\n await response.text()\n )}.`\n );\n } catch {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Expected a JSON response from server when fetching Expo token, received response: ${JSON.stringify(\n response\n )}.`\n );\n }\n }\n}\n\nfunction getExpoPushToken(data: any) {\n if (\n !data ||\n !(typeof data === 'object') ||\n !data.data ||\n !(typeof data.data === 'object') ||\n !data.data.expoPushToken ||\n !(typeof data.data.expoPushToken === 'string')\n ) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Malformed response from server, expected \"{ data: { expoPushToken: string } }\", received: ${JSON.stringify(\n data,\n null,\n 2\n )}.`\n );\n }\n\n return data.data.expoPushToken as string;\n}\n\n// Same as in DevicePushTokenAutoRegistration\nasync function getDeviceIdAsync() {\n try {\n if (!ServerRegistrationModule.getInstallationIdAsync) {\n throw new UnavailabilityError('ExpoServerRegistrationModule', 'getInstallationIdAsync');\n }\n\n return await ServerRegistrationModule.getInstallationIdAsync();\n } catch (e) {\n throw new CodedError(\n 'ERR_NOTIF_DEVICE_ID',\n `Could not have fetched installation ID of the application: ${e}.`\n );\n }\n}\n\nfunction getDeviceToken(devicePushToken: DevicePushToken) {\n if (typeof devicePushToken.data === 'string') {\n return devicePushToken.data;\n }\n\n return JSON.stringify(devicePushToken.data);\n}\n\n// Same as in DevicePushTokenAutoRegistration\nasync function shouldUseDevelopmentNotificationService() {\n if (Platform.OS === 'ios') {\n try {\n const notificationServiceEnvironment =\n await Application.getIosPushNotificationServiceEnvironmentAsync();\n if (notificationServiceEnvironment === 'development') {\n return true;\n }\n } catch {\n // We can't do anything here, we'll fallback to false then.\n }\n }\n\n return false;\n}\n\n// Same as in DevicePushTokenAutoRegistration\nfunction getTypeOfToken(devicePushToken: DevicePushToken) {\n switch (devicePushToken.type) {\n case 'ios':\n return 'apns';\n case 'android':\n return 'fcm';\n // This probably will error on server, but let's make this function future-safe.\n default:\n return devicePushToken.type;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"getExpoPushTokenAsync.js","sourceRoot":"","sources":["../src/getExpoPushTokenAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Application from 'expo-application';\nimport Constants from 'expo-constants';\nimport { Platform, CodedError, UnavailabilityError } from 'expo-modules-core';\n\nimport { setAutoServerRegistrationEnabledAsync } from './DevicePushTokenAutoRegistration.fx';\nimport ServerRegistrationModule from './ServerRegistrationModule';\nimport { DevicePushToken, ExpoPushToken } from './Tokens.types';\nimport getDevicePushTokenAsync from './getDevicePushTokenAsync';\n\nconst productionBaseUrl = 'https://exp.host/--/api/v2/';\n\ninterface Options {\n // Endpoint URL override\n baseUrl?: string;\n\n // Request URL override\n url?: string;\n\n // Request body overrides\n type?: string;\n deviceId?: string;\n development?: boolean;\n experienceId?: string;\n projectId?: string;\n applicationId?: string;\n devicePushToken?: DevicePushToken;\n}\n\nexport default async function getExpoPushTokenAsync(options: Options = {}): Promise<ExpoPushToken> {\n const devicePushToken = options.devicePushToken || (await getDevicePushTokenAsync());\n\n const deviceId = options.deviceId || (await getDeviceIdAsync());\n\n const experienceId =\n options.experienceId || Constants.expoConfig?.originalFullName || Constants.manifest?.id;\n\n const projectId =\n options.projectId ||\n Constants.manifest2?.extra?.eas?.projectId ||\n Constants.manifest?.projectId;\n\n if (!experienceId && !projectId) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NO_EXPERIENCE_ID',\n \"No experienceId or projectId found. If one or the other can't be inferred from the manifest (eg. in bare workflow), you have to pass one in yourself.\"\n );\n }\n\n const applicationId = options.applicationId || Application.applicationId;\n if (!applicationId) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NO_APPLICATION_ID',\n \"No applicationId found. If it can't be inferred from native configuration by expo-application, you have to pass it in yourself.\"\n );\n }\n const type = options.type || getTypeOfToken(devicePushToken);\n const development = options.development || (await shouldUseDevelopmentNotificationService());\n\n const baseUrl = options.baseUrl ?? productionBaseUrl;\n const url = options.url ?? `${baseUrl}push/getExpoPushToken`;\n\n const body = {\n type,\n deviceId: deviceId.toLowerCase(),\n development,\n appId: applicationId,\n deviceToken: getDeviceToken(devicePushToken),\n ...(projectId ? { projectId } : { experienceId }),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n }).catch((error) => {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_NETWORK_ERROR',\n `Error encountered while fetching Expo token: ${error}.`\n );\n });\n\n if (!response.ok) {\n const statusInfo = response.statusText || response.status;\n let body: string | undefined = undefined;\n try {\n body = await response.text();\n } catch {\n // do nothing\n }\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Error encountered while fetching Expo token, expected an OK response, received: ${statusInfo} (body: \"${body}\").`\n );\n }\n\n const expoPushToken = getExpoPushToken(await parseResponse(response));\n\n try {\n if (options.url || options.baseUrl) {\n console.debug(\n `[expo-notifications] Since the URL endpoint to register in has been customized in the options, expo-notifications won't try to auto-update the device push token on the server.`\n );\n } else {\n await setAutoServerRegistrationEnabledAsync(true);\n }\n } catch (e) {\n console.warn(\n '[expo-notifications] Could not enable automatically registering new device tokens with the Expo notification service',\n e\n );\n }\n\n return {\n type: 'expo',\n data: expoPushToken,\n };\n}\n\nasync function parseResponse(response: Response) {\n try {\n return await response.json();\n } catch {\n try {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Expected a JSON response from server when fetching Expo token, received body: ${JSON.stringify(\n await response.text()\n )}.`\n );\n } catch {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Expected a JSON response from server when fetching Expo token, received response: ${JSON.stringify(\n response\n )}.`\n );\n }\n }\n}\n\nfunction getExpoPushToken(data: any) {\n if (\n !data ||\n !(typeof data === 'object') ||\n !data.data ||\n !(typeof data.data === 'object') ||\n !data.data.expoPushToken ||\n !(typeof data.data.expoPushToken === 'string')\n ) {\n throw new CodedError(\n 'ERR_NOTIFICATIONS_SERVER_ERROR',\n `Malformed response from server, expected \"{ data: { expoPushToken: string } }\", received: ${JSON.stringify(\n data,\n null,\n 2\n )}.`\n );\n }\n\n return data.data.expoPushToken as string;\n}\n\n// Same as in DevicePushTokenAutoRegistration\nasync function getDeviceIdAsync() {\n try {\n if (!ServerRegistrationModule.getInstallationIdAsync) {\n throw new UnavailabilityError('ExpoServerRegistrationModule', 'getInstallationIdAsync');\n }\n\n return await ServerRegistrationModule.getInstallationIdAsync();\n } catch (e) {\n throw new CodedError(\n 'ERR_NOTIF_DEVICE_ID',\n `Could not have fetched installation ID of the application: ${e}.`\n );\n }\n}\n\nfunction getDeviceToken(devicePushToken: DevicePushToken) {\n if (typeof devicePushToken.data === 'string') {\n return devicePushToken.data;\n }\n\n return JSON.stringify(devicePushToken.data);\n}\n\n// Same as in DevicePushTokenAutoRegistration\nasync function shouldUseDevelopmentNotificationService() {\n if (Platform.OS === 'ios') {\n try {\n const notificationServiceEnvironment =\n await Application.getIosPushNotificationServiceEnvironmentAsync();\n if (notificationServiceEnvironment === 'development') {\n return true;\n }\n } catch {\n // We can't do anything here, we'll fallback to false then.\n }\n }\n\n return false;\n}\n\n// Same as in DevicePushTokenAutoRegistration\nfunction getTypeOfToken(devicePushToken: DevicePushToken) {\n switch (devicePushToken.type) {\n case 'ios':\n return 'apns';\n case 'android':\n return 'fcm';\n // This probably will error on server, but let's make this function future-safe.\n default:\n return devicePushToken.type;\n }\n}\n"]}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-notifications",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Notifications module",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"preset": "expo-module-scripts/ios"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@expo/config-plugins": "
|
|
40
|
+
"@expo/config-plugins": "~5.0.0",
|
|
41
41
|
"@expo/image-utils": "^0.3.18",
|
|
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": "~4.
|
|
47
|
-
"expo-constants": "~13.
|
|
46
|
+
"expo-application": "~4.2.0",
|
|
47
|
+
"expo-constants": "~13.2.0",
|
|
48
48
|
"fs-extra": "^9.1.0",
|
|
49
49
|
"uuid": "^3.4.0"
|
|
50
50
|
},
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"expo": "*"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "c6678c65b68e45062d49a2deea8e822f69388278"
|
|
62
62
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { ConfigPlugin } from '@expo/config-plugins';
|
|
2
2
|
export declare type NotificationsPluginProps = {
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Local path to an image to use as the icon for push notifications.
|
|
5
5
|
* 96x96 all-white png with transparency. We recommend following
|
|
6
6
|
* [Google's design guidelines](https://material.io/design/iconography/product-icons.html#design-principles).
|
|
7
|
+
* @platform android
|
|
7
8
|
*/
|
|
8
9
|
icon?: string;
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
+
* Tint color for the push notification image when it appears in the notification tray.
|
|
11
12
|
* @default '#ffffff'
|
|
13
|
+
* @platform android
|
|
12
14
|
*/
|
|
13
15
|
color?: string;
|
|
14
16
|
/**
|
|
@@ -16,8 +18,9 @@ export declare type NotificationsPluginProps = {
|
|
|
16
18
|
*/
|
|
17
19
|
sounds?: string[];
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
21
|
+
* Environment of the app: either 'development' or 'production'.
|
|
20
22
|
* @default 'development'
|
|
23
|
+
* @platform ios
|
|
21
24
|
*/
|
|
22
25
|
mode?: 'development' | 'production';
|
|
23
26
|
};
|
|
@@ -7,14 +7,16 @@ const pkg = require('expo-notifications/package.json');
|
|
|
7
7
|
|
|
8
8
|
export type NotificationsPluginProps = {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Local path to an image to use as the icon for push notifications.
|
|
11
11
|
* 96x96 all-white png with transparency. We recommend following
|
|
12
12
|
* [Google's design guidelines](https://material.io/design/iconography/product-icons.html#design-principles).
|
|
13
|
+
* @platform android
|
|
13
14
|
*/
|
|
14
15
|
icon?: string;
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
+
* Tint color for the push notification image when it appears in the notification tray.
|
|
17
18
|
* @default '#ffffff'
|
|
19
|
+
* @platform android
|
|
18
20
|
*/
|
|
19
21
|
color?: string;
|
|
20
22
|
/**
|
|
@@ -22,8 +24,9 @@ export type NotificationsPluginProps = {
|
|
|
22
24
|
*/
|
|
23
25
|
sounds?: string[];
|
|
24
26
|
/**
|
|
25
|
-
*
|
|
27
|
+
* Environment of the app: either 'development' or 'production'.
|
|
26
28
|
* @default 'development'
|
|
29
|
+
* @platform ios
|
|
27
30
|
*/
|
|
28
31
|
mode?: 'development' | 'production';
|
|
29
32
|
};
|
|
@@ -31,11 +31,8 @@ function guardPermission() {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function _subscribeDeviceToPushNotificationsAsync(): Promise<DevicePushToken['data']> {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Constants.manifest?.notification?.vapidPublicKey ??
|
|
37
|
-
// @ts-expect-error: TODO: not on the schema
|
|
38
|
-
Constants.manifest2?.extra?.expoClient?.notification?.vapidPublicKey;
|
|
34
|
+
// @ts-expect-error: TODO: not on the schema
|
|
35
|
+
const vapidPublicKey: string | null = Constants.expoConfig?.notification?.vapidPublicKey;
|
|
39
36
|
if (!vapidPublicKey) {
|
|
40
37
|
throw new CodedError(
|
|
41
38
|
'ERR_NOTIFICATIONS_PUSH_WEB_MISSING_CONFIG',
|
|
@@ -43,11 +40,8 @@ async function _subscribeDeviceToPushNotificationsAsync(): Promise<DevicePushTok
|
|
|
43
40
|
);
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Constants.manifest?.notification.serviceWorkerPath ??
|
|
49
|
-
// @ts-expect-error: TODO: not on the schema
|
|
50
|
-
Constants.manifest2?.extra?.expoClient?.notification?.serviceWorkerPath;
|
|
43
|
+
// @ts-expect-error: TODO: not on the schema
|
|
44
|
+
const serviceWorkerPath = Constants.expoConfig?.notification?.serviceWorkerPath;
|
|
51
45
|
if (!serviceWorkerPath) {
|
|
52
46
|
throw new CodedError(
|
|
53
47
|
'ERR_NOTIFICATIONS_PUSH_MISSING_CONFIGURATION',
|
|
@@ -104,11 +98,7 @@ async function _subscribeDeviceToPushNotificationsAsync(): Promise<DevicePushTok
|
|
|
104
98
|
// We wrap it with `fromExpoWebClient` to make sure other message
|
|
105
99
|
// will not override content such as `notificationIcon`.
|
|
106
100
|
// https://stackoverflow.com/a/35729334/2603230
|
|
107
|
-
const notificationIcon = (
|
|
108
|
-
Constants.manifest?.notification ??
|
|
109
|
-
Constants.manifest2?.extra?.expoClient?.notification ??
|
|
110
|
-
{}
|
|
111
|
-
).icon;
|
|
101
|
+
const notificationIcon = (Constants.expoConfig?.notification ?? {}).icon;
|
|
112
102
|
await registration.active.postMessage(
|
|
113
103
|
JSON.stringify({ fromExpoWebClient: { notificationIcon } })
|
|
114
104
|
);
|
|
@@ -32,10 +32,7 @@ export default async function getExpoPushTokenAsync(options: Options = {}): Prom
|
|
|
32
32
|
const deviceId = options.deviceId || (await getDeviceIdAsync());
|
|
33
33
|
|
|
34
34
|
const experienceId =
|
|
35
|
-
options.experienceId ||
|
|
36
|
-
Constants.manifest?.originalFullName ||
|
|
37
|
-
Constants.manifest2?.extra?.expoClient?.originalFullName ||
|
|
38
|
-
Constants.manifest?.id;
|
|
35
|
+
options.experienceId || Constants.expoConfig?.originalFullName || Constants.manifest?.id;
|
|
39
36
|
|
|
40
37
|
const projectId =
|
|
41
38
|
options.projectId ||
|
package/tsconfig.json
CHANGED