preface

The project has been using UniApp to package the APP, but every time it releases a test or goes live, it uses the official cloud package… Despite the size limit, the waiting time on Friday was longer than the packing time, so I thought, can I hot update? To start

Research stage

In a document on the club’s official website to find the first, turns out that the official had hot update platform, which unfortunately the official documentation, here the plug-in installed according to the official document, the document writing or very detailed, plug-in points and two packages of management platform have nothing to say, basically according to the official document is ok, here basically says the plugin on the use of the APP and some perfect Part of the

The silent update

According to the official document, we can basically update the package, because we do not want users to be aware of the update process, so we choose to use the silent update, but in the process of using the problem… Once in a while, after a silent update, the interface style is completely out of order, and then you can restart the application manually…

The problem has been around for a while, and there seems to be no official solution, so we have to take matters into our own hands

Fixed silent update bug

Now it is known that the interface style may be confused if the package is updated in the process of use, so we will help the user restart directly after the update, perfect ~

However, things were not so simple. At this time, the product manager told me that the user would directly restart the software when using it, and the user would think there was something wrong with our software. I said… Well, how about I put a popover and tell him, and the product manager thinks it’s still a bad idea. Maybe the user is filling in some forms and so on, popover directly after the exit does not work… After a long discussion

The final conclusion is that… Rewrite the whole process of silent update, which is basically that the user runs the APP foreground — checks whether there is an updated version — downloads it, saves it locally, installs it the next time the user runs the APP foreground, and prompts that it needs to restart to use the latest function, and then helps the user restart

Code implementation

Check the plug-in source code that the hot update logic is relatively simple, mainly using H5+ plus.runtime.install method to update, that is to say, in fact, how to download, how to deal with the hot update package we can completely customize. Just install at the end using the install method mentioned above.

Well, let’s start where we downloaded the package

Js/uni_modules/ uni-upups-center-app /utils/check-update.js /utils/check-update.js/uni_modules/ uni-upups-center-app /utils/check-update.js /utils/check-update.js/uni_modules/ uni-upups-center-app /utils/check-update.js

if (is_silently) {
	uni.downloadFile({
		url: e.result.url,
		success: res= > {
			if (res.statusCode == 200) {
				// Save the file first, and then make the installation judgment when entering the home page
				uni.saveFile({
					tempFilePath:res.tempFilePath,
					success:function(res){
						if(globalConfig.gitName ! ='master') {Git branch git branch git branch git branch git branch git branch git branch git branch
							uni.showModal({
								title:"WGT saved successfully",
							})
						}
						uni.setStorageSync('wgtFile',res.savedFilePath)
					},
					fail(e){
						if(globalConfig.gitName ! ='master'){
							uni.showModal({
								title:"Save failed".content:JSON.stringify(e)
							})
						}
					},
				})
				// plus.runtime.install(res.tempFilePath, {
				// force: false
				// });}},fail(e){
			if(globalConfig.gitName ! ='master'){
				uni.showModal({
					title:"Download failed".content:JSON.stringify(e)
				})
			}
		
		},
	});
	return;
}



Copy the code

Hot update package installation processing

With the downloads handled, we handle the installation logic. In the App. The Lord at the entrance to the vue, onShow life cycle, the life cycle is the time when the user software running at the front desk, will enter the life cycle, determine whether hot update package is not installed, so into the installation, the installation is completed, will pop-up prompts the user to restart, after user click ok, kill the App, here actually The initial attempt was to use the Restart hot restart, but the styling problem was still there, so I chose to kill the entire APP, which is the nativeQuit method below, as discussed later

if(uni.getStorageSync('wgtFile')){
	installFinish = false
	console.log("There are wgtFile")
        // This is the main function of hot update, borrow H5+ install hot update package
	plus.runtime.install(uni.getStorageSync('wgtFile'), {
		force: true
	},function(){
		uni.removeStorageSync('wgtFile')
		uni.showModal({
		    title: 'tip'.content: 'APP needs to be restarted to use the latest features'.showCancel:false.success: function (res) {
					console.log("Ready to restart.")
		        if (res.confirm) {
					_this.nativeQuit();
					// plus.runtime.restart();  }}}); },function(error){
		uni.showModal({
		    title: 'tip'.content: 'Installation failed' + error,
			showCancel:false}); }); }if(installFinish && ! uni.getStorageSync('wgtFile') && !uni.getStorageSync('downing')) {// Call the APP update method if the installation package is being installed or downloaded. Don't get it
	wgtUpdate().then((e) = >{
	}).catch((e) = >{})}Copy the code

Custom exit APP method nativeQuit

The H5+ hot reboot still doesn’t solve the problem of style disorder, so we have to kill the APP and let the user manually enable the APP. Since UNIApp is the webview of the native APP, it is necessary to realize different ways of exiting the APP according to IOS and Android

Android exit APP and kill background method

// After hot update, you need to kill the process and restart it. You need to introduce android system classes to achieve this
let system = plus.android.importClass('java.lang.System')
_this.nativeQuit = function(){
	system.exit(0);
};
Copy the code

IOS exit APP and kill background method

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

NativeQuit complete code

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();
			// After hot update, you need to kill the process and restart it. You need to introduce android system classes to achieve this
			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'); }}}})Copy the code

At this point, the hot update part is almost complete, but since the plug-in uses uni’s cloud space directly, and the test is not the same as the hot update package address of the formal environment, there is a problem. Manually switch the cloud space for each branch update? That once forget to switch, link the test cloud space package to the official… I was fired the next day for entering the company with my left foot

Automatic switching of cloud space based on branch name

One caveat to this cloud space is that the uniCloud folder does not automatically generate!!!! And without this folder, if you use cloud space like me, you will find that you can no longer make hot updates… So if you have a new buddy pull item, remember to have him manually generate, don’t ask me why I know….

Gets the name of the current Git branch

In vue.config.js, using the child_process library, you can run scripts that get branch names and save them for global access

const childProcess = require('child_process')
// Get the current git branch name
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= > {
      // Save the branch name
        args[0] ['process.env'].GIT_BRANCH_NAME = JSON.stringify(branchName)
        return args
      })
  }
}

Copy the code

Create a new file to save the configuration items in the cloud space

Find the configuration of the space in the UNI cloud Space background

Create a new file to save the configuration items, which is required to initialize the cloud space

const config = {
	gitName: process.env.GIT_BRANCH_NAME, // The current git branch name
	uniClound: { // Cloud space configuration information for hot update
		master: {
			provider: 'aliyun'.// What is aliyun?
			spaceId: 'Cloud Space Id'.clientSecret: 'Cloud Space Secret Key'
		},
		test: {
			provider: 'Cloud Space Service Provider'.spaceId: 'Cloud Space Id'.clientSecret: 'Cloud Space Secret Key'}}}export default config
Copy the code

Dynamically initialize the cloud space

The official plugin initializes the cloud space file in uni_modules/ uni-upupgrade -center-app/utils/call-check-version.js, and modifies the default exported function

import config from ".. /.. /.. /globalConfig.js" // Import the configuration file above
export default function() {
	// #ifdef APP-PLUS
	return new Promise((resolve, reject) = > {
		plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
                // This method can obtain the current APP version number and other information, used to determine the level of the version
			let myCloud = ' '
			// Use git branch names to initialize different cloud Spaces
			if(config.gitName == 'master') {// Connect to the cloud space of the production environment
				myCloud = uniCloud.init(config.uniClound.master);
			}else{
                        // Connect to the cloud space of the test environment
				myCloud = uniCloud.init(config.uniClound.test);
			}
			myCloud.callFunction({
				name: 'check-version'.data: {
					appid: plus.runtime.appid,
					// appVersion: plus.runtime.version,
					appVersion: widgetInfo.version, // The APP name is a large version number, which is used to compare the entire package of APP updates
					// wgtVersion: widgetInfo.version
					wgtVersion: widgetInfo.versionCode, // Use the application version number to determine the hot update of WGT
				},
				success: (e) = > {
					resolve(e)
				},
				fail: (error) = > {
					reject(error)
				}
			})
		})
	})
	// #endif
	// #ifndef APP-PLUS
	return new Promise((resolve, reject) = > {
		reject({
			message: 'Please use it in App'})})// #endif
}

Copy the code

In the test environment, hot update popup

Error: uni_modules/ uni-upupgrade -ce? (uni_modules/uni-upgrade-ce? Added test environment popup prompt in nter-app/utils/check-update.js


uni.downloadFile({
	url: e.result.url,
	success: res= > {
		if (res.statusCode == 200) {
			// Save the file first, and then make the installation judgment when entering the home page
			uni.saveFile({
				tempFilePath:res.tempFilePath,
				success:function(res){
					if(globalConfig.gitName ! ='master') {// Do a popup prompt when the branch is not master
						uni.showModal({
							title:"WGT saved successfully",
						})
					}
					uni.setStorageSync('wgtFile',res.savedFilePath)
				},
				fail(e){
					if(globalConfig.gitName ! ='master') {// Do a popup prompt when the branch is not master
						uni.showModal({
							title:"Save failed".content:JSON.stringify(e)
						})
					}
				},
			})
			// plus.runtime.install(res.tempFilePath, {
			// force: false
			// });}},fail(e){
		if(globalConfig.gitName ! ='master') {// Do a popup prompt when the branch is not master
			uni.showModal({
				title:"Download failed".content:JSON.stringify(e)
			})
		}
	
	},
});
Copy the code

A few final caveats

  1. Silent updates can only update business code. If you add low-level calling capabilities, such as Bluetooth calls and push, then use the whole package
  2. If there are problems accessing the cloud space, chances are that the person who packed last time didn’t have a uniCould folder, or the account number is incorrect, because the cloud space follows the account number.
  3. Switching IDE accounts will cause the uniCloud connection to disconnect, remember to manually connect before packing, otherwise there will be no hot update function

So far all over, end scatter flower ~