uni-app开发的app版本更新
标签: uni-app 版本更新
前情
uni-app是我很喜欢的跨平台框架,它能开发小程序,H5,APP(安卓/iOS),对前端开发很友好,自带的IDE让开发体验也很棒,公司项目就是主推uni-app。而是app版本更新是最基本的功能,特记录整个踩坑过程。
版本更新
更新主逻辑
在每次app启动并登录成功的时候做一个版本检测,如果当前版本小于服务端配置的版本号,服务端会告诉是否有更新数据(此处为res.updateFlag,true为需要更新),如果有的话会告诉我去哪里(此次为res下的url)拿更新包数据,客户端再请求res.url拿到更新相关数据(更新包的包地址),如果有更新包地址则弹出弹窗提示用户去更新。
安装更新逻辑为当返回数据url是热更新地址时,则执行热更新逻辑,如果不是则直接调用浏览器去下载安装。
更新关键代码
function checkVersion() {
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
let currVersion = widgetInfo.version;
// 提交版本号和当前appCode,appcode主要是因为我们多个app共用了一套服务端,传此参数是为了告诉服务是哪个app在请求更新
const params = { "appVersionNo": currVersion, "appCode": APPCODE};
// 更新判断接口请求,
uni.request({
url: "更新判断接口地址",
data: params,
success: function(res) {
// console.log("----更新检测数据----:", res);
if (res.updateFlag) {
updateShowModel(res.url, currVersion)
}
}
});
});
// #endif
}
/**
* 更新提示
* @param {string} url
* @param {string} currVersion
*/
function updateShowModel(url, currVersion) {
uni.request({ url, success: json => {
//console.log("----当前从服务端拉取的版本信息----:", json);
if (!json || !json.data || !json.data.versions || !json.data.versions[0]) {
return;
}
const versionData = json.data
const versionInfo = versionData.versions[0];
const forcedVersion = versionData.lastForceVersion;
// 是否强制更新,只有当前版本小于服务端返回的强制更新版本号隐藏处弹窗的取消按钮来达到要求用户强制更新
const isForcedUpdate = versionCompare(currVersion, forcedVersion) == -1;
//console.log("----更新相关数据----:",versionData, isForcedUpdate,currVersion,forcedVersion);
uni.showModal({
title: `发现新版本v${versionInfo.version}`,
content: versionInfo.details.join('\n'),
showCancel: !isForcedUpdate,
success: function (res) {
if (res.confirm) {
updateApp(versionData)
//console.log('用户点击确定');
} else if (res.cancel) {
//console.log('用户点击取消');
}
}
});
}})
}
/**
* 执行更新操作
* @param {Object} versionData
*/
function updateApp(versionData) {
// 如果有热更新配置文件,则热更
if (versionData.wgtUrl) {
startAndroidUpdate(versionData);
return;
}
switch (uni.getSystemInfoSync().platform) {
case 'android':
// 安卓安装包的apk地址
plus.runtime.openURL(versionData.url);
break
case 'ios':
// ios需要特殊处理,需要服务端给一个plist地址
plus.runtime.openURL(`itms-services://?action=download-manifest&url=${versionData.url}`);
break
}
}
/**
* 自动下载安装更新
* @param {Object} versionData 安装包地址相关信息
*/
var showLoading;
function startAndroidUpdate(versionData) {
// 热更新的wgt文件
let url = versionData.wgtUrl;
var dtask = plus.downloader.createDownload(
url, {method:"GET",filename:`_downloads/${APPID}.wgt`},
function(d, status) {
// 下载完成
if (status == 200) {
//console.log("----安装包文件地址----:",d, plus.io.convertLocalFileSystemURL(d.filename), d.filename);
//plus.nativeUI.toast("软件开始安装重启");
showLoading.setTitle(" 安装重启中... ");
plus.runtime.install(d.filename, {force: true}, e => {
plus.nativeUI.closeWaiting();
plus.runtime.restart();
}, function(error) {
console.log("----安装失败01----:", error);
handleWgtInstallFail(versionData);
})
} else {
console.log("----安装失败02----:", d, status);
handleWgtInstallFail(versionData);
}
});
try {
var progress = 0;
showLoading = plus.nativeUI.showWaiting(" 开始下载 "); //创建一个showWaiting对象
dtask.start(); // 开启下载的任务
dtask.addEventListener('statechanged', function(
task,
status
) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
showLoading.setTitle(" 正在下载 0% ");
break;
case 2:
showLoading.setTitle("已连接到服务器");
break;
case 3:
progress = parseInt((parseFloat(task.downloadedSize) / parseFloat(task.totalSize)) * 100);
showLoading.setTitle(" 正在下载" + String(progress).padStart(3, " ") + "% ");
break;
case 4:
//plus.nativeUI.closeWaiting();
//下载完成
break;
}
});
} catch (err) {
plus.nativeUI.closeWaiting();
console.log("----安装失败03----:", err);
handleWgtInstallFail(versionData);
}
}
/**
* 热更新失败处理
*
*/
function handleWgtInstallFail(versionInfo) {
plus.nativeUI.closeWaiting();
uni.showModal({
title: "温馨提示",
content: "自动更新失败,是否手动更新",
success: function (res) {
if (res.confirm) {
plus.runtime.openURL(versionInfo.url);
}
}
});
}
/**
* 版本号比较
* @param {Object} v1 当前版本
* @param {Object} v2 强制更新版本
*/
function versionCompare(v1, v2) {
var GTR = 1; //大于
var LSS = -1; //小于
var EQU = 0; //等于
var v1arr = String(v1).split(".").map(function (a) {
return parseInt(a);
});
var v2arr = String(v2).split(".").map(function (a) {
return parseInt(a);
});
var arrLen = Math.max(v1arr.length, v2arr.length);
var result;
//排除错误调用
if (v1 == undefined || v2 == undefined) {
throw new Error();
}
//检查空字符串,任何非空字符串都大于空字符串
if (v1.length == 0 && v2.length == 0) {
return EQU;
} else if (v1.length == 0) {
return LSS;
} else if (v2.length == 0) {
return GTR;
}
//循环比较版本号
for (var i = 0; i < arrLen; i++) {
result = xxcanghaiComp(v1arr[i], v2arr[i]);
if (result == EQU) {
continue;
} else {
break;
}
}
return result;
function xxcanghaiComp(n1, n2) {
if (typeof n1 != "number") {
n1 = 0;
}
if (typeof n2 != "number") {
n2 = 0;
}
if (n1 > n2) {
return GTR;
} else if (n1 < n2) {
return LSS;
} else {
return EQU;
}
}
}
注意事项
开发过程中在ios下热更是可以的,但是在安卓下一直报如下错误:
{
"code": -1201,
"message": "WGT/WGTU文件格式错误"
}
官方论坛也有人遇到,试了很多解决方法都不行,通过打日志发现安卓下下载下来的包是.bin文件。而不是热更需要的wgt文件,一开始怀疑是包没下载完,但明显是在下载完的回调里处理的,后面想到能不能手动改成.wgt文件,plus.downloader.createDownload第二个参数可以指定下载包的文件名,就这样解决了这个问题。
其实安卓下拿到apk地址是可以不需要通过调用浏览器去下载的,直接走热更新逻辑也是可以的。
uni-app开发的app版本更新的更多相关文章
- App开发到App Store上架,发布流程。
http://blog.csdn.net/wojsg001/article/details/12005887 App开发到App Store上架,发布流程. 分类: IOS2013-09-25 11 ...
- 开发一个App要多少钱?APP开发报价单,APP开发外包有哪些注意事项-广州达到信息www.ddapp.com.cn
来源:广州达到信息著作权归广州达到信息所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作为一个APP开发从业者,经常会有人问到:开发一个App要多少钱?下面针对这个问题来好好解答解答正经的谈 ...
- 《APP开发》APP规范实例-详细的UI设计方法
对了一个APP开发初手来说,可能心里有很多的疑惑: 屏幕设计为多宽,宽度是不是应该设置为百分比; 按钮大小多大,怎么排列,文字字体用多大的?什么字体显示好看?图标多大,怎么用色?界面怎么布局?等等很多 ...
- APICloud APP前端框架——手机APP开发、APP制作、APP定制平台
概述 APICloud前端框架,包括api.js和api.css.api.css处理不同平台浏览器的默认样式.api.js是一个JavaScript库.是APICloud为混合移动开发定制的轻量Jav ...
- 简单5步说清App软件在线开发、App制作多少钱?
开发制作一款App,所有人都会首先关心开发一款App多少钱这个问题.从网上的信息来看,花费个几十万是很正常的事情,甚至有人说要花上百万才能制作出一款App.那么App软件的开发制作到底和什么有关?怎么 ...
- Hybrid App 开发模式
开发移动App主要有三种模式:Native. Hybrid 和 Web App. 需要注意的一点是在选择开发模式的时候,要根据你的项目类型(图片类?视频类?新闻类?等),产品业务和人员技术储备等做权衡 ...
- Native App开发 与Web App开发(原生与web开发优缺点)
Native App开发 Native App开发即我们所称的传统APP开发模式(原生APP开发模式),该开发针对IOS.Android等不同的手机操作系统要采用不同的语言和框架进行开发,该模式通常是 ...
- APP开发项目思维导图
APP开发项目思维导图 下载思维导图:APP开发项目.xmind.zip --------------------------------------- APP开发项目 app项目标记: 未启动 功能 ...
- Android--观察APP运行日志以及APP的工程目录结构解释
运行日志 Log:d--便于跟踪调试 APP开发基础 APP的运行环境 第一种情况,就是在Android studio软件客户端上面使用模拟器运行APP 第二种情况,就是使用真实的手机运行APP程序 ...
- 巧用第三方快速开发Android App 热门第三方SDK及框架
巧用第三方快速开发Android App 热门第三方SDK及框架 历经大半年的时间,终于是把这门课程给录制出来了,也就在今天,正式在慕课网上上线了 项目地址:巧用第三方快速开发Android App ...
随机推荐
- SQL limit字句
limit用法介绍 limit子句可以返回检索查询行的某一连续的部分 用法介绍: SELECT column_list FROM table1 ORDER BY column_list LIMIT r ...
- 第16天:信息打点-CDN绕过&业务部署&漏洞回链&接口探针&全网扫描&反向邮件
#CDN配置: 配置1:加速域名-需要启用加速的域名 配置2:加速区域-需要启用加速的地区 配置3:加速类型-需要启用加速的资源 #参考知识: 超级Ping:http://www.17ce.com/ ...
- 对抗生成网络(GAN)简单介绍
对抗生成网络主要由生成网络和判别网络构成,GAN在图像领域使用较多.利用生成网络生成假的图像,然后利用判别器是否能判断该图像是假的. 1.用于医学图像分割,一般我们可以利用一个U-Net网络生成分割结 ...
- ChatGPT “眼”中的开源数据库
开源作为数据库发展的未来趋势之一,被冠以"数据库弯道超车的法宝"的称号.中国开源数据库产品正处于蓬勃发展的趋势,根据 墨天轮中国数据库流行度 ,截止2023年2月底已有46款开源数 ...
- 【01】DataFrame的创建和属性
DataFrame是一个表格型的数据结构,可以看成就是excel中的表格. 官方文档:https://pandas.pydata.org/docs/reference/frame.html DataF ...
- threejs 父元素 相对位置 position 网格对象
设置position都是相对于父元素的位置设置的 // 导入 threejs import * as THREE from "three"; import { OrbitContr ...
- webpack与grunt、gulp的不同
首先,它们的共同点三者都是前端构建工具,grunt和gulp早期比较流行,现在 webpack 是主流: 区别:grunt 和 gulp 基于 任务和流 : webpack 基于入口文件,webpac ...
- mysql进阶-锁
锁 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(CPU.RAM.I/O)的争用以外,数据也是一种供许多用户共享的资源. 如何保证数据并发访问的一致性.有效性 ...
- FluxCD 多集群应用的设计与实现
前言 FluxCD 是 CNCF 的孵化项目,可以让我们以 GitOps 的方式轻松地交付应用.和另一个同类的 CNCF 孵化项目 ArgoCD 不同,FluxCD 是许多 toolkit 的集合,天 ...
- spring boot下跨域安全配置
1 @Bean 2 public FilterRegistrationBean corsFilter() { 3 final UrlBasedCorsConfigurationSource sourc ...