react-native-update 9.1.5 → 10.0.0-beta.0
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/android/build.gradle +23 -0
- package/android/src/main/AndroidManifest.xml +0 -1
- package/android/src/main/AndroidManifestNew.xml +14 -0
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +1 -1
- package/package.json +10 -5
- package/react-native-update.podspec +23 -1
- package/src/client.tsx +316 -0
- package/src/context.ts +30 -0
- package/src/core.ts +106 -0
- package/src/index.ts +3 -0
- package/src/index.web.js +17 -0
- package/src/provider.tsx +184 -0
- package/{lib/NativeUpdate.ts → src/turboModuleSpec.ts} +0 -2
- package/{lib → src}/type.ts +17 -5
- package/{lib → src}/utils.ts +2 -2
- package/lib/endpoint.ts +0 -53
- package/lib/index.ts +0 -2
- package/lib/index.web.js +0 -18
- package/lib/main.ts +0 -398
- package/lib/simpleUpdate.tsx +0 -135
package/src/provider.tsx
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
ReactNode,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import {
|
|
9
|
+
Alert,
|
|
10
|
+
NativeEventSubscription,
|
|
11
|
+
AppState,
|
|
12
|
+
Platform,
|
|
13
|
+
Linking,
|
|
14
|
+
} from 'react-native';
|
|
15
|
+
import { Pushy } from './client';
|
|
16
|
+
import { isFirstTime } from './core';
|
|
17
|
+
import { CheckResult } from './type';
|
|
18
|
+
import { PushyContext } from './context';
|
|
19
|
+
|
|
20
|
+
export const PushyProvider = ({
|
|
21
|
+
client,
|
|
22
|
+
children,
|
|
23
|
+
}: {
|
|
24
|
+
client: Pushy;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}) => {
|
|
27
|
+
const { strategy, useAlert } = client.options;
|
|
28
|
+
const stateListener = useRef<NativeEventSubscription>();
|
|
29
|
+
const [updateInfo, setUpdateInfo] = useState<CheckResult>();
|
|
30
|
+
const [lastError, setLastError] = useState<Error>();
|
|
31
|
+
|
|
32
|
+
const dismissError = useCallback(() => {
|
|
33
|
+
if (lastError) {
|
|
34
|
+
setLastError(undefined);
|
|
35
|
+
}
|
|
36
|
+
}, [lastError]);
|
|
37
|
+
|
|
38
|
+
const showAlert = useCallback(
|
|
39
|
+
(...args: Parameters<typeof Alert.alert>) => {
|
|
40
|
+
if (useAlert) {
|
|
41
|
+
Alert.alert(...args);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
[useAlert],
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const switchVersion = useCallback(() => {
|
|
48
|
+
if (updateInfo && 'hash' in updateInfo) {
|
|
49
|
+
client.switchVersion(updateInfo.hash);
|
|
50
|
+
}
|
|
51
|
+
}, [client, updateInfo]);
|
|
52
|
+
|
|
53
|
+
const switchVersionLater = useCallback(() => {
|
|
54
|
+
if (updateInfo && 'hash' in updateInfo) {
|
|
55
|
+
client.switchVersionLater(updateInfo.hash);
|
|
56
|
+
}
|
|
57
|
+
}, [client, updateInfo]);
|
|
58
|
+
|
|
59
|
+
const downloadUpdate = useCallback(async () => {
|
|
60
|
+
if (!updateInfo || !('update' in updateInfo)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const hash = await client.downloadUpdate(updateInfo);
|
|
65
|
+
if (!hash) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
stateListener.current && stateListener.current.remove();
|
|
69
|
+
showAlert('提示', '下载完毕,是否立即更新?', [
|
|
70
|
+
{
|
|
71
|
+
text: '下次再说',
|
|
72
|
+
style: 'cancel',
|
|
73
|
+
onPress: () => {
|
|
74
|
+
client.switchVersionLater(hash);
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
text: '立即更新',
|
|
79
|
+
style: 'default',
|
|
80
|
+
onPress: () => {
|
|
81
|
+
client.switchVersion(hash);
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
setLastError(err);
|
|
87
|
+
showAlert('更新失败', err.message);
|
|
88
|
+
}
|
|
89
|
+
}, [client, showAlert, updateInfo]);
|
|
90
|
+
|
|
91
|
+
const checkUpdate = useCallback(async () => {
|
|
92
|
+
let info: CheckResult;
|
|
93
|
+
try {
|
|
94
|
+
info = await client.checkUpdate();
|
|
95
|
+
} catch (err) {
|
|
96
|
+
setLastError(err);
|
|
97
|
+
showAlert('更新检查失败', err.message);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setUpdateInfo(info);
|
|
101
|
+
if ('expired' in info) {
|
|
102
|
+
const { downloadUrl } = info;
|
|
103
|
+
showAlert('提示', '您的应用版本已更新,点击更新下载安装新版本', [
|
|
104
|
+
{
|
|
105
|
+
text: '更新',
|
|
106
|
+
onPress: () => {
|
|
107
|
+
if (downloadUrl) {
|
|
108
|
+
if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) {
|
|
109
|
+
client.downloadAndInstallApk(downloadUrl);
|
|
110
|
+
} else {
|
|
111
|
+
Linking.openURL(downloadUrl);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
} else if ('update' in info) {
|
|
118
|
+
showAlert(
|
|
119
|
+
'提示',
|
|
120
|
+
'检查到新的版本' + info.name + ',是否下载?\n' + info.description,
|
|
121
|
+
[
|
|
122
|
+
{ text: '取消', style: 'cancel' },
|
|
123
|
+
{
|
|
124
|
+
text: '确定',
|
|
125
|
+
style: 'default',
|
|
126
|
+
onPress: () => {
|
|
127
|
+
downloadUpdate();
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}, [client, downloadUpdate, showAlert]);
|
|
134
|
+
|
|
135
|
+
const markSuccess = client.markSuccess;
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (isFirstTime) {
|
|
139
|
+
markSuccess();
|
|
140
|
+
}
|
|
141
|
+
if (strategy === 'both' || strategy === 'onAppResume') {
|
|
142
|
+
stateListener.current = AppState.addEventListener(
|
|
143
|
+
'change',
|
|
144
|
+
(nextAppState) => {
|
|
145
|
+
if (nextAppState === 'active') {
|
|
146
|
+
checkUpdate();
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
if (strategy === 'both' || strategy === 'onAppStart') {
|
|
152
|
+
checkUpdate();
|
|
153
|
+
}
|
|
154
|
+
let dismissErrorTimer: ReturnType<typeof setTimeout>;
|
|
155
|
+
const { dismissErrorAfter } = client.options;
|
|
156
|
+
if (typeof dismissErrorAfter === 'number' && dismissErrorAfter > 0) {
|
|
157
|
+
dismissErrorTimer = setTimeout(() => {
|
|
158
|
+
dismissError();
|
|
159
|
+
}, dismissErrorAfter);
|
|
160
|
+
}
|
|
161
|
+
return () => {
|
|
162
|
+
stateListener.current && stateListener.current.remove();
|
|
163
|
+
clearTimeout(dismissErrorTimer);
|
|
164
|
+
};
|
|
165
|
+
}, [checkUpdate, client.options, dismissError, markSuccess, strategy]);
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<PushyContext.Provider
|
|
169
|
+
value={{
|
|
170
|
+
checkUpdate,
|
|
171
|
+
switchVersion,
|
|
172
|
+
switchVersionLater,
|
|
173
|
+
dismissError,
|
|
174
|
+
updateInfo,
|
|
175
|
+
lastError,
|
|
176
|
+
markSuccess,
|
|
177
|
+
client,
|
|
178
|
+
downloadUpdate,
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
</PushyContext.Provider>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
@@ -9,14 +9,12 @@ export interface Spec extends TurboModule {
|
|
|
9
9
|
isFirstTime: boolean;
|
|
10
10
|
rolledBackVersion: string;
|
|
11
11
|
buildTime: string;
|
|
12
|
-
blockUpdate: Object;
|
|
13
12
|
uuid: string;
|
|
14
13
|
isUsingBundleUrl: boolean;
|
|
15
14
|
};
|
|
16
15
|
setLocalHashInfo(hash: string, info: string): Promise<void>;
|
|
17
16
|
getLocalHashInfo(hash: string): Promise<string>;
|
|
18
17
|
setUuid(uuid: string): Promise<void>;
|
|
19
|
-
setBlockUpdate(options: { reason: string; until: number }): Promise<void>;
|
|
20
18
|
reloadUpdate(options: { hash: string }): Promise<void>;
|
|
21
19
|
setNeedUpdate(options: { hash: string }): Promise<void>;
|
|
22
20
|
markSuccess(): Promise<void>;
|
package/{lib → src}/type.ts
RENAMED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
export interface ExpiredResult {
|
|
2
|
-
upToDate?: false;
|
|
3
2
|
expired: true;
|
|
4
3
|
downloadUrl: string;
|
|
5
4
|
}
|
|
6
5
|
|
|
7
6
|
export interface UpTodateResult {
|
|
8
|
-
expired?: false;
|
|
9
7
|
upToDate: true;
|
|
10
8
|
paused?: 'app' | 'package';
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
export interface UpdateAvailableResult {
|
|
14
|
-
|
|
15
|
-
upToDate?: false;
|
|
12
|
+
upToDate: false;
|
|
16
13
|
update: true;
|
|
17
14
|
name: string; // version name
|
|
18
15
|
hash: string;
|
|
@@ -62,10 +59,25 @@ export interface EventData {
|
|
|
62
59
|
newVersion?: string;
|
|
63
60
|
[key: string]: any;
|
|
64
61
|
}
|
|
65
|
-
export type
|
|
62
|
+
export type UpdateEventsLogger = ({
|
|
66
63
|
type,
|
|
67
64
|
data,
|
|
68
65
|
}: {
|
|
69
66
|
type: EventType;
|
|
70
67
|
data: EventData;
|
|
71
68
|
}) => void;
|
|
69
|
+
|
|
70
|
+
export interface PushyServerConfig {
|
|
71
|
+
main: string;
|
|
72
|
+
backups?: string[];
|
|
73
|
+
queryUrl?: string;
|
|
74
|
+
}
|
|
75
|
+
export interface PushyOptions {
|
|
76
|
+
appKey: string;
|
|
77
|
+
server?: PushyServerConfig;
|
|
78
|
+
logger?: UpdateEventsLogger;
|
|
79
|
+
useAlert?: boolean;
|
|
80
|
+
strategy?: 'onAppStart' | 'onAppResume' | 'both';
|
|
81
|
+
autoMarkSuccess?: boolean;
|
|
82
|
+
dismissErrorAfter?: number;
|
|
83
|
+
}
|
package/{lib → src}/utils.ts
RENAMED
package/lib/endpoint.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { logger } from './utils';
|
|
2
|
-
|
|
3
|
-
let currentEndpoint = 'https://update.react-native.cn/api';
|
|
4
|
-
let backupEndpoints: string[] = ['https://update.reactnative.cn/api'];
|
|
5
|
-
let backupEndpointsQueryUrl: string | null = null;
|
|
6
|
-
|
|
7
|
-
export async function updateBackupEndpoints() {
|
|
8
|
-
if (backupEndpointsQueryUrl) {
|
|
9
|
-
try {
|
|
10
|
-
const resp = await fetch(backupEndpointsQueryUrl);
|
|
11
|
-
const remoteEndpoints = await resp.json();
|
|
12
|
-
if (Array.isArray(remoteEndpoints)) {
|
|
13
|
-
backupEndpoints = Array.from(
|
|
14
|
-
new Set([...backupEndpoints, ...remoteEndpoints]),
|
|
15
|
-
);
|
|
16
|
-
logger('fetch remote endpoints:', remoteEndpoints);
|
|
17
|
-
logger('merged backup endpoints:', backupEndpoints);
|
|
18
|
-
}
|
|
19
|
-
} catch (e) {
|
|
20
|
-
logger('fetch remote endpoints failed');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return backupEndpoints;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function getCheckUrl(APPKEY, endpoint = currentEndpoint) {
|
|
27
|
-
return `${endpoint}/checkUpdate/${APPKEY}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param {string} main - The main api endpoint
|
|
32
|
-
* @param {string[]} [backups] - The back up endpoints.
|
|
33
|
-
* @param {string} [backupQueryUrl] - An url that return a json file containing an array of endpoint.
|
|
34
|
-
* like: ["https://backup.api/1", "https://backup.api/2"]
|
|
35
|
-
*/
|
|
36
|
-
export function setCustomEndpoints({
|
|
37
|
-
main,
|
|
38
|
-
backups,
|
|
39
|
-
backupQueryUrl,
|
|
40
|
-
}: {
|
|
41
|
-
main: string;
|
|
42
|
-
backups?: string[];
|
|
43
|
-
backupQueryUrl?: string;
|
|
44
|
-
}) {
|
|
45
|
-
currentEndpoint = main;
|
|
46
|
-
backupEndpointsQueryUrl = null;
|
|
47
|
-
if (Array.isArray(backups) && backups.length > 0) {
|
|
48
|
-
backupEndpoints = backups;
|
|
49
|
-
}
|
|
50
|
-
if (typeof backupQueryUrl === 'string') {
|
|
51
|
-
backupEndpointsQueryUrl = backupQueryUrl;
|
|
52
|
-
}
|
|
53
|
-
}
|
package/lib/index.ts
DELETED
package/lib/index.web.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export const downloadRootDir = '';
|
|
2
|
-
export const packageVersion = '';
|
|
3
|
-
export const currentVersion = '';
|
|
4
|
-
export const isFirstTime = false;
|
|
5
|
-
export const isRolledBack = false;
|
|
6
|
-
|
|
7
|
-
const noop = () => {};
|
|
8
|
-
|
|
9
|
-
export const checkUpdate = noop;
|
|
10
|
-
export const downloadUpdate = noop;
|
|
11
|
-
export const switchVersion = noop;
|
|
12
|
-
export const switchVersionLater = noop;
|
|
13
|
-
export const markSuccess = noop;
|
|
14
|
-
export const downloadAndInstallApk = noop;
|
|
15
|
-
export const setCustomEndpoints = noop;
|
|
16
|
-
export const getCurrentVersionInfo = noop;
|
|
17
|
-
export const simpleUpdate = (app) => app;
|
|
18
|
-
export const onPushyEvents = noop;
|