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(); const [updateInfo, setUpdateInfo] = useState(); const [progress, setProgress] = useState(); const [lastError, setLastError] = useState(); const dismissError = useCallback(() => { setLastError(undefined); }, []); const showAlert = useCallback( (...args: Parameters) => { 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; if (typeof dismissErrorAfter === 'number' && dismissErrorAfter > 0) { dismissErrorTimer = setTimeout(() => { dismissError(); }, dismissErrorAfter); } return () => { stateListener.current && stateListener.current.remove(); clearTimeout(dismissErrorTimer); }; }, [checkUpdate, options, dismissError, markSuccess]); return ( {children} ); };