preface
The project has always used uniapp to package apps, but every time it is released, tested or launched, it must use the official cloud packaging... There are size restrictions. Needless to say, the waiting time on Friday is longer than the packaging time, so I wonder if it can be hot updated? Just do it
Research stage
First, I looked in the documents on the official website and found that the official had a hot update platform. Unfortunately Official documents Here, the plug-ins are installed according to the official documents. The documents are still very detailed. The plug-ins are divided into two parts. There is nothing to say about the package management platform. It's OK to basically follow the official documents. Here we mainly talk about the use of APP plug-ins and some perfect parts
Silent update
According to the official documents, we can basically update the package. Because we don't want users to be aware of the update process, we choose to use silent update, but there are problems in the process... After silent update, the interface style will be completely disordered occasionally, and then restart the application manually
This problem has been tossed for some time. It seems that the official has no solution, so we can only do it ourselves
Fix silent update bug
Now it is known that if the package is updated during use, the interface style may be confused. After the update, we can help the user restart directly. It's perfect~
However, things are not so simple. At this time, the product manager told me that if the user restarts directly during use, the user will think there is a problem with our software... I said... Why don't I add a pop-up window to tell him, and then the product manager thinks it's still bad. Maybe the user can't just exit after filling out some forms... After a long discussion
The final conclusion is... Rewrite the whole silent update process, which is probably that the user runs the APP foreground - detects whether there is an updated version - if so, download it, save it locally, install it the next time the user runs the APP foreground, and prompt that it needs to be restarted to use the latest functions, and then help the user restart
code implementation
Looking at the plug-in source code, we know that the logic of hot update is relatively simple. It is mainly updated by using the H5 + plus.runtime.install method. In other words, we can completely customize how to download and deal with this hot update package. As long as we use the install method mentioned above at the end
Let's start with the place where we downloaded the package
Find the location of the APP hot update plug-in source code, uni in the root directory_ Modules / uni-upgrade-center-APP/utils/check-update.js, where the download is successful and the update is silent, the original is to download and install directly. Remove the installed code and save it first
if (is_silently) { uni.downloadFile({ url: e.result.url, success: res => { if (res.statusCode == 200) { // Save the file first, and then judge the installation when you enter the home page uni.saveFile({ tempFilePath:res.tempFilePath, success:function(res){ if(globalConfig.gitName != 'master'){ // It can be added here. It is judged according to the git branch, which will be mentioned later 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; }
Handling of hot update package installation
After the download is completed, we will deal with the installation logic. At the main entrance of App.vue, in the life cycle of onShow, this life cycle is the life cycle that the user will enter when the software foreground is running to judge whether there are uninstalled hot update packages. If there are, enter the installation. After the installation is completed, a window will pop up to prompt the user to restart. After the user clicks OK, the whole APP will be killed, In fact, at the beginning, I wanted to use restart for hot restart, but the problem of disordered style still exists, so I chose to kill the whole APP, that is, the following nativeQuit method, which will be mentioned later
if(uni.getStorageSync('wgtFile')){ installFinish = false console.log("have wgtFile") // Here is the main function of hot update. Use H5 + install to install the hot update package plus.runtime.install(uni.getStorageSync('wgtFile'), { force: true },function(){ uni.removeStorageSync('wgtFile') uni.showModal({ title: 'Tips', content: 'APP A reboot is required 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: 'Tips', 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, do not get it wgtUpdate().then((e)=>{ }).catch((e)=>{ }) }
Customize the method of exiting APP nativeQuit
As mentioned above, the hot restart of H5 + still can not solve the problem of disordered style. We can only forcibly kill the APP and let the user manually enable the APP. Here, because the uniapp is the webview of the native APP, we need to realize different ways to exit the APP according to IOS and Android
Android exits APP and kills the background
// After the hot update, the process needs to be killed and reopened, which needs to be implemented by introducing the class of Android system let system = plus.android.importClass('java.lang.System') _this.nativeQuit = function(){ system.exit(0); };
IOS exits APP and kills the background
_this.nativeQuit = function(){ plus.ios.import('UIApplication').sharedApplication().performSelector('exit'); }
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 the hot update, the process needs to be killed and reopened, which needs to be implemented by introducing the class of Android 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'); } } } })
So far, the hot update part has been basically completed. However, since the plug-in directly uses the cloud space of uni, and the test is different from the hot update package address of the formal environment, it brings a problem. Manually switch the cloud space every branch update? Once you forget to switch, send the package of link test cloud space to the official... Won't you be fired the next day for entering the company with your left foot
Automatic switching of cloud space according to branch name
Here is a note about the cloud space. The uniCloud folder will not be generated automatically!!!, And without this folder, if you use cloud space like me, you will find that you can't hot update any more... So if a new partner pulls a project, remember to let him generate it manually. Don't ask me why I know
Gets the name of the current git branch
In vue.config.js, borrow child_process library, you can run the script, get the branch name through the script, and save it 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 }) } }
Create a new file to save the configuration items of cloud space
Find the configuration of the space in the background of the uni cloud space
Create a new file to save the configuration items. It needs to be used to initialize the cloud space
const config = { gitName: process.env.GIT_BRANCH_NAME, // Branch name of current git uniClound: { // The configuration information of cloud space is used for hot update master: { provider: 'aliyun', // Alibaba cloud here is aliyun. What is Tencent? I forgot 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
Dynamically initialize cloud space
The official plug-in initializes cloud space files in uni_ Modules / UNI upgrade center app / utils / call check version.js, modify the function exported by default
import config from "../../../globalConfig.js" // Import the above configuration file export default function() { // #ifdef APP-PLUS return new Promise((resolve, reject) => { plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { // This method can obtain the version number and other information of the current APP, which should be used to judge the version number let myCloud = '' // Use the branch name of git to initialize different cloud spaces if(config.gitName == 'master'){ // Cloud space connected to production environment myCloud = uniCloud.init(config.uniClound.master); }else{ // Connect 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 application name is a large version number, which is used to compare the whole package updates of the APP // wgtVersion: widgetInfo.version wgtVersion: widgetInfo.versionCode, // Instead, use the application version number to judge 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 in App Used in' }) }) // #endif }
In the test environment, the hot update pop-up window
It's convenient to eliminate errors. Personally, I think it's very important, because there are almost no prompts for silent updates, so it's best to catch errors and pop up windows at several download and update nodes, but only in the test environment, so we can also judge according to the branch name in uni_ Add pop-up prompt of test environment under modules / UNI upgrade center app / utils / check-update.js
uni.downloadFile({ url: e.result.url, success: res => { if (res.statusCode == 200) { // Save the file first, and then judge the installation when you enter the home page uni.saveFile({ tempFilePath:res.tempFilePath, success:function(res){ if(globalConfig.gitName != 'master'){ // Pop up the prompt when the branch is not the master uni.showModal({ title:"WGT Saved successfully", }) } uni.setStorageSync('wgtFile',res.savedFilePath) }, fail(e){ if(globalConfig.gitName != 'master'){ // Pop up the prompt when the branch is not the master uni.showModal({ title:"Save failed", content:JSON.stringify(e) }) } }, }) // plus.runtime.install(res.tempFilePath, { // force: false // }); } }, fail(e){ if(globalConfig.gitName != 'master'){ // Pop up the prompt when the branch is not the master uni.showModal({ title:"Download failed", content:JSON.stringify(e) }) } }, });
Finally, let's say a few points of attention
- The silent update can only update the business code. If you add the underlying calling capabilities, such as Bluetooth calls and push these, you need to use the whole package update
- If there is a problem that the cloud space cannot be accessed, the most likely reason is that the person who packed the last time did not have a uniCould folder, or the account is incorrect, because the cloud space follows the account
- IDE account switching will cause the uniCloud connection to be disconnected. Remember to manually connect and then package, otherwise there will be no hot update function
It's all over now. It's over~