Implement app hot update using uniapp development

Ah~ I finally have some free time after many months. I recently sorted out the information and found that hot updates are common in app development. They are basically necessary and really convenient, so I summarized some things for everyone to see. If you have any questions, you can discuss them together.

1. What are needed to implement hot update?

The server is required to store update package resources, and the backend provides an interface to detect whether the current version is the latest version. (Add, delete, modify and check)
The process of hot update is actually very simple, as shown in the figure below

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

2. Specific process code

1. Get the current app version

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

2. Obtain the update package resources on the server (including download link, update package version), and compare whether the current version is the latest version. If not, a prompt will pop up to update to the latest version.

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. The user selects the updated version to download the update package.

// 下载补丁
// 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
	}
},

This completes the hot update function. It doesn’t look difficult. Finally, I will post the complete code I wrote. It is best to encapsulate it into a component.

<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('<this.globalData.version>', 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 file


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
}

Finally, attached is how to package the update package. This is also simple, just like packaging the installation package.
Insert image description here

Just choose to make a wgt package, then click Generate, and then wait for packaging. Update packages are generally faster than installation packages and there is no limit on the number of times.
Insert image description here

It’s also worth noting that you remember to change the version number and version name every time you package. See you
Insert image description here
next time! ! ! !

Guess you like

Origin blog.csdn.net/qingshui_zhuo/article/details/121227253