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 ...
随机推荐
- 邀请你参与字节跳动 UME 插件开发竞赛
UME 是由字节跳动 Flutter Infra 团队出品和维护的 Flutter 应用内调试工具.通过在 Flutter 应用中加入 UME 工具,开发者们可以直接在应用内查看调试信息,而无需使用 ...
- 《TensorFlow+Keras自然语言处理实战》已出版
<TensorFlow+Keras自然语言处理实战>已出版 当当京东天猫均有出售.清华社官网信息如下: http://www.tup.tsinghua.edu.cn/booksCenter ...
- spring boot 向nacos注册方式,以及遇见的报错(boot!boot! 不是cloud!)
一.首先添加nacos注册发现的pom依赖 <dependency> <groupId>com.alibaba.boot</groupId> <artifac ...
- cornerstone中RAFT的buffer的实现
1.概览: 谈到raft协议实现就绕不开网上流行的mit6.824,但其为go语言,官方没有lab的答案,框架也很晦涩难懂,且全网没有一个博客对其有清晰的解释,有的只是甩一堆名词然后直接贴没有任何注释 ...
- jetpack1
组合函数 package com.example.myapplication1 import android.os.Bundle import androidx.activity.ComponentA ...
- fiddler限速配置&mock配置
一.限速配置 1.开启性能选项 2.找到对应的参数入口 3.修改对应的从参数 解释下 这2个参数是如何做到限速的 4.request-trickle-delay(上传数据限制) 默认值是300,他的意 ...
- Issac_GYM对Go2机器人的仿真心得
override 覆盖 torques 扭矩 1 args()参数信息等 cd /home/yyds/桌面/Gym2/legged_robot_competition-master/legged_gy ...
- WinDbg调试命令之线程操作
WinDbg的线程操作命令可以帮助开发人员诊断和解决多线程应用程序中的问题,常用的命令有以下这些. ~*e - 列出当前进程中的所有线程 这个命令会列出当前进程中的所有线程,包括它们的线程ID.状态. ...
- 5.5 Vim移动光标命令汇总
Vim 文本编辑器中,最简单的移动光标的方式是使用方向键,但这种方式的效率太低,更高效的方式使用快捷键. Vim 移动光标常用的快捷键及其功能如下面各表所示,需要注意的是,表中所有的快捷键都在命令模式 ...
- debug指南-基础bug
基础Bug 本章节主要阐述一些最基本的bug. 虽然这些bug看起来很弱智简单,但正是因为这些小bug,让我们调代码的时间增加至少 \(2,3\) 个小时. 本系列的宗旨就是综合这些小bug极其对应解 ...