mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-09-17 15:26:10 +08:00
203 lines
5.1 KiB
TypeScript
203 lines
5.1 KiB
TypeScript
import React, {
|
|
ReactNode,
|
|
useCallback,
|
|
useEffect,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
import {
|
|
Alert,
|
|
NativeEventSubscription,
|
|
AppState,
|
|
Platform,
|
|
Linking,
|
|
} from 'react-native';
|
|
import { Pushy } from './client';
|
|
import {
|
|
currentVersion,
|
|
isFirstTime,
|
|
packageVersion,
|
|
getCurrentVersionInfo,
|
|
} from './core';
|
|
import { CheckResult, ProgressData } from './type';
|
|
import { PushyContext } from './context';
|
|
|
|
export const PushyProvider = ({
|
|
client,
|
|
children,
|
|
}: {
|
|
client: Pushy;
|
|
children: ReactNode;
|
|
}) => {
|
|
const { options } = client;
|
|
const stateListener = useRef<NativeEventSubscription>();
|
|
const [updateInfo, setUpdateInfo] = useState<CheckResult>();
|
|
const [progress, setProgress] = useState<ProgressData>();
|
|
const [lastError, setLastError] = useState<Error>();
|
|
|
|
const dismissError = useCallback(() => {
|
|
setLastError(undefined);
|
|
}, []);
|
|
|
|
const showAlert = useCallback(
|
|
(...args: Parameters<typeof Alert.alert>) => {
|
|
if (options.useAlert) {
|
|
Alert.alert(...args);
|
|
}
|
|
},
|
|
[options],
|
|
);
|
|
|
|
const switchVersion = useCallback(() => {
|
|
if (updateInfo && updateInfo.hash) {
|
|
client.switchVersion(updateInfo.hash);
|
|
}
|
|
}, [client, updateInfo]);
|
|
|
|
const switchVersionLater = useCallback(() => {
|
|
if (updateInfo && updateInfo.hash) {
|
|
client.switchVersionLater(updateInfo.hash);
|
|
}
|
|
}, [client, updateInfo]);
|
|
|
|
const downloadUpdate = useCallback(async () => {
|
|
if (!updateInfo || !updateInfo.update) {
|
|
return;
|
|
}
|
|
try {
|
|
const hash = await client.downloadUpdate(updateInfo, setProgress);
|
|
if (!hash) {
|
|
return;
|
|
}
|
|
stateListener.current && stateListener.current.remove();
|
|
showAlert('提示', '下载完毕,是否立即更新?', [
|
|
{
|
|
text: '下次再说',
|
|
style: 'cancel',
|
|
onPress: () => {
|
|
client.switchVersionLater(hash);
|
|
},
|
|
},
|
|
{
|
|
text: '立即更新',
|
|
style: 'default',
|
|
onPress: () => {
|
|
client.switchVersion(hash);
|
|
},
|
|
},
|
|
]);
|
|
} catch (err) {
|
|
setLastError(err);
|
|
showAlert('更新失败', err.message);
|
|
}
|
|
}, [client, showAlert, updateInfo]);
|
|
|
|
const downloadAndInstallApk = useCallback(
|
|
async (downloadUrl: string) => {
|
|
if (Platform.OS === 'android' && downloadUrl) {
|
|
await client.downloadAndInstallApk(downloadUrl, setProgress);
|
|
}
|
|
},
|
|
[client],
|
|
);
|
|
|
|
const checkUpdate = useCallback(async () => {
|
|
let info: CheckResult;
|
|
try {
|
|
info = await client.checkUpdate();
|
|
} catch (err) {
|
|
setLastError(err);
|
|
showAlert('更新检查失败', err.message);
|
|
return;
|
|
}
|
|
setUpdateInfo(info);
|
|
if (info.expired) {
|
|
const { downloadUrl } = info;
|
|
showAlert('提示', '您的应用版本已更新,点击更新下载安装新版本', [
|
|
{
|
|
text: '更新',
|
|
onPress: () => {
|
|
if (downloadUrl) {
|
|
if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) {
|
|
downloadAndInstallApk(downloadUrl);
|
|
} else {
|
|
Linking.openURL(downloadUrl);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
]);
|
|
} else if (info.update) {
|
|
showAlert(
|
|
'提示',
|
|
'检查到新的版本' + info.name + ',是否下载?\n' + info.description,
|
|
[
|
|
{ text: '取消', style: 'cancel' },
|
|
{
|
|
text: '确定',
|
|
style: 'default',
|
|
onPress: () => {
|
|
downloadUpdate();
|
|
},
|
|
},
|
|
],
|
|
);
|
|
}
|
|
}, [client, downloadAndInstallApk, downloadUpdate, showAlert]);
|
|
|
|
const markSuccess = client.markSuccess;
|
|
|
|
useEffect(() => {
|
|
const { strategy, dismissErrorAfter, autoMarkSuccess } = options;
|
|
if (isFirstTime && autoMarkSuccess) {
|
|
markSuccess();
|
|
}
|
|
if (strategy === 'both' || strategy === 'onAppResume') {
|
|
stateListener.current = AppState.addEventListener(
|
|
'change',
|
|
(nextAppState) => {
|
|
if (nextAppState === 'active') {
|
|
checkUpdate();
|
|
}
|
|
},
|
|
);
|
|
}
|
|
if (strategy === 'both' || strategy === 'onAppStart') {
|
|
checkUpdate();
|
|
}
|
|
let dismissErrorTimer: ReturnType<typeof setTimeout>;
|
|
if (typeof dismissErrorAfter === 'number' && dismissErrorAfter > 0) {
|
|
dismissErrorTimer = setTimeout(() => {
|
|
dismissError();
|
|
}, dismissErrorAfter);
|
|
}
|
|
return () => {
|
|
stateListener.current && stateListener.current.remove();
|
|
clearTimeout(dismissErrorTimer);
|
|
};
|
|
}, [checkUpdate, options, dismissError, markSuccess]);
|
|
|
|
return (
|
|
<PushyContext.Provider
|
|
value={{
|
|
checkUpdate,
|
|
switchVersion,
|
|
switchVersionLater,
|
|
dismissError,
|
|
updateInfo,
|
|
lastError,
|
|
markSuccess,
|
|
client,
|
|
downloadUpdate,
|
|
packageVersion,
|
|
currentHash: currentVersion,
|
|
progress,
|
|
downloadAndInstallApk,
|
|
getCurrentVersionInfo,
|
|
}}
|
|
>
|
|
{children}
|
|
</PushyContext.Provider>
|
|
);
|
|
};
|