import { getLastData } from '../api/user.js' /** 规范化版本号,如 v1.6.83 → [1, 6, 83] */ const normalizeVersion = (version) => { if (!version) return [] return String(version) .replace(/^v/i, '') .split('.') .map((part) => parseInt(part, 10) || 0) } /** * 比较版本号 * @returns 1 远端较新需更新 | 0 相同 | -1 本地较新 */ const compareVersion = (remote, local) => { const remoteParts = normalizeVersion(remote) const localParts = normalizeVersion(local) const len = Math.max(remoteParts.length, localParts.length) for (let i = 0; i < len; i++) { const rv = remoteParts[i] || 0 const lv = localParts[i] || 0 if (rv > lv) return 1 if (rv < lv) return -1 } return 0 } /** 自定义调试基座 / HBuilder 标准基座,不走线上更新 */ const isCustomDebugBase = (appName = '') => { return /自定义基座|custom debug|HBuilder|DCloud/i.test(appName) } export const checkAppUpdate = () => { // #ifndef APP-PLUS return // #endif // 开发环境跳过检查 const isDev = process.env.NODE_ENV === 'development' if (isDev) { console.log('开发环境,不执行更新检查') return } // 自定义基座调试,跳过更新检查 // try { // const { appName } = uni.getSystemInfoSync() // if (isCustomDebugBase(appName)) { // console.log('自定义基座调试中,不执行更新检查') // return // } // } catch (e) {} // 获取当前应用信息 plus.runtime.getProperty(plus.runtime.appid, (info) => { // if (isCustomDebugBase(info?.name)) { // console.log('自定义基座调试中,不执行更新检查') // return // } const currentVersion = info.version getLastData() .then((res) => { // let res = { // data: { // versionName: 'v1.6.83', // forceUpdate: '1', // androidPath: 'https://app.liuyingyong.cn/build/download/3c26e400-3a33-11f1-8997-a16e76fa35b3', // // androidPath: 'http://112.4.144.18:8040/shiningCloud/file/canneng_wulian.apk', // iosPath: 'xxxx', // }, // } if (!res?.data) { console.log('未获取到版本信息') return } // 适配新的接口返回格式,默认强制更新 const { versionName, androidPath, iosPath, forceUpdate = '1' } = res.data console.log('🚀 ~ checkAppUpdate ~ versionName, currentVersion:', versionName, currentVersion) // 版本相同或本地较新则不需要更新 if (compareVersion(versionName, currentVersion) <= 0) { console.log('已是最新版本') return } const isForce = forceUpdate !== '0' // 默认强制更新,'0' 为可选更新 const iosUrl = iosPath handleUpdate({ version: versionName, androidPath, iosUrl, isForce }) }) .catch((err) => { console.error('获取版本接口失败', err) }) }) } /** * 处理更新逻辑 */ const handleUpdate = ({ version, androidPath, iosUrl, isForce }) => { const isAndroid = plus.os.name === 'Android' const isIOS = plus.os.name === 'iOS' if (isAndroid) { handleAndroidUpdate({ version, androidPath, isForce }) } else if (isIOS) { handleIOSUpdate({ version, iosUrl, isForce }) } else { console.warn('未知操作系统') } } /** * 处理安卓更新 */ const handleAndroidUpdate = ({ version, androidPath, isForce }) => { if (!androidPath?.length) { console.error('未找到安卓安装包') uni.showToast({ title: '更新包不存在', icon: 'error', }) return } const downloadUrl = androidPath const content = isForce ? `发现新版本 ${version},请立即更新后继续使用` : `发现新版本 ${version},是否立即更新?` uni.showModal({ title: '更新提示', content, showCancel: false, confirmText: '去更新', success: (modalRes) => { if (modalRes.confirm) { downloadAndInstallApk(downloadUrl) } else if (isForce) { // 强制更新:用户按返回键关闭弹窗时退出 plus.runtime.quit() } }, }) } /** * 处理iOS更新 */ const handleIOSUpdate = ({ version, iosUrl, isForce }) => { if (!iosUrl) { console.error('未找到iOS下载链接') uni.showToast({ title: '更新链接不存在', icon: 'error', }) return } const content = isForce ? `发现新版本 ${version},请前往 App Store 更新后继续使用` : `发现新版本 ${version},请前往 App Store 更新` uni.showModal({ title: '更新提示', content, showCancel: false, confirmText: '去更新', success: (modalRes) => { if (modalRes.confirm) { plus.runtime.openURL(iosUrl) setTimeout(() => { plus.runtime.quit() }, 300) } else if (isForce) { // 强制更新且用户取消,退出应用 } }, }) } /** * 下载并安装APK(安卓专用) */ const downloadAndInstallApk = (url) => { // 显示原生进度条 let progressWaiting = plus.nativeUI.showWaiting('正在下载中,请稍等...', { modal: true, round: true, close: false, // 不允许用户关闭 padlock: true, // 锁定屏幕 }) let progressClosed = false const closeProgress = () => { if (progressClosed) return progressClosed = true progressWaiting.close() } const options = { filename: '_doc/update/canneng_wulian.apk', timeout: 300, } console.log('🚀 ~ downloadAndInstallApk ~ url:', url) const downloadTask = plus.downloader.createDownload(url, options, (downloadedFile, status) => { closeProgress() if (status === 200) { installApk(downloadedFile.filename, url) } else { handleDownloadError(url) } }) // // 更新进度 downloadTask.addEventListener('statechanged', (task) => { if (progressClosed) return if (task.state === 3 && task.totalSize > 0) { const percent = ((task.downloadedSize / task.totalSize) * 100).toFixed(0) console.log('🚀 ~ downloadAndInstallApk ~ percent:', percent) // 直接更新 waiting 的标题,不会闪烁 progressWaiting.setTitle(`正在下载更新 ${percent}%`) } }) downloadTask.start() } /** * 安装APK */ const installApk = (filePath, downloadUrl) => { console.log('🚀 ~ installApk ~ filePath:', filePath) plus.runtime.install( filePath, { force: true }, () => { // 安装成功 uni.showModal({ title: '安装成功', content: '是否立即重启应用?', showCancel: false, confirmText: '立即重启', success: () => { plus.runtime.restart() }, }) }, (error) => { console.error('安装失败', error) uni.showModal({ title: '安装失败', content: `安装失败:${error.message}\n请检查是否已开启安装权限`, showCancel: false, confirmText: '重试', success: (res) => { if (res.confirm) { downloadAndInstallApk(downloadUrl) } else { plus.runtime.quit() } }, }) }, ) } /** * 处理下载错误 */ const handleDownloadError = (downloadUrl) => { uni.showModal({ title: '下载失败', content: '网络异常或下载链接失效,是否重试?', showCancel: false, confirmText: '重试', success: (res) => { if (res.confirm) { downloadAndInstallApk(downloadUrl) } else { plus.runtime.quit() } }, }) }