使用uniapp开发实现 app热更新

啊~时隔多月终于闲下来了。最近整理了下资料发现热更新在app开发是经常见的,基本必备而且确实很方便,所以就总结了点东西给大家看看,有问题可以一起讨论

一、实现热更新需要那些东西

需要服务器存放更新包资源,后端提供接口用于检测当前版本是否为最新版本。(增删改查)
热更新的流程其实很简单,如下图所示

用户进入应用
检测是否有更新
需要更新
请求资源更新包
下载安装
下载完成重启
取消下载
不需要更新
正常运行

二、具体流程代码

1.获取当前应用app版本

// 保存 app 版本信息
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, (widgetInfo)=> {
	// console.log('widgetInfo', widgetInfo);
	this.version = widgetInfo.version;
});
// #endif

2.获取服务器上更新包的资源(包含下载链接,更新包版本),比较当前版本是否为最新版本,不是则弹出提示更新最新版本

checkWgtFun() {
	//loginApi.getPatchManage() 获取更新包接口
	loginApi.getPatchManage().then(res=> {
		console.log('检查更新包', res);
		if(res.code == 200) {
			let result = res.data.versionNum // 更新包版本
			if(this.version.substr(0, 3) * 1 >= result.substr(0, 3) * 1){
				this.$toast('当前为最新版本');
				return
			} 
			if(this.version.replace(/\./g, "") * 1 >= result.replace(/\./g, "") * 1){
				this.$toast('当前为最新版本');
				return
			}
			uni.showModal({
				title: '提示',
				content: '发现有新版本可以升级',
				cancelText: '取消更新',
				confirmText: '立即更新',
				success: res1 => {
					if (res1.confirm) {
						console.log('用户点击确定');
						// 补丁下载安装
						// this.versionNum=res.data.versionNum
						this.downWgt(res.data.patchUrl)
					} else if (res1.cancel) {
						console.log('用户点击取消');
					}
				},
				fail: (err) => {
					console.log('下载失败', err);
				}
			});
		} else {
			this.$toast(res.msg);
		}
	})
	},

3.用户选择更新版本下载更新包

// 下载补丁
// patchUrl 更新包下载路径
downWgt(patchUrl) {
	let _this=this
	this.downloadTask = uni.downloadFile({
		url:patchUrl,
		success: (downloadResult) => {
			if (downloadResult.statusCode === 200) {  
				// 安装应用
				plus.runtime.install(
					downloadResult.tempFilePath, 
					{force: false}, 
				()=> {  
					plus.nativeUI.toast('最新版本下载完成')
					// 安装成功之后关闭应用重启app
					plus.runtime.restart();  
				}, (e)=> {  
					plus.nativeUI.toast("补丁安装失败")// 常见问题:版本号,appId
				});  
			}
		},
		fail: (err) => {
			plus.nativeUI.toast("补丁下载失败")
		}
	})
},
// 用户取消更新,中断下载
cancel() {
	if(this.downloadTask) {
		this.$toast('取消下载安装!')
		this.downloadTask.abort()
		this.downloadTask = null
	}
},

到此就完成了热更新的功能,看着不难吧,最后贴出我写的完整的代码,最好封装成一个组件

<template>
	<view>
		<view @click="checkApp" v-if="verShow">
			<u-cell-item title="检查新版本" :value='version' :arrow='false'></u-cell-item>
		</view>
		<u-mask :show="show">
				<view class="warp">
					<view class="version">
						<view class="new-version">发现新版本</view>
						<view style="color: #fff;">v {{versionNum}}</view>
						<view class="be-updating">正在更新</view>
						<u-line-progress :percent='schedule.progress' :show-percent='false' active-color='#4B86FE' striped striped-active></u-line-progress>
						<view class="down-prog">{{schedule.totalBytesWritten}}/{{schedule.totalBytesExpectedToWrite}}</view>
						<view class="cancel" @click="cancel">取消升级</view>
					</view>
				</view>
			</u-mask>
	</view>
</template>

<script>
	import {mineApi,loginApi} from '@/api/myAjax.js'
	import filters from '@/common/filters.js'
	export default {
		props:{
			verShow:{
				type:Boolean,
				default:true
			},
			
		},
		data() {
			return {
				versionNum:'',
				schedule:{},
				show: false,
				downloadTask:null,
				time:10,
				isCheck:false
				// versionText:''
			};
		},
		computed:{
			version() {
			 	// 获取版本号(在其他地方需要用到所以存了全局变量)
				return getApp().globalData.version
			}
		},
		methods:{
			// 检查补丁更新
			checkWgtFun() {
				loginApi.getPatchManage().then(res=> {
					console.log('检查补丁更新包', res);
					console.log('', uni.getStorageSync('appVersion'));
					if(res.code == 200) {
						let result = res.data.versionNum
						if(this.version.substr(0, 3) * 1 > result.substr(0, 3) * 1){
							if(this.verShow){
								this.$toast('当前为最新版本');
							}
							return
						} 
						if(this.version.replace(/\./g, "") * 1 >= result.replace(/\./g, "") * 1){
							if(this.verShow){
								this.$toast('当前为最新版本');
							}
							return
						}
						uni.showModal({
							title: '提示',
							content: '发现有新版本可以升级',
							cancelText: '取消更新',
							confirmText: '立即更新',
							success: res1 => {
								if (res1.confirm) {
									console.log('用户点击确定');
									console.log(res);
									// 补丁下载安装
									this.versionNum=res.data.versionNum
									this.downWgt(res.data.patchUrl)
								} else if (res1.cancel) {
									console.log('用户点击取消');
								}
							},
							fail: (err) => {
								console.log('下载失败', err);
							}
						});
					} else {
						this.isCheck = false
					}
				})
			},
			// 下载补丁
			downWgt(patchUrl) {
				let _this=this
				console.log(patchUrl);
				this.isCheck = false
				this.show = true
				this.downloadTask = uni.downloadFile({
					url:patchUrl,
					success: (downloadResult) => {
						if (downloadResult.statusCode === 200) {  
							// 安装应用
							plus.runtime.install(downloadResult.tempFilePath, {force: false}, ()=> {  
								_this.show =false
								plus.nativeUI.toast('最新版本下载完成')
								// 安装成功之后重启
								plus.runtime.restart();  
							}, (e)=> {  
								_this.show =false
								plus.nativeUI.toast("补丁下载失败")
							});  
						}
					},
					fail: (err) => {
						_this.show =false
						plus.nativeUI.toast("补丁下载失败")
					}
				})
				this.downloadTask.onProgressUpdate((res) => {
					// 当前下载进度
					if(this.time%10==0){
						this.schedule=res
						this.schedule.totalBytesExpectedToWrite=filters.sizeMB(res.totalBytesExpectedToWrite)
						this.schedule.totalBytesWritten=filters.sizeMB(res.totalBytesWritten)
					}
					this.time+=1
				});
			},
			// 关闭蒙层 中断下载
			cancel() {
				if(this.downloadTask) {
					this.$toast('取消下载安装!')
					this.downloadTask.abort()
					this.downloadTask = null
					this.show=false
					this.schedule={}
				}
			},
		}
	}
</script>

<style lang="scss" scoped>
.version{
	width: 521rpx;
	height: 583rpx;
	font-size: 24rpx;
	padding: 207rpx 44rpx 33rpx;
	background: url(/static/mine/gxt.png) no-repeat;
	background-size: 100% 100%;
	.new-version{
		font-size: 30rpx;
		color: #fff;
		margin-bottom: 7rpx;
		height: 45rpx;
		line-height: 45rpx;
	}
	.be-updating{
		margin-top: 96rpx;
		margin-bottom: 14rpx;
	}
	.down-prog{
		margin: 14rpx 0;
	}
	.cancel{
		text-align: right;
		color: #2CA6F8;
	}
}
</style>

filters.js文件


function sizeMB(size){
	if(size<1024){
		return size+'B'; 
	}else if(size/1024>=1 && size/1024/1024<1){
		return Math.floor(size/1024*100)/100+'KB';
	}else if(size/1024/1024>=1){
		return Math.floor(size/1024/1024*100)/100+'MB';
	}
}
export default {
	sizeMB
}

最后在附上如何打包更新包,这个也简单,跟打包安装包一样
使用uniapp开发实现 app热更新_第1张图片

选择制作wgt包,然后点击生成就可以了,然后就等待打包,更新包一般比安装包快且没有次数限制
使用uniapp开发实现 app热更新_第2张图片

还有值得注意的是记得每次打包记得更改版本号跟版本名称这两个地方哦
使用uniapp开发实现 app热更新_第3张图片
有缘下次见!!!!

你可能感兴趣的:(uniapp,javascript,uni-app)