expo-notifications 55.0.20 → 55.0.21
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 +6 -0
- package/android/build.gradle +2 -2
- package/build/DevicePushTokenAutoRegistration.fx.d.ts.map +1 -1
- package/build/DevicePushTokenAutoRegistration.fx.js +20 -2
- package/build/DevicePushTokenAutoRegistration.fx.js.map +1 -1
- package/build/utils/updateDevicePushTokenAsync.d.ts +5 -0
- package/build/utils/updateDevicePushTokenAsync.d.ts.map +1 -1
- package/build/utils/updateDevicePushTokenAsync.js +68 -0
- package/build/utils/updateDevicePushTokenAsync.js.map +1 -1
- package/expo-module.config.json +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.module → 55.0.21/expo.modules.notifications-55.0.21.module} +7 -7
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.pom → 55.0.21/expo.modules.notifications-55.0.21.pom} +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.21/expo.modules.notifications-55.0.21.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha512 +1 -1
- package/package.json +2 -2
- package/src/DevicePushTokenAutoRegistration.fx.ts +22 -4
- package/src/utils/updateDevicePushTokenAsync.ts +86 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.notifications/55.0.20/expo.modules.notifications-55.0.20.pom.sha512 +0 -1
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20-sources.jar → 55.0.21/expo.modules.notifications-55.0.21-sources.jar} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20-sources.jar.md5 → 55.0.21/expo.modules.notifications-55.0.21-sources.jar.md5} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20-sources.jar.sha1 → 55.0.21/expo.modules.notifications-55.0.21-sources.jar.sha1} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20-sources.jar.sha256 → 55.0.21/expo.modules.notifications-55.0.21-sources.jar.sha256} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20-sources.jar.sha512 → 55.0.21/expo.modules.notifications-55.0.21-sources.jar.sha512} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.aar → 55.0.21/expo.modules.notifications-55.0.21.aar} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.aar.md5 → 55.0.21/expo.modules.notifications-55.0.21.aar.md5} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.aar.sha1 → 55.0.21/expo.modules.notifications-55.0.21.aar.sha1} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.aar.sha256 → 55.0.21/expo.modules.notifications-55.0.21.aar.sha256} +0 -0
- /package/local-maven-repo/host/exp/exponent/expo.modules.notifications/{55.0.20/expo.modules.notifications-55.0.20.aar.sha512 → 55.0.21/expo.modules.notifications-55.0.21.aar.sha512} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 55.0.21 — 2026-04-28
|
|
14
|
+
|
|
15
|
+
### 💡 Others
|
|
16
|
+
|
|
17
|
+
- Skip redundant device push token registration when token and metadata are unchanged since last successful registration. ([#44836](https://github.com/expo/expo/pull/44836) by [@stephanepham](https://github.com/stephanepham))
|
|
18
|
+
|
|
13
19
|
## 55.0.20 — 2026-04-21
|
|
14
20
|
|
|
15
21
|
_This version does not introduce any user-facing changes._
|
package/android/build.gradle
CHANGED
|
@@ -5,13 +5,13 @@ plugins {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
group = 'host.exp.exponent'
|
|
8
|
-
version = '55.0.
|
|
8
|
+
version = '55.0.21'
|
|
9
9
|
|
|
10
10
|
android {
|
|
11
11
|
namespace "expo.modules.notifications"
|
|
12
12
|
defaultConfig {
|
|
13
13
|
versionCode 21
|
|
14
|
-
versionName '55.0.
|
|
14
|
+
versionName '55.0.21'
|
|
15
15
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevicePushTokenAutoRegistration.fx.d.ts","sourceRoot":"","sources":["../src/DevicePushTokenAutoRegistration.fx.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"DevicePushTokenAutoRegistration.fx.d.ts","sourceRoot":"","sources":["../src/DevicePushTokenAutoRegistration.fx.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AAyBnC;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,qCAAqC,CAAC,OAAO,EAAE,OAAO,iBAsB3E;AAGD,wBAAsB,sCAAsC,CAC1D,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,iBAiC5C"}
|
|
@@ -3,9 +3,13 @@ import { UnavailabilityError } from 'expo-modules-core';
|
|
|
3
3
|
import ServerRegistrationModule from './ServerRegistrationModule';
|
|
4
4
|
import { addPushTokenListener } from './TokenEmitter';
|
|
5
5
|
import { getDevicePushTokenAsync } from './getDevicePushTokenAsync';
|
|
6
|
-
import { updateDevicePushTokenAsync as updateDevicePushTokenAsyncWithSignal } from './utils/updateDevicePushTokenAsync';
|
|
6
|
+
import { updateDevicePushTokenAsync as updateDevicePushTokenAsyncWithSignal, hasDeviceTokenChangedAsync, } from './utils/updateDevicePushTokenAsync';
|
|
7
7
|
let lastAbortController = null;
|
|
8
8
|
async function updatePushTokenAsync(token) {
|
|
9
|
+
const changed = await hasDeviceTokenChangedAsync(token);
|
|
10
|
+
if (!changed) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
9
13
|
// Abort current update process
|
|
10
14
|
lastAbortController?.abort();
|
|
11
15
|
lastAbortController = new AbortController();
|
|
@@ -25,7 +29,21 @@ export async function setAutoServerRegistrationEnabledAsync(enabled) {
|
|
|
25
29
|
if (!ServerRegistrationModule.setRegistrationInfoAsync) {
|
|
26
30
|
throw new UnavailabilityError('ServerRegistrationModule', 'setRegistrationInfoAsync');
|
|
27
31
|
}
|
|
28
|
-
|
|
32
|
+
if (!enabled) {
|
|
33
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(null);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
let existing = {};
|
|
37
|
+
try {
|
|
38
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync?.();
|
|
39
|
+
if (info) {
|
|
40
|
+
existing = JSON.parse(info);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch { }
|
|
44
|
+
existing.isEnabled = true;
|
|
45
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));
|
|
46
|
+
}
|
|
29
47
|
}
|
|
30
48
|
// note(Chmiela): This function is exported only for testing purposes.
|
|
31
49
|
export async function __handlePersistedRegistrationInfoAsync(registrationInfo) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DevicePushTokenAutoRegistration.fx.js","sourceRoot":"","sources":["../src/DevicePushTokenAutoRegistration.fx.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,wBAAwB,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,
|
|
1
|
+
{"version":3,"file":"DevicePushTokenAutoRegistration.fx.js","sourceRoot":"","sources":["../src/DevicePushTokenAutoRegistration.fx.ts"],"names":[],"mappings":"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","sourcesContent":["import 'abort-controller/polyfill';\nimport { UnavailabilityError } from 'expo-modules-core';\n\nimport ServerRegistrationModule from './ServerRegistrationModule';\nimport { addPushTokenListener } from './TokenEmitter';\nimport { DevicePushToken } from './Tokens.types';\nimport { getDevicePushTokenAsync } from './getDevicePushTokenAsync';\nimport {\n updateDevicePushTokenAsync as updateDevicePushTokenAsyncWithSignal,\n hasDeviceTokenChangedAsync,\n} from './utils/updateDevicePushTokenAsync';\n\nlet lastAbortController: AbortController | null = null;\nasync function updatePushTokenAsync(token: DevicePushToken) {\n const changed = await hasDeviceTokenChangedAsync(token);\n if (!changed) {\n return;\n }\n\n // Abort current update process\n lastAbortController?.abort();\n lastAbortController = new AbortController();\n return await updateDevicePushTokenAsyncWithSignal(lastAbortController.signal, token);\n}\n\n/**\n * Encapsulates device server registration data\n */\nexport type DevicePushTokenRegistration = {\n isEnabled: boolean;\n};\n\n/**\n * @hidden - the comment is misleading and the purpose of the function needs to be reevaluated\n *\n * Sets the registration information so that the device push token gets pushed\n * to the given registration endpoint\n * @param enabled\n */\nexport async function setAutoServerRegistrationEnabledAsync(enabled: boolean) {\n // We are overwriting registration, so we shouldn't let\n // any pending request complete.\n lastAbortController?.abort();\n\n if (!ServerRegistrationModule.setRegistrationInfoAsync) {\n throw new UnavailabilityError('ServerRegistrationModule', 'setRegistrationInfoAsync');\n }\n\n if (!enabled) {\n await ServerRegistrationModule.setRegistrationInfoAsync(null);\n } else {\n let existing: Record<string, unknown> = {};\n try {\n const info = await ServerRegistrationModule.getRegistrationInfoAsync?.();\n if (info) {\n existing = JSON.parse(info);\n }\n } catch {}\n existing.isEnabled = true;\n await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));\n }\n}\n\n// note(Chmiela): This function is exported only for testing purposes.\nexport async function __handlePersistedRegistrationInfoAsync(\n registrationInfo: string | null | undefined\n) {\n if (!registrationInfo) {\n // No registration info, nothing to do\n return;\n }\n\n let registration: DevicePushTokenRegistration | null = null;\n try {\n registration = JSON.parse(registrationInfo);\n } catch (e) {\n console.warn(\n '[expo-notifications] Error encountered while fetching registration information for auto token updates.',\n e\n );\n }\n\n if (!registration?.isEnabled) {\n // Registration is invalid or not enabled, nothing more to do\n return;\n }\n\n try {\n // Since the registration is enabled, fetching a \"new\" device token\n // shouldn't be a problem.\n const latestDevicePushToken = await getDevicePushTokenAsync();\n await updatePushTokenAsync(latestDevicePushToken);\n } catch (e) {\n console.warn(\n '[expo-notifications] Error encountered while updating server registration with latest device push token.',\n e\n );\n }\n}\n\nif (ServerRegistrationModule.getRegistrationInfoAsync) {\n // A global scope (to get all the updates) device push token\n // subscription, never cleared.\n addPushTokenListener(async (token) => {\n try {\n // Before updating the push token on server we always check if we should\n // Since modules can't change their method availability while running, we\n // can assert it's defined.\n const registrationInfo = await ServerRegistrationModule.getRegistrationInfoAsync!();\n\n if (!registrationInfo) {\n // Registration is not enabled\n return;\n }\n\n const registration: DevicePushTokenRegistration | null = JSON.parse(registrationInfo);\n if (registration?.isEnabled) {\n // Dispatch an abortable task to update\n // registration with new token.\n await updatePushTokenAsync(token);\n }\n } catch (e) {\n console.warn(\n '[expo-notifications] Error encountered while updating server registration with latest device push token.',\n e\n );\n }\n });\n\n // Verify if persisted registration\n // has successfully uploaded last known\n // device push token. If not, retry.\n ServerRegistrationModule.getRegistrationInfoAsync().then(\n __handlePersistedRegistrationInfoAsync,\n (e) => {\n console.error('[expo-notifications] Error reading persisted server registration info: ', e);\n }\n );\n} else {\n console.warn(\n `[expo-notifications] Error encountered while fetching auto-registration state, new tokens will not be automatically registered on server.`,\n new UnavailabilityError('ServerRegistrationModule', 'getRegistrationInfoAsync')\n );\n}\n"]}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { DevicePushToken } from '../Tokens.types';
|
|
2
|
+
/**
|
|
3
|
+
* Returns `true` if the device token or metadata has changed since the last
|
|
4
|
+
* successful registration, or if the check cannot be performed (fail-open).
|
|
5
|
+
*/
|
|
6
|
+
export declare function hasDeviceTokenChangedAsync(token: DevicePushToken): Promise<boolean>;
|
|
2
7
|
export declare function updateDevicePushTokenAsync(signal: AbortSignal, token: DevicePushToken): Promise<void>;
|
|
3
8
|
//# sourceMappingURL=updateDevicePushTokenAsync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateDevicePushTokenAsync.d.ts","sourceRoot":"","sources":["../../src/utils/updateDevicePushTokenAsync.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"updateDevicePushTokenAsync.d.ts","sourceRoot":"","sources":["../../src/utils/updateDevicePushTokenAsync.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAmDlD;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAuBzF;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,iBAqG3F"}
|
|
@@ -3,6 +3,65 @@ import { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';
|
|
|
3
3
|
import { computeNextBackoffInterval } from './backoff';
|
|
4
4
|
import ServerRegistrationModule from '../ServerRegistrationModule';
|
|
5
5
|
const updateDevicePushTokenUrl = 'https://exp.host/--/api/v2/push/updateDeviceToken';
|
|
6
|
+
const LAST_TOKEN_KEY = 'lastRegisteredDeviceToken';
|
|
7
|
+
// Force re-registration after 7 days even if nothing changed, in case the
|
|
8
|
+
// server lost the device record (cleanup, migration, etc.).
|
|
9
|
+
const REGISTRATION_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
10
|
+
async function getLastRegisteredTokenDataAsync() {
|
|
11
|
+
try {
|
|
12
|
+
if (!ServerRegistrationModule.getRegistrationInfoAsync) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync();
|
|
16
|
+
if (!info) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const parsed = JSON.parse(info);
|
|
20
|
+
return parsed?.[LAST_TOKEN_KEY] ?? null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function setLastRegisteredTokenDataAsync(tokenData) {
|
|
27
|
+
try {
|
|
28
|
+
if (!ServerRegistrationModule.getRegistrationInfoAsync ||
|
|
29
|
+
!ServerRegistrationModule.setRegistrationInfoAsync) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync();
|
|
33
|
+
const existing = info ? JSON.parse(info) : {};
|
|
34
|
+
existing[LAST_TOKEN_KEY] = tokenData;
|
|
35
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Best-effort — next app open will re-register
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns `true` if the device token or metadata has changed since the last
|
|
43
|
+
* successful registration, or if the check cannot be performed (fail-open).
|
|
44
|
+
*/
|
|
45
|
+
export async function hasDeviceTokenChangedAsync(token) {
|
|
46
|
+
try {
|
|
47
|
+
const development = await shouldUseDevelopmentNotificationService();
|
|
48
|
+
const lastTokenData = await getLastRegisteredTokenDataAsync();
|
|
49
|
+
if (lastTokenData == null) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
const age = Date.now() - (lastTokenData.registeredAt ?? 0);
|
|
53
|
+
if (age < 0 || age >= REGISTRATION_TTL_MS) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return (token.data !== lastTokenData.deviceToken ||
|
|
57
|
+
Application.applicationId !== lastTokenData.appId ||
|
|
58
|
+
development !== lastTokenData.development ||
|
|
59
|
+
getTypeOfToken(token) !== lastTokenData.type);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
6
65
|
export async function updateDevicePushTokenAsync(signal, token) {
|
|
7
66
|
const doUpdateDevicePushTokenAsync = async (retry) => {
|
|
8
67
|
const [development, deviceId] = await Promise.all([
|
|
@@ -29,6 +88,15 @@ export async function updateDevicePushTokenAsync(signal, token) {
|
|
|
29
88
|
if (!response.ok) {
|
|
30
89
|
console.debug('[expo-notifications] Error encountered while updating the device push token with the server:', await response.text());
|
|
31
90
|
}
|
|
91
|
+
if (response.ok) {
|
|
92
|
+
await setLastRegisteredTokenDataAsync({
|
|
93
|
+
deviceToken: token.data,
|
|
94
|
+
appId: Application.applicationId,
|
|
95
|
+
development,
|
|
96
|
+
type: getTypeOfToken(token),
|
|
97
|
+
registeredAt: Date.now(),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
32
100
|
// Retry if request failed
|
|
33
101
|
if (!response.ok) {
|
|
34
102
|
retry();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateDevicePushTokenAsync.js","sourceRoot":"","sources":["../../src/utils/updateDevicePushTokenAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Application from 'expo-application';\nimport { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';\n\nimport { computeNextBackoffInterval } from './backoff';\nimport ServerRegistrationModule from '../ServerRegistrationModule';\nimport { DevicePushToken } from '../Tokens.types';\n\nconst updateDevicePushTokenUrl = 'https://exp.host/--/api/v2/push/updateDeviceToken';\n\nexport async function updateDevicePushTokenAsync(signal: AbortSignal, token: DevicePushToken) {\n const doUpdateDevicePushTokenAsync = async (retry: () => void) => {\n const [development, deviceId] = await Promise.all([\n shouldUseDevelopmentNotificationService(),\n getDeviceIdAsync(),\n ]);\n const body = {\n deviceId: deviceId.toLowerCase(),\n development,\n deviceToken: token.data,\n appId: Application.applicationId,\n type: getTypeOfToken(token),\n };\n\n try {\n const response = await fetch(updateDevicePushTokenUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n\n // Help debug erroring servers\n if (!response.ok) {\n console.debug(\n '[expo-notifications] Error encountered while updating the device push token with the server:',\n await response.text()\n );\n }\n\n // Retry if request failed\n if (!response.ok) {\n retry();\n }\n } catch (error: any) {\n // Error returned if the request is aborted should be an 'AbortError'. In\n // React Native fetch is polyfilled using `whatwg-fetch` which:\n // - creates `AbortError`s like this\n // https://github.com/github/fetch/blob/75d9455d380f365701151f3ac85c5bda4bbbde76/fetch.js#L505\n // - which creates exceptions like\n // https://github.com/github/fetch/blob/75d9455d380f365701151f3ac85c5bda4bbbde76/fetch.js#L490-L494\n if (typeof error === 'object' && error?.name === 'AbortError') {\n // We don't consider AbortError a failure, it's a sign somewhere else the\n // request is expected to succeed and we don't need this one, so let's\n // just return.\n return;\n }\n\n console.warn(\n '[expo-notifications] Error thrown while updating the device push token with the server:',\n error\n );\n\n retry();\n }\n };\n\n let shouldTry = true;\n const retry = () => {\n shouldTry = true;\n };\n\n let retriesCount = 0;\n const initialBackoff = 500; // 0.5 s\n const backoffOptions = {\n maxBackoff: 2 * 60 * 1000, // 2 minutes\n };\n let nextBackoffInterval = computeNextBackoffInterval(\n initialBackoff,\n retriesCount,\n backoffOptions\n );\n\n while (shouldTry && !signal.aborted) {\n // Will be set to true by `retry` if it's called\n shouldTry = false;\n await doUpdateDevicePushTokenAsync(retry);\n\n // Do not wait if we won't retry\n if (shouldTry && !signal.aborted) {\n nextBackoffInterval = computeNextBackoffInterval(\n initialBackoff,\n retriesCount,\n backoffOptions\n );\n retriesCount += 1;\n await new Promise((resolve) => setTimeout(resolve, nextBackoffInterval));\n }\n }\n}\n\n// Same as in getExpoPushTokenAsync\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_NOTIFICATIONS_DEVICE_ID',\n `Could not fetch the installation ID of the application: ${e}.`\n );\n }\n}\n\n// Same as in getExpoPushTokenAsync\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\n// Same as in getExpoPushTokenAsync\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"]}
|
|
1
|
+
{"version":3,"file":"updateDevicePushTokenAsync.js","sourceRoot":"","sources":["../../src/utils/updateDevicePushTokenAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Application from 'expo-application';\nimport { CodedError, Platform, UnavailabilityError } from 'expo-modules-core';\n\nimport { computeNextBackoffInterval } from './backoff';\nimport ServerRegistrationModule from '../ServerRegistrationModule';\nimport { DevicePushToken } from '../Tokens.types';\n\nconst updateDevicePushTokenUrl = 'https://exp.host/--/api/v2/push/updateDeviceToken';\n\nconst LAST_TOKEN_KEY = 'lastRegisteredDeviceToken';\n\ntype StoredTokenData = {\n deviceToken: string;\n appId: string | null;\n development: boolean;\n type: string;\n registeredAt: number;\n};\n\n// Force re-registration after 7 days even if nothing changed, in case the\n// server lost the device record (cleanup, migration, etc.).\nconst REGISTRATION_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nasync function getLastRegisteredTokenDataAsync(): Promise<StoredTokenData | null> {\n try {\n if (!ServerRegistrationModule.getRegistrationInfoAsync) {\n return null;\n }\n const info = await ServerRegistrationModule.getRegistrationInfoAsync();\n if (!info) {\n return null;\n }\n const parsed = JSON.parse(info);\n return parsed?.[LAST_TOKEN_KEY] ?? null;\n } catch {\n return null;\n }\n}\n\nasync function setLastRegisteredTokenDataAsync(tokenData: StoredTokenData): Promise<void> {\n try {\n if (\n !ServerRegistrationModule.getRegistrationInfoAsync ||\n !ServerRegistrationModule.setRegistrationInfoAsync\n ) {\n return;\n }\n const info = await ServerRegistrationModule.getRegistrationInfoAsync();\n const existing = info ? JSON.parse(info) : {};\n existing[LAST_TOKEN_KEY] = tokenData;\n await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));\n } catch {\n // Best-effort — next app open will re-register\n }\n}\n\n/**\n * Returns `true` if the device token or metadata has changed since the last\n * successful registration, or if the check cannot be performed (fail-open).\n */\nexport async function hasDeviceTokenChangedAsync(token: DevicePushToken): Promise<boolean> {\n try {\n const development = await shouldUseDevelopmentNotificationService();\n const lastTokenData = await getLastRegisteredTokenDataAsync();\n\n if (lastTokenData == null) {\n return true;\n }\n\n const age = Date.now() - (lastTokenData.registeredAt ?? 0);\n if (age < 0 || age >= REGISTRATION_TTL_MS) {\n return true;\n }\n\n return (\n token.data !== lastTokenData.deviceToken ||\n Application.applicationId !== lastTokenData.appId ||\n development !== lastTokenData.development ||\n getTypeOfToken(token) !== lastTokenData.type\n );\n } catch {\n return true;\n }\n}\n\nexport async function updateDevicePushTokenAsync(signal: AbortSignal, token: DevicePushToken) {\n const doUpdateDevicePushTokenAsync = async (retry: () => void) => {\n const [development, deviceId] = await Promise.all([\n shouldUseDevelopmentNotificationService(),\n getDeviceIdAsync(),\n ]);\n const body = {\n deviceId: deviceId.toLowerCase(),\n development,\n deviceToken: token.data,\n appId: Application.applicationId,\n type: getTypeOfToken(token),\n };\n\n try {\n const response = await fetch(updateDevicePushTokenUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n\n // Help debug erroring servers\n if (!response.ok) {\n console.debug(\n '[expo-notifications] Error encountered while updating the device push token with the server:',\n await response.text()\n );\n }\n\n if (response.ok) {\n await setLastRegisteredTokenDataAsync({\n deviceToken: token.data,\n appId: Application.applicationId,\n development,\n type: getTypeOfToken(token),\n registeredAt: Date.now(),\n });\n }\n\n // Retry if request failed\n if (!response.ok) {\n retry();\n }\n } catch (error: any) {\n // Error returned if the request is aborted should be an 'AbortError'. In\n // React Native fetch is polyfilled using `whatwg-fetch` which:\n // - creates `AbortError`s like this\n // https://github.com/github/fetch/blob/75d9455d380f365701151f3ac85c5bda4bbbde76/fetch.js#L505\n // - which creates exceptions like\n // https://github.com/github/fetch/blob/75d9455d380f365701151f3ac85c5bda4bbbde76/fetch.js#L490-L494\n if (typeof error === 'object' && error?.name === 'AbortError') {\n // We don't consider AbortError a failure, it's a sign somewhere else the\n // request is expected to succeed and we don't need this one, so let's\n // just return.\n return;\n }\n\n console.warn(\n '[expo-notifications] Error thrown while updating the device push token with the server:',\n error\n );\n\n retry();\n }\n };\n\n let shouldTry = true;\n const retry = () => {\n shouldTry = true;\n };\n\n let retriesCount = 0;\n const initialBackoff = 500; // 0.5 s\n const backoffOptions = {\n maxBackoff: 2 * 60 * 1000, // 2 minutes\n };\n let nextBackoffInterval = computeNextBackoffInterval(\n initialBackoff,\n retriesCount,\n backoffOptions\n );\n\n while (shouldTry && !signal.aborted) {\n // Will be set to true by `retry` if it's called\n shouldTry = false;\n await doUpdateDevicePushTokenAsync(retry);\n\n // Do not wait if we won't retry\n if (shouldTry && !signal.aborted) {\n nextBackoffInterval = computeNextBackoffInterval(\n initialBackoff,\n retriesCount,\n backoffOptions\n );\n retriesCount += 1;\n await new Promise((resolve) => setTimeout(resolve, nextBackoffInterval));\n }\n }\n}\n\n// Same as in getExpoPushTokenAsync\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_NOTIFICATIONS_DEVICE_ID',\n `Could not fetch the installation ID of the application: ${e}.`\n );\n }\n}\n\n// Same as in getExpoPushTokenAsync\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\n// Same as in getExpoPushTokenAsync\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"]}
|
package/expo-module.config.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"component": {
|
|
4
4
|
"group": "host.exp.exponent",
|
|
5
5
|
"module": "expo.modules.notifications",
|
|
6
|
-
"version": "55.0.
|
|
6
|
+
"version": "55.0.21",
|
|
7
7
|
"attributes": {
|
|
8
8
|
"org.gradle.status": "release"
|
|
9
9
|
}
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
{
|
|
27
|
-
"name": "expo.modules.notifications-55.0.
|
|
28
|
-
"url": "expo.modules.notifications-55.0.
|
|
27
|
+
"name": "expo.modules.notifications-55.0.21.aar",
|
|
28
|
+
"url": "expo.modules.notifications-55.0.21.aar",
|
|
29
29
|
"size": 402983,
|
|
30
30
|
"sha512": "e4c3409cfecc6c9a8049529caf9fd17f34f2a8be55e5b1a345b52544079b8a62ad48e55e47179519e150b8296c814dda0cf951fbd53ced1f80da17365fcc457b",
|
|
31
31
|
"sha256": "a96065f543fc9f57cf6eb4871137f339854dec0541e8277eb237e0d48abefeda",
|
|
@@ -122,8 +122,8 @@
|
|
|
122
122
|
],
|
|
123
123
|
"files": [
|
|
124
124
|
{
|
|
125
|
-
"name": "expo.modules.notifications-55.0.
|
|
126
|
-
"url": "expo.modules.notifications-55.0.
|
|
125
|
+
"name": "expo.modules.notifications-55.0.21.aar",
|
|
126
|
+
"url": "expo.modules.notifications-55.0.21.aar",
|
|
127
127
|
"size": 402983,
|
|
128
128
|
"sha512": "e4c3409cfecc6c9a8049529caf9fd17f34f2a8be55e5b1a345b52544079b8a62ad48e55e47179519e150b8296c814dda0cf951fbd53ced1f80da17365fcc457b",
|
|
129
129
|
"sha256": "a96065f543fc9f57cf6eb4871137f339854dec0541e8277eb237e0d48abefeda",
|
|
@@ -142,8 +142,8 @@
|
|
|
142
142
|
},
|
|
143
143
|
"files": [
|
|
144
144
|
{
|
|
145
|
-
"name": "expo.modules.notifications-55.0.
|
|
146
|
-
"url": "expo.modules.notifications-55.0.
|
|
145
|
+
"name": "expo.modules.notifications-55.0.21-sources.jar",
|
|
146
|
+
"url": "expo.modules.notifications-55.0.21-sources.jar",
|
|
147
147
|
"size": 100001,
|
|
148
148
|
"sha512": "6bc8c1210d364179f454b9fe28fd71a79f1e28fc34dc615e61cdbb89c6afea3991b04b76b77ae42cb9ce6abc6e36a861caddba68d900fa6a09880b960300444d",
|
|
149
149
|
"sha256": "c6920c792c28a4f9785956f71822697398385da86af1c6da362785e41f329140",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
b883c3fa764c63168689d0ef6bf9d950
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a5e14cab71395e77d9db47e83d453d882e241fba
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
67af83ef1a812724c70cac553b2b40a475cb1434f87126126df497bbead95e51
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
76677ca056e91e0c56708334fbf0aaf67c94f9119a51be3ff88f1d2c257e434ef88332b678f2142612b1b92f90352ac04ee3566790ac1efba3ac352eb5bda15a
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<modelVersion>4.0.0</modelVersion>
|
|
10
10
|
<groupId>host.exp.exponent</groupId>
|
|
11
11
|
<artifactId>expo.modules.notifications</artifactId>
|
|
12
|
-
<version>55.0.
|
|
12
|
+
<version>55.0.21</version>
|
|
13
13
|
<packaging>aar</packaging>
|
|
14
14
|
<name>expo.modules.notifications</name>
|
|
15
15
|
<url>https://github.com/expo/expo</url>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1bb08f913112da628ca3a49ef0046dd2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
151a16f3b938590488f75ccb6dabac9cf8d4c7aa
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7ccaaf2e3cab1295e3aec37efb4b551d81cddbca119878740ce630260a1bffb2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4f70873dc594e81efd2b183e83068f3e47c4e75da4322abf85e2071bf9abd9b4219c6983290e50ea944bbdc8ab2cc51481891a8bacb3fdcdaa6104153e6269cf
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<groupId>host.exp.exponent</groupId>
|
|
4
4
|
<artifactId>expo.modules.notifications</artifactId>
|
|
5
5
|
<versioning>
|
|
6
|
-
<latest>55.0.
|
|
7
|
-
<release>55.0.
|
|
6
|
+
<latest>55.0.21</latest>
|
|
7
|
+
<release>55.0.21</release>
|
|
8
8
|
<versions>
|
|
9
|
-
<version>55.0.
|
|
9
|
+
<version>55.0.21</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<lastUpdated>
|
|
11
|
+
<lastUpdated>20260428153947</lastUpdated>
|
|
12
12
|
</versioning>
|
|
13
13
|
</metadata>
|
package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.md5
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3b54b27032ae9516bcefd0397a796fff
|
package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha1
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
b045b5a99f3e0926a580b3f61ccbe7598fccd03d
|
package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
b2f4eab032f9ead6be917f8a39e89436cac601b88acbcc91784574388caef6bb
|
package/local-maven-repo/host/exp/exponent/expo.modules.notifications/maven-metadata.xml.sha512
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d9dc7a64278b76cb02a5e879c1e00be26de4216b50e068837c7595ac8b7f3b4b258b8364724d6c1cacc4b1c0ff04107168927c03e5320052d6d0e4d885554b09
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-notifications",
|
|
3
|
-
"version": "55.0.
|
|
3
|
+
"version": "55.0.21",
|
|
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",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"react": "*",
|
|
59
59
|
"react-native": "*"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "be06cb45cb9eb8076b6910daa98813a6a3b03287"
|
|
62
62
|
}
|
|
@@ -5,10 +5,18 @@ import ServerRegistrationModule from './ServerRegistrationModule';
|
|
|
5
5
|
import { addPushTokenListener } from './TokenEmitter';
|
|
6
6
|
import { DevicePushToken } from './Tokens.types';
|
|
7
7
|
import { getDevicePushTokenAsync } from './getDevicePushTokenAsync';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
updateDevicePushTokenAsync as updateDevicePushTokenAsyncWithSignal,
|
|
10
|
+
hasDeviceTokenChangedAsync,
|
|
11
|
+
} from './utils/updateDevicePushTokenAsync';
|
|
9
12
|
|
|
10
13
|
let lastAbortController: AbortController | null = null;
|
|
11
14
|
async function updatePushTokenAsync(token: DevicePushToken) {
|
|
15
|
+
const changed = await hasDeviceTokenChangedAsync(token);
|
|
16
|
+
if (!changed) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
// Abort current update process
|
|
13
21
|
lastAbortController?.abort();
|
|
14
22
|
lastAbortController = new AbortController();
|
|
@@ -38,9 +46,19 @@ export async function setAutoServerRegistrationEnabledAsync(enabled: boolean) {
|
|
|
38
46
|
throw new UnavailabilityError('ServerRegistrationModule', 'setRegistrationInfoAsync');
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
if (!enabled) {
|
|
50
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(null);
|
|
51
|
+
} else {
|
|
52
|
+
let existing: Record<string, unknown> = {};
|
|
53
|
+
try {
|
|
54
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync?.();
|
|
55
|
+
if (info) {
|
|
56
|
+
existing = JSON.parse(info);
|
|
57
|
+
}
|
|
58
|
+
} catch {}
|
|
59
|
+
existing.isEnabled = true;
|
|
60
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));
|
|
61
|
+
}
|
|
44
62
|
}
|
|
45
63
|
|
|
46
64
|
// note(Chmiela): This function is exported only for testing purposes.
|
|
@@ -7,6 +7,82 @@ import { DevicePushToken } from '../Tokens.types';
|
|
|
7
7
|
|
|
8
8
|
const updateDevicePushTokenUrl = 'https://exp.host/--/api/v2/push/updateDeviceToken';
|
|
9
9
|
|
|
10
|
+
const LAST_TOKEN_KEY = 'lastRegisteredDeviceToken';
|
|
11
|
+
|
|
12
|
+
type StoredTokenData = {
|
|
13
|
+
deviceToken: string;
|
|
14
|
+
appId: string | null;
|
|
15
|
+
development: boolean;
|
|
16
|
+
type: string;
|
|
17
|
+
registeredAt: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Force re-registration after 7 days even if nothing changed, in case the
|
|
21
|
+
// server lost the device record (cleanup, migration, etc.).
|
|
22
|
+
const REGISTRATION_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
23
|
+
|
|
24
|
+
async function getLastRegisteredTokenDataAsync(): Promise<StoredTokenData | null> {
|
|
25
|
+
try {
|
|
26
|
+
if (!ServerRegistrationModule.getRegistrationInfoAsync) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync();
|
|
30
|
+
if (!info) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const parsed = JSON.parse(info);
|
|
34
|
+
return parsed?.[LAST_TOKEN_KEY] ?? null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function setLastRegisteredTokenDataAsync(tokenData: StoredTokenData): Promise<void> {
|
|
41
|
+
try {
|
|
42
|
+
if (
|
|
43
|
+
!ServerRegistrationModule.getRegistrationInfoAsync ||
|
|
44
|
+
!ServerRegistrationModule.setRegistrationInfoAsync
|
|
45
|
+
) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const info = await ServerRegistrationModule.getRegistrationInfoAsync();
|
|
49
|
+
const existing = info ? JSON.parse(info) : {};
|
|
50
|
+
existing[LAST_TOKEN_KEY] = tokenData;
|
|
51
|
+
await ServerRegistrationModule.setRegistrationInfoAsync(JSON.stringify(existing));
|
|
52
|
+
} catch {
|
|
53
|
+
// Best-effort — next app open will re-register
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns `true` if the device token or metadata has changed since the last
|
|
59
|
+
* successful registration, or if the check cannot be performed (fail-open).
|
|
60
|
+
*/
|
|
61
|
+
export async function hasDeviceTokenChangedAsync(token: DevicePushToken): Promise<boolean> {
|
|
62
|
+
try {
|
|
63
|
+
const development = await shouldUseDevelopmentNotificationService();
|
|
64
|
+
const lastTokenData = await getLastRegisteredTokenDataAsync();
|
|
65
|
+
|
|
66
|
+
if (lastTokenData == null) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const age = Date.now() - (lastTokenData.registeredAt ?? 0);
|
|
71
|
+
if (age < 0 || age >= REGISTRATION_TTL_MS) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
token.data !== lastTokenData.deviceToken ||
|
|
77
|
+
Application.applicationId !== lastTokenData.appId ||
|
|
78
|
+
development !== lastTokenData.development ||
|
|
79
|
+
getTypeOfToken(token) !== lastTokenData.type
|
|
80
|
+
);
|
|
81
|
+
} catch {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
10
86
|
export async function updateDevicePushTokenAsync(signal: AbortSignal, token: DevicePushToken) {
|
|
11
87
|
const doUpdateDevicePushTokenAsync = async (retry: () => void) => {
|
|
12
88
|
const [development, deviceId] = await Promise.all([
|
|
@@ -39,6 +115,16 @@ export async function updateDevicePushTokenAsync(signal: AbortSignal, token: Dev
|
|
|
39
115
|
);
|
|
40
116
|
}
|
|
41
117
|
|
|
118
|
+
if (response.ok) {
|
|
119
|
+
await setLastRegisteredTokenDataAsync({
|
|
120
|
+
deviceToken: token.data,
|
|
121
|
+
appId: Application.applicationId,
|
|
122
|
+
development,
|
|
123
|
+
type: getTypeOfToken(token),
|
|
124
|
+
registeredAt: Date.now(),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
42
128
|
// Retry if request failed
|
|
43
129
|
if (!response.ok) {
|
|
44
130
|
retry();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3ce92fe48a63609373fca7ff3e8edb75
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
4985e807960a5a57d682ab06993dbb6c1563a454
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
11d4bc71ff97200171bac05867edf40e38caf1fec6cc2cd5653d68929ce733a5
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dd3375fc5f612b3acf00fbd0b4529ab198be83bcec2f84522d7f707c538999b60906961c2e2144c2f1e35013d02197d3d04c44aea025e6b832e36ee2d82ec843
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
22c4f66e902c2f9545e83b137f2d40f1
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0561170177d76b655678d1a308af6cc695e49a92
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
877a752de20364449a860f12d9eb122c3ef26f803949c4540de0426e58f74256
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
96a26ceab8a313b08ade1341687575e1d8d164af24205e3d843898deb2e87bcf877b0495b3b56074913e420073a95050f3f9dc82e142da6e03867fbca74d8f9c
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|