From 36533d43c44d88c97bb158daa19d386413579827 Mon Sep 17 00:00:00 2001 From: sunnylqm Date: Sun, 21 Jan 2024 14:41:06 +0800 Subject: [PATCH] fix: new version --- Example/testHotUpdate/babel.config.js | 5 + Example/testHotUpdate/package.json | 5 +- Example/testHotUpdate/src/index.js | 279 +++++++++++--------------- Example/testHotUpdate/yarn.lock | 80 +++++++- src/client.tsx | 7 +- src/context.ts | 4 + src/provider.tsx | 71 +++---- 7 files changed, 244 insertions(+), 207 deletions(-) diff --git a/Example/testHotUpdate/babel.config.js b/Example/testHotUpdate/babel.config.js index f842b77..0e47e3b 100644 --- a/Example/testHotUpdate/babel.config.js +++ b/Example/testHotUpdate/babel.config.js @@ -1,3 +1,8 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], + env: { + production: { + plugins: ['react-native-paper/babel'], + }, + }, }; diff --git a/Example/testHotUpdate/package.json b/Example/testHotUpdate/package.json index 2d71ddd..db01693 100644 --- a/Example/testHotUpdate/package.json +++ b/Example/testHotUpdate/package.json @@ -16,7 +16,10 @@ "postinstall-postinstall": "^2.1.0", "react": "18.0.0", "react-native": "0.69.8", - "react-native-update": "link:../.." + "react-native-paper": "^5.12.1", + "react-native-safe-area-context": "^4.8.2", + "react-native-update": "link:../..", + "react-native-vector-icons": "^10.0.3" }, "devDependencies": { "@babel/core": "^7.21.0", diff --git a/Example/testHotUpdate/src/index.js b/Example/testHotUpdate/src/index.js index 1eddb20..e35dc55 100644 --- a/Example/testHotUpdate/src/index.js +++ b/Example/testHotUpdate/src/index.js @@ -1,188 +1,122 @@ -import React, {Component} from 'react'; +import React, {useState} from 'react'; import { StyleSheet, Platform, Text, View, - Alert, TouchableOpacity, - Linking, Image, + Switch, } from 'react-native'; - -import { - isFirstTime, - isRolledBack, - packageVersion, - currentVersion, - checkUpdate, - downloadUpdate, - switchVersion, - switchVersionLater, - markSuccess, - downloadAndInstallApk, - cInfo, -} from 'react-native-update'; +import {Icon, PaperProvider} from 'react-native-paper'; +import {Snackbar, Banner} from 'react-native-paper'; import TestConsole from './TestConsole'; import _updateConfig from '../update.json'; +import {PushyProvider} from '../../../src/provider'; +import {Pushy} from '../../../src/client'; +import {usePushy} from '../../../src/context'; const {appKey} = _updateConfig[Platform.OS]; -export default class App extends Component { - state = { - received: 0, - total: 0, - showTestConsole: false, - }; - componentDidMount() { - if (isRolledBack) { - Alert.alert('提示', '刚刚更新失败了,版本被回滚.'); - } else if (isFirstTime) { - Alert.alert( - '提示', - '这是当前版本第一次启动,是否要模拟启动失败?将回滚到上一版本', - [ - { - text: '是', - onPress: () => { - throw new Error('模拟启动失败,请重启应用'); - }, - }, - { - text: '否', - onPress: () => { - markSuccess(); - }, - }, - ], - ); - } - } - doUpdate = async info => { - try { - const hash = await downloadUpdate(info, { - onDownloadProgress: ({received, total}) => { - this.setState({ - received, - total, + +function App() { + const { + client, + checkUpdate, + downloadUpdate, + switchVersionLater, + switchVersion, + updateInfo, + progress: {received, total} = {}, + } = usePushy(); + const [useDefaultAlert, setUseDefaultAlert] = useState(true); + const [showUpdateBanner, setShowUpdateBanner] = useState(false); + const [showUpdateSnackbar, setShowUpdateSnackbar] = useState(false); + const snackbarVisible = + showUpdateSnackbar && + updateInfo && + updateInfo.updateAvailable && + !useDefaultAlert; + return ( + + 欢迎使用Pushy热更新服务 + { + setUseDefaultAlert(v); + client.setOptions({ + showAlert: v, }); - }, - }); - if (!hash) { - return; - } - Alert.alert('提示', '下载完毕,是否重启应用?', [ - { - text: '是', - onPress: () => { - switchVersion(hash); - }, - }, - {text: '否'}, - { - text: '下次启动时', - onPress: () => { - switchVersionLater(hash); - }, - }, - ]); - } catch (err) { - Alert.alert('更新失败', err.message); - } - }; + }}> + {useDefaultAlert ? '当前使用' : '当前不使用'}默认的alert更新提示 + + + + 这是版本一 {'\n'} + 当前原生包版本号: {packageVersion} + {'\n'} + 当前热更新版本Hash: {currentVersion || '(空)'} + {'\n'} + + + 下载进度:{received} / {total} + + + 点击这里检查更新 + - checkUpdate = async () => { - let info; - try { - info = await checkUpdate(appKey); - } catch (err) { - Alert.alert('更新检查失败', err.message); - return; - } - if (info.expired) { - Alert.alert('提示', '您的应用版本已更新,点击确定下载安装新版本', [ - { - text: '确定', - onPress: () => { - if (info.downloadUrl) { - // apk可直接下载安装 - if ( - Platform.OS === 'android' && - info.downloadUrl.endsWith('.apk') - ) { - downloadAndInstallApk({ - url: info.downloadUrl, - onDownloadProgress: ({received, total}) => { - this.setState({ - received, - total, - }); - }, - }); - } else { - Linking.openURL(info.downloadUrl); - } - } + { + this.setState({showTestConsole: true}); + }}> + + react-native-update版本:{client.version} + + + + { + setShowUpdateSnackbar(false); + }} + action={{ + label: '更新', + onPress: async () => { + setShowUpdateSnackbar(false); + await downloadUpdate(); + setShowUpdateBanner(true); }, - }, - ]); - } else if (info.upToDate) { - Alert.alert('提示', '您的应用版本已是最新.'); - } else { - Alert.alert( - '提示', - '检查到新的版本' + info.name + ',是否下载?\n' + info.description, - [ + }}> + 有新版本({updateInfo.version})可用,是否更新? + + { - this.doUpdate(info); + switchVersionLater(); + setShowUpdateBanner(false); }, }, - {text: '否'}, - ], - ); - } - }; - - render() { - const {received, total, showTestConsole} = this.state; - return ( - - 欢迎使用热更新服务 - - - 这是版本一 {'\n'} - 当前原生包版本号: {packageVersion} - {'\n'} - 当前热更新版本Hash: {currentVersion || '(空)'} - {'\n'} - - - 下载进度:{received} / {total} - - - 点击这里检查更新 - - - { - this.setState({showTestConsole: true}); - }}> - - react-native-update版本:{cInfo.pushy} - - - - - ); - } + ]} + icon={({size}) => ( + + )}> + 更新已完成,是否立即重启? + + + ); } const styles = StyleSheet.create({ @@ -204,3 +138,18 @@ const styles = StyleSheet.create({ }, image: {}, }); + +const pushyClient = new Pushy({ + appKey, + showAlert: false, +}); + +export default function Root() { + return ( + + + + + + ); +} diff --git a/Example/testHotUpdate/yarn.lock b/Example/testHotUpdate/yarn.lock index 2df66c9..eb84e31 100644 --- a/Example/testHotUpdate/yarn.lock +++ b/Example/testHotUpdate/yarn.lock @@ -787,6 +787,14 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@callstack/react-theme-provider@^3.0.9": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz#01035fa1231f1fffc1a806be1b55eb82716e80c1" + integrity sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA== + dependencies: + deepmerge "^3.2.0" + hoist-non-react-statics "^3.3.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2303,7 +2311,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -2322,11 +2330,27 @@ color-name@1.1.3: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + colorette@^1.0.7: version "1.4.0" resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" @@ -3583,6 +3607,13 @@ hermes-profile-transformer@^0.0.6: dependencies: source-map "^0.7.3" +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -3715,6 +3746,11 @@ is-arrayish@^0.2.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -5805,7 +5841,7 @@ prompts@^2.0.1, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: +prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5869,7 +5905,7 @@ react-devtools-core@4.24.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -5894,10 +5930,32 @@ react-native-gradle-plugin@^0.0.7: resolved "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.7.tgz#96602f909745239deab7b589443f14fce5da2056" integrity sha512-+4JpbIx42zGTONhBTIXSyfyHICHC29VTvhkkoUOJAh/XHPEixpuBduYgf6Y4y9wsN1ARlQhBBoptTvXvAFQf5g== +react-native-paper@^5.12.1: + version "5.12.1" + resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-5.12.1.tgz#0c3211f78b4d29a110aa168e6541cfb0a2c6a071" + integrity sha512-6ZBBJBsHxXUG5mD22Q0tArTlk5GpGlhZDkRU1RRqPtTpxWCMc7Dbc04pU3+qG0peJQCAO6GnXqUbkZ0YLnMPNg== + dependencies: + "@callstack/react-theme-provider" "^3.0.9" + color "^3.1.2" + use-latest-callback "^0.1.5" + +react-native-safe-area-context@^4.8.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.8.2.tgz#e6b3d8acf3c6afcb4b5db03a97f9c37df7668f65" + integrity sha512-ffUOv8BJQ6RqO3nLml5gxJ6ab3EestPiyWekxdzO/1MQ7NF8fW1Mzh1C5QE9yq573Xefnc7FuzGXjtesZGv7cQ== + "react-native-update@link:../..": version "0.0.0" uid "" +react-native-vector-icons@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-10.0.3.tgz#369824a3b17994b2cd65edbaa32dbf9540d49678" + integrity sha512-ZgVlV5AdQgnPHHvBEihGf2xwyziT1acpXV1U+WfCgCv3lcEeCRsmwAsBU+kUSNsU+8TcWVsX04kdI6qUaS8D7w== + dependencies: + prop-types "^15.7.2" + yargs "^16.1.1" + react-native@0.69.8: version "0.69.8" resolved "https://registry.npmjs.org/react-native/-/react-native-0.69.8.tgz#3d9b47c42c100455850b47859ff12b66c5ffb689" @@ -6374,6 +6432,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -6975,6 +7040,11 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== +use-latest-callback@^0.1.5: + version "0.1.9" + resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.9.tgz#10191dc54257e65a8e52322127643a8940271e2a" + integrity sha512-CL/29uS74AwreI/f2oz2hLTW7ZqVeV5+gxFeGudzQrgkCytrHw33G4KbnQOrRlAEzzAFXi7dDLMC9zhWcVpzmw== + use-sync-external-store@^1.0.0: version "1.2.0" resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" @@ -7240,7 +7310,7 @@ yargs@^15.1.0, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.3: +yargs@^16.0.3, yargs@^16.1.1: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== diff --git a/src/client.tsx b/src/client.tsx index 03287d6..a279a1b 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -41,17 +41,22 @@ export class Pushy { marked = false; applyingUpdate = false; + version = cInfo.pushy; constructor(options: PushyOptions) { if (!options.appKey) { throw new Error('appKey is required'); } + this.setOptions(options); + } + + setOptions = (options: Partial) => { for (const [key, value] of Object.entries(options)) { if (value !== undefined) { this.options[key] = value; } } - } + }; getCheckUrl = (endpoint: string = this.options.server!.main) => { return `${endpoint}/checkUpdate/${this.options.appKey}`; diff --git a/src/context.ts b/src/context.ts index 2f1f430..6e2202b 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,6 @@ import { createContext, useContext } from 'react'; import { CheckResult, ProgressData } from './type'; +import { Pushy } from './client'; const empty = {}; const noop = () => {}; @@ -10,6 +11,7 @@ export const defaultContext = { switchVersionLater: noop, markSuccess: noop, dismissError: noop, + downloadUpdate: noop, }; export const PushyContext = createContext<{ @@ -21,6 +23,8 @@ export const PushyContext = createContext<{ updateInfo?: CheckResult; lastError?: Error; dismissError: () => void; + client?: Pushy; + downloadUpdate: () => void; }>(defaultContext); export const usePushy = () => useContext(PushyContext); diff --git a/src/provider.tsx b/src/provider.tsx index 92efcda..50cc661 100644 --- a/src/provider.tsx +++ b/src/provider.tsx @@ -14,7 +14,7 @@ import { } from 'react-native'; import { Pushy } from './client'; import { isFirstTime } from './core'; -import { UpdateAvailableResult, CheckResult } from './type'; +import { CheckResult } from './type'; import { PushyContext } from './context'; export const PushyProvider = ({ @@ -56,38 +56,37 @@ export const PushyProvider = ({ } }, [client, updateInfo]); - const doUpdate = useCallback( - async (info: UpdateAvailableResult) => { - try { - const hash = await client.downloadUpdate(info); - if (!hash) { - return; - } - setUpdateInfo(info); - stateListener.current && stateListener.current.remove(); - showAlert('Download complete', 'Do you want to apply the update now?', [ - { - text: '下次再说', - style: 'cancel', - onPress: () => { - client.switchVersionLater(hash); - }, - }, - { - text: '立即更新', - style: 'default', - onPress: () => { - client.switchVersion(hash); - }, - }, - ]); - } catch (err) { - setLastError(err); - showAlert('Failed to update', err.message); + const downloadUpdate = useCallback(async () => { + if (!updateInfo || !('update' in updateInfo)) { + return; + } + try { + const hash = await client.downloadUpdate(updateInfo); + if (!hash) { + return; } - }, - [client, showAlert], - ); + stateListener.current && stateListener.current.remove(); + showAlert('Download complete', 'Do you want to apply the update now?', [ + { + text: '下次再说', + style: 'cancel', + onPress: () => { + client.switchVersionLater(hash); + }, + }, + { + text: '立即更新', + style: 'default', + onPress: () => { + client.switchVersion(hash); + }, + }, + ]); + } catch (err) { + setLastError(err); + showAlert('Failed to update', err.message); + } + }, [client, showAlert, updateInfo]); const checkUpdate = useCallback(async () => { let info: CheckResult; @@ -98,9 +97,9 @@ export const PushyProvider = ({ showAlert('Failed to check update', err.message); return; } + setUpdateInfo(info); if ('expired' in info) { const { downloadUrl } = info; - setUpdateInfo(info); showAlert( 'Major update', 'A full update is required to download and install to continue.', @@ -129,13 +128,13 @@ export const PushyProvider = ({ text: '确定', style: 'default', onPress: () => { - doUpdate(info as UpdateAvailableResult); + downloadUpdate(); }, }, ], ); } - }, [client, doUpdate, showAlert]); + }, [client, downloadUpdate, showAlert]); const markSuccess = client.markSuccess; @@ -179,6 +178,8 @@ export const PushyProvider = ({ updateInfo, lastError, markSuccess, + client, + downloadUpdate, }} > {children}