UNPKG

uni-update-check

Version:

跨端(微信小程序 & App)的一体化版本更新检查工具,用于uni-app项目。支持wgt热更新、APK整包更新、iOS商店跳转以及小程序原生更新。

157 lines (142 loc) 4.26 kB
'use strict'; const { compareVersion } = require('./utils'); /** * 读取本地应用版本 * @returns {Promise<string>} */ function getLocalVersion() { return new Promise((resolve) => { try { if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.getProperty) { plus.runtime.getProperty(plus.runtime.appid, (info) => { resolve(info.version || '0.0.0'); }); } else { resolve('0.0.0'); } } catch (e) { resolve('0.0.0'); } }); } /** * 拉取服务端更新信息 * @param {string} url * @returns {Promise<object>} */ function fetchServerMeta(url) { return new Promise((resolve, reject) => { if (!url) return resolve(null); uni.request({ url, method: 'GET', success: (res) => resolve(res.data || null), fail: reject }); }); } /** * 下载并安装(支持 wgt/apk)。iOS 使用 AppStore URL 跳转。 * @param {object} meta * @param {object} options */ function doUpdate(meta, options) { const { onProgress } = options || {}; const type = String(meta.type || '').toLowerCase(); const isIOS = uni.getSystemInfoSync().platform === 'ios'; if (isIOS) { // iOS:走 AppStore if (meta.iosAppStoreUrl) { plus.runtime.openURL(meta.iosAppStoreUrl); } else { uni.showToast({ title: '请前往 App Store 更新', icon: 'none' }); } return; } if (type === 'wgt') { if (!meta.urlWgt) { uni.showToast({ title: '缺少 wgt 地址', icon: 'none' }); return; } downloadAndInstall(meta.urlWgt, 'wgt', onProgress); } else if (type === 'apk') { if (!meta.urlApk) { uni.showToast({ title: '缺少 apk 地址', icon: 'none' }); return; } downloadAndInstall(meta.urlApk, 'apk', onProgress); } else { // 未知类型:优先用 wgt if (meta.urlWgt) return downloadAndInstall(meta.urlWgt, 'wgt', onProgress); if (meta.urlApk) return downloadAndInstall(meta.urlApk, 'apk', onProgress); uni.showToast({ title: '未提供有效更新包', icon: 'none' }); } } /** * 下载并安装 * @param {string} url * @param {'wgt'|'apk'} pkgType * @param {(p:number)=>void} onProgress */ function downloadAndInstall(url, pkgType, onProgress) { try { const dtask = plus.downloader.createDownload(url, {}, (d, status) => { if (status === 200) { plus.runtime.install(d.filename, { force: true }, () => { plus.runtime.restart(); }, (e) => { console.error('安装失败', e); uni.showToast({ title: '安装失败', icon: 'none' }); }); } else { uni.showToast({ title: '下载失败', icon: 'none' }); } }); dtask.addEventListener('statechanged', (task, status) => { // 3: 下载中, 4: 已完成 if (task.state === 3 && task.totalSize) { const p = Math.floor(task.downloadedSize / task.totalSize * 100); onProgress && onProgress(p); } else if (task.state === 4) { onProgress && onProgress(100); } }); dtask.start(); } catch (e) { console.error('创建下载任务失败', e); uni.showToast({ title: '创建下载任务失败', icon: 'none' }); } } /** * App端检查更新入口 * @param {{url?: string, title?: string, content?: string, onProgress?: Function, confirmBeforeUpdate?: Function}} options */ async function checkUpdateApp(options = {}) { const { url, title = '发现新版本', content = '是否立即更新?', confirmBeforeUpdate } = options; const localVer = await getLocalVersion(); const meta = await fetchServerMeta(url); if (!meta) return; if (!compareVersion(meta.version, localVer)) { return; // 已是最新 } // 用户自定义确认弹窗 if (typeof confirmBeforeUpdate === 'function') { const intercepted = await Promise.resolve(confirmBeforeUpdate(meta)); if (intercepted) return; } // 默认弹窗 const msg = (meta.note ? (meta.note + '\n') : '') + content; uni.showModal({ title, content: msg, showCancel: meta.force ? false : true, success: (res) => { if (res.confirm || meta.force) { doUpdate(meta, options); } } }); } module.exports = { checkUpdateApp };