ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

uniapp热更新,告别云打包

2021-12-08 17:59:01  阅读:245  来源: 互联网

标签:uniapp res APP 更新 plus master 告别 uni 打包


前言

项目一直使用uniapp来打包APP,但是每次发布测试或者上线,都要使用官方的云打包…有大小限制不说,周五等时间等待的时间比打包的时间更加长,所以就想着能不能热更新呢?说干就干

调研阶段

首先在官网的文档上找了一下,发现原来官方就有热更新的平台,这不巧了嘛官方文档,这里根据官方文档把插件安装好,文档写的还是很详细的,插件分两个,包的管理平台没什么可说,基本按照官方文档走就可以了,这里主要说一下APP的插件上的使用和一些完善的部分

静默更新

根据官方的文档走完,基本就能更新包了,因为更新的过程我们不希望用户感知到,所以我们选择使用静默更新,但是使用的过程中问题就来了…静默更新之后,会偶尔出现界面样式完全错乱的情况,然后手动重启应用之后又可以了…

image.png

这个问题折腾了一段时间,似乎官方也没有解决的办法,那就只能自己动手了

解决静默更新bug

现在已知在使用过程中更新包的话,会可能出现界面样式混乱的问题,那我们就更新之后,帮用户直接重启不就可以了,完美~

image.png

然而事情并没有这么简单,这个时候产品经理来告诉我,用户使用的过程中直接重启,用户会以为我们的软件有问题…我说…那要不我加个弹窗告诉他,然后产品经理认为这样还是不好.可能用户在填写一些表单之类的,弹窗之后直接退出也不行…经过漫长的讨论

image.png

最后的结论就是…重新写一下整个静默更新的流程,大概就是用户将APP前台运行–检测是否有更新版本–有就下载好,保存到本地,再用户下一次APP前台运行的时候进行安装,并且提示为使用最新功能,需要重启,然后帮用户重启

image.png

代码实现

查看插件源码得知,热更新的逻辑相对简单,主要是使用H5+的plus.runtime.install的方法进行更新的,也就是说,其实怎么下载,怎么处理这个热更新的包我们完全可以自定义.只要在最后使用上面提到的install的方法进行安装就行.

那我们先从下载包的地方入手

找到APP热更新插件源码的位置,在根目录下的uni_modules/uni-upgrade-center-app/utils/check-update.js,在下载成功并且静默更新的地方,原本是下载直接安装,把安装的代码去掉,先保存起来

if (is_silently) {
	uni.downloadFile({
		url: e.result.url,
		success: res => {
			if (res.statusCode == 200) {
				// 先将文件保存起来,在进来主页的时候再进行安装判断
				uni.saveFile({
					tempFilePath:res.tempFilePath,
					success:function(res){
						if(globalConfig.gitName != 'master'){
                                                // 这里可以加,这里是根据git分支进行判断的,后面会说到
							uni.showModal({
								title:"WGT保存成功",
							})
						}
						uni.setStorageSync('wgtFile',res.savedFilePath)
					},
					fail(e){
						if(globalConfig.gitName != 'master'){
							uni.showModal({
								title:"保存失败",
								content:JSON.stringify(e)
							})
						}
					},
				})
				// plus.runtime.install(res.tempFilePath, {
				// 	force: false
				// });
			}
		},
		fail(e){
			if(globalConfig.gitName != 'master'){
				uni.showModal({
					title:"下载失败",
					content:JSON.stringify(e)
				})
			}
		
		},
	});
	return;
}



热更新包安装的处理

下载处理好之后,我们处理安装的逻辑.在App.vue的主入口处,onShow的生命周期里面,这个生命周期就是用户软件前台运行的时候,会进入的生命周期,判断是否有未安装的热更新包,有的话进入安装,安装完成之后,就弹窗提示用户需要重启,用户点击确定之后,就杀死整个APP,这里其实一开始是想要使用restart热重启,但是样式错乱的问题依然存在,所以就选择了杀死整个APP的方式,也就是下面的nativeQuit方法,后面会说到

if(uni.getStorageSync('wgtFile')){
	installFinish = false
	console.log("有wgtFile")
        // 这里就是热更新的主要功能,借用H5+的install安装热更新的包
	plus.runtime.install(uni.getStorageSync('wgtFile'), {
		force: true
	},function(){
		uni.removeStorageSync('wgtFile')
		uni.showModal({
		    title: '提示',
		    content: 'APP需要重启以使用最新功能',
			showCancel:false,
		    success: function (res) {
					console.log("准备重启")
		        if (res.confirm) {
					_this.nativeQuit();
					// plus.runtime.restart();  
		        } 
		    }
		});
	},function(error){
		uni.showModal({
		    title: '提示',
		    content: '安装失败了' + error,
			showCancel:false,
		});
	});
}
if(installFinish && !uni.getStorageSync('wgtFile') && !uni.getStorageSync('downing')){
	// 调用APP更新方法,如果安装包正在安装,或者正在下载.则不要去获取
	wgtUpdate().then((e)=>{
	}).catch((e)=>{
	})
}

自定义退出APP的方法nativeQuit

上面说到,H5+的热重启依然解决不了样式错乱的问题,只能强行杀死APP让用户手动启用APP了.这里由于uniapp是原生APP的webview,所以需要根据IOS跟安卓来实现不同的退出APP的方式

安卓退出APP并且杀死后台的方法

//  热更新之后需要杀死进程重新打开,需要引入安卓system的类来实现
let system = plus.android.importClass('java.lang.System')
_this.nativeQuit = function(){
	system.exit(0);
};

IOS退出APP并且杀死后台的方法

_this.nativeQuit = function(){
	plus.ios.import('UIApplication').sharedApplication().performSelector('exit');
}

nativeQuit完整代码

let _this = this;
uni.getSystemInfo({
	success: function(e) {
		console.log(e.platform)
		Vue.prototype.StatusBar = e.statusBarHeight;
		Vue.prototype.$phoneInfo = e
		// let system = plus.android.import('java.lang.System')
		
		if (e.platform == 'android') {
			let main = plus.android.runtimeMainActivity();
			//  热更新之后需要杀死进程重新打开,需要引入安卓system的类来实现
			let system = plus.android.importClass('java.lang.System')
			_this.nativeQuit = function(){
				system.exit(0);
			};
		}else{
			_this.nativeQuit = function(){
				plus.ios.import('UIApplication').sharedApplication().performSelector('exit');
			}
		}
	}
})

至此热更新部分已经基本完成了,但是由于插件直接使用的是uni的云空间,而且测试跟正式环境的热更新包地址是不一样的,那就带来了一个问题,每次分支更新手动切换云空间?那一旦忘记切换,把链接测试云空间的包发到正式…那岂不是第二天因为左脚进入公司被开除

image.png

根据分支名称进行云空间的自动切换

这里要先写一下这个云空间的一个注意的点那个uniCloud的文件夹不会自动生成的!!!,而且没有这个文件夹,如果跟我一样使用云空间的小伙伴就会发现无法再进行热更新了…所以如果有新的小伙伴拉取项目,记住一定要让他手动去生成,不要问我为什么知道…

image.png

获取当前git分支的名称

在vue.config.js当中,借用child_process这个库,就可以运行脚本,通过脚本获取分支名称,并且保存起来让全局可以让访问到

const childProcess = require('child_process')
//  获取当前git分支名称
const branchName = childProcess.execSync("git rev-parse --abbrev-ref HEAD", {
	cwd: __dirname.replace(/\\/g, '/')
}).toString().trim()

module.exports = {
  chainWebpack: config => {
    config
      .plugin('define')
      .tap(args => {
      // 把分支名称保存起来
        args[0]['process.env'].GIT_BRANCH_NAME = JSON.stringify(branchName)
        return args
      })
  }
}

新建一个文件保存云空间的配置项

在uni云空间后台找到空间的配置

image.png

新建一个文件来保存配置项,初始化云空间需要用

const config = {
	gitName: process.env.GIT_BRANCH_NAME, // 当前git的分支名称
	uniClound: { // 云空间的配置信息,用于做热更新使用
		master: {
			provider: 'aliyun', // 这里阿里云就是aliyun,腾讯是什么忘记了...
			spaceId: '云空间Id',
			clientSecret: '云空间秘钥'
		},
		test: {
			provider: '云空间服务商',
			spaceId: '云空间Id',
			clientSecret: '云空间秘钥'
		}
	}
}

export default config

动态初始化云空间

官方插件初始化云空间的文件在uni_modules/uni-upgrade-center-app/utils/call-check-version.js,修改默认导出的函数

import config from "../../../globalConfig.js" // 引入上面的配置文件
export default function() {
	// #ifdef APP-PLUS
	return new Promise((resolve, reject) => {
		plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
                // 这个方法可以获取到当前APP的版本号等信息,要用来判断版本号高低的
			let myCloud = ''
			//  利用git的分支名称来初始化不同的云空间
			if(config.gitName == 'master'){
                        // 连接生产环境的云空间
				myCloud = uniCloud.init(config.uniClound.master);
			}else{
                        // 连接测试环境的云空间
				myCloud = uniCloud.init(config.uniClound.test);
			}
			myCloud.callFunction({
				name: 'check-version',
				data: {
					appid: plus.runtime.appid,
					// appVersion: plus.runtime.version,
					appVersion: widgetInfo.version, // 应用名称为大的版本号,用于比较APP的整包更新
					// wgtVersion: widgetInfo.version
					wgtVersion: widgetInfo.versionCode, // 改成利用应用版本号来进行判断wgt的热更新
				},
				success: (e) => {
					resolve(e)
				},
				fail: (error) => {
					reject(error)
				}
			})
		})
	})
	// #endif
	// #ifndef APP-PLUS
	return new Promise((resolve, reject) => {
		reject({
			message: '请在App中使用'
		})
	})
	// #endif
}

在测试环境下,热更新弹窗

这里方便自己排除错误,个人感觉挺重要的,因为静默更新几乎看不到什么提示,所以最好在几个下载,更新的节点捕捉一下错误,并且弹窗,但是仅限在测试环境下,所以我们也可以根据分支名称来进行判断,在uni_modules/uni-upgrade-center-app/utils/check-update.js下增加测试环境的弹窗提示


uni.downloadFile({
	url: e.result.url,
	success: res => {
		if (res.statusCode == 200) {
			// 先将文件保存起来,在进来主页的时候再进行安装判断
			uni.saveFile({
				tempFilePath:res.tempFilePath,
				success:function(res){
					if(globalConfig.gitName != 'master'){
                                        // 在分支不是master的时候,进行弹窗提示
						uni.showModal({
							title:"WGT保存成功",
						})
					}
					uni.setStorageSync('wgtFile',res.savedFilePath)
				},
				fail(e){
					if(globalConfig.gitName != 'master'){
                                         // 在分支不是master的时候,进行弹窗提示
						uni.showModal({
							title:"保存失败",
							content:JSON.stringify(e)
						})
					}
				},
			})
			// plus.runtime.install(res.tempFilePath, {
			// 	force: false
			// });
		}
	},
	fail(e){
		if(globalConfig.gitName != 'master'){
                 // 在分支不是master的时候,进行弹窗提示
			uni.showModal({
				title:"下载失败",
				content:JSON.stringify(e)
			})
		}
	
	},
});

最后说几个注意点

  1. 静默更新只能更新业务代码,如果你这次更新添加了底层的调用能力,比如蓝牙的调用,推送这些,那就要使用整包更新
  2. 如果出现了访问不到云空间的问题,大概率就是上一次打包的人没有uniCould的文件夹,或者是账号不正确,因为云空间是跟着账号走的.
  3. IDE切换账号会导致uniCloud连接断掉,记得手动连一下再打包,否则会没有热更新功能

至此就全部结束了,完结撒花~

标签:uniapp,res,APP,更新,plus,master,告别,uni,打包
来源: https://blog.csdn.net/qq_42253142/article/details/121797225

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有