Files
app-govern/common/js/update.js
2026-06-18 16:34:25 +08:00

292 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}
},
})
}