在做APP时需要用到自动更新升级机制,当版本更新了则提示用户升级下载更新。

下面是我实现的逻辑

版本更新后端数据库存入版本号,APP访问时获取当前版本和后端接口返回版本号是否一致。如一致则是最新版本,如不一致则提示用户更新下载新的版本。

1.编写后台接口检测版本(为了方便测试和理解 我这里使用的是原生php的代码)

创建index.php文件,编写如下代码

<?php

header("Access-Control-Allow-Origin: *");// 允许所有地址跨域请求

class Index{
    protected $version = '1.0.0'; // 版本号
    protected $appid = ''; // 当前应用APPID 例如:__UNI__BBBBB14 示例

    /**
     * 返回json Api格式
     * @param $code
     * @param string $msg
     * @param array $data
     * @param int $httpCode
     * @return \think\response\Json
     */
    public function show($code, $msg = "", $data = []){
        $result = [
            'code' => $code,
            'msg' => $msg,
            'data' => $data
        ];
        echo json_encode($result,true);
        exit;
    }

    /**
     *
     *接收头信息
     **/
    public function em_getallheaders()
    {
        $headers = [];
        foreach ($_SERVER as $name => $value)
        {
            if (substr($name, 0, 5) == 'HTTP_')
            {
                $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
            }
        }
        return $headers;
    }

    public function getVersion(){
        $header = $this->em_getallheaders();

        if(!isset($_POST['version']) || !isset($header['Appid'])){
            $this->show(0,"参数错误",[]);
        }
        
        if($header['Appid'] == $this->appid){
            if($_POST['version'] != $this->version){
                $this->show(1,"ok",['url'=>'这里填写已经打包好的apk下载的地址']);
            }else{
                $this->show(2,"已是最新版本",[]);
            }
        }else{
            $this->show(0,"当前应用appid不存在",[]);
        }
    }
}

(new Index())->getVersion();

2.后端接口咱们已经写好了,接下来看uniapp如何检测

在项目中App.vue onLaunch 方法中检测版本更新,我的代码如下

App.vue

<script>
	import Vue from 'vue'
	import config from '@/lib/config.js'
	
	export default {
		onLaunch: function(){ 
			let that = this
			// 检测版本更新
			that.checkVersion()
		},
		onShow: function() {
			console.log('App Show')
		},
		onHide: function() {
			console.log('App Hide')
		}, 
		methods:{
			checkVersion(){
				let that = this 
				// #ifdef APP-PLUS
				
				plus.screen.lockOrientation('portrait-primary') // 竖屏锁定

				uni.request({
					url:config.verifyVersion, // 接口请求地址,也就是上面我们编写的index.php
					method:'POST',
					data:{
						"version": plus.runtime.version // uniapp H5+ 提供的获取版本号的方法
					},
					header:{
						'appid': plus.runtime.appid, // uniapp H5+ 提供的获取APPID的方法
						'X-Requested-With': 'XMLHttpRequest',
						'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
					},
					dataType:"JSON",
					success:function(res){ 
						// 如果code === 1 则需要更新
						if (res.data.code == 1) {
							uni.showModal({
								title: "有新的版本",
								content: "请确认是否更新?",
								success: (info) => {
									if(info.confirm) { 
                                        // 因为App.vue中不能直接使用组件,这里用到了vuex来调用下载进度的组件
                                        // 显示下载进度弹窗
										that.$store.commit('setHide',true)
										if (plus.os.name.toLowerCase() == 'ios') {
											// ios直接跳转到下载页面
											plus.runtime.openURL(res.data.data.url)
										}else{
											that.createDownload(res.data.data.url)
										}
									}
								}
							})
						}else if(res.data.code != 2){
							uni.showToast({
								title:res.data.msg,
								icon:"none",
								duration:3000
							})
						}
					}
				})
				// #endif
			},
			createDownload(url){
				let that = this
				try {
					// 更新下载
					let dtask = plus.downloader.createDownload(url,{'method':'GET'})
					dtask.start() // 开启下载的任务
					dtask.addEventListener('statechanged', function(task,status) {
					  // 给下载任务设置一个监听 并根据状态  做操作
					  switch (task.state) {
						case 1:
							// 正在下载
							break
						case 2:
							// 已连接到服务器
							break
						case 3:
							let current = parseInt(task.downloadedSize/task.totalSize*100)
                            // 更新下载进度
							that.$store.commit('setRogress',current)
							break
						case 4:
                            // 下载完成隐藏进度弹窗
							that.$store.commit('setHide',false)
							console.log("Download success: " + task.filename)
							let ins=plus.runtime.install(
								plus.io.convertLocalFileSystemURL(task.filename), 
								{force: true},
								()=>{
									uni.showToast({icon:'none',title:'安装成功!'});
								},(e)=>{
									uni.showToast({icon:'none',title:'安装失败!'});
								}
							)
						    break
					  }
					});
				} catch (err) {
					uni.showToast({icon:'none',title:'安装失败!'});
				}
			}
		}
	}
</script>

<style>
    /*样式中使用了colorui开源样式 */
	@import url('./style/colorui/main.css');
	@import url('./style/colorui/icon.css');
	@import url('./style/icon.css');
	/*每个页面公共css */
</style>

页面中使用到了进度弹窗和vuex,下面介绍如何使用

首先没有安装vuex的得先进行vuex的安装,不要问我vuex是什么。具体去vue官方网站查询

安装命令 (npm是node.js开发的一个包管理命令,npm是世界上最大的开源库生态系统)所以这里得先安装好了node.js再执行下面命令,不了解node.js可以去下面地址查看 https://blog.csdn.net/LGDmar/article/details/107604214

npm install vuex

安装完成后再项目的根目录下创建store文件夹,然后在文件夹中创建index.js

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import common from './modules/common.js'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
        //
		
    },
    mutations: {
		// 
    },
    actions: {

    },
    modules: {
        common:common
    }
});

export default store

我这里使用的是多模块方法 common是我的公共访问模块,common.js代码如下


const common = {
    state: {
        hide:false, // 弹窗隐藏显示
        rogress: '0', // 进度
    },
    mutations: {
        // 设置显示隐藏进度弹窗
		setHide(state,val){
			state.hide = val
		},
        // 设置进度数据
		setRogress(state,val){
			state.rogress = val
		},
	}
}

export default common

然后在项目的main.js中加载vuex模块

import Vue from 'vue'
import App from './App'
import store from './store' // 引入模块

Vue.config.productionTip = false

Vue.prototype.$store = store // 注册全局属性

App.mpType = 'app'


const app = new Vue({
	store,
    ...App
})
app.$mount()

这样App.vue 中编写的 this.$store.commit 才能成功调用

调用完成,接下来要生成组件,下面是我的弹窗组件代码。我是在项目下创建了一个components目录来放置我的组件。

在components 下创建了app-update/app-update.vue 结构文件 组件样式使用的是colorui

app-update.vue

<template>
	<view>
		<view class="cu-modal" :class="hide==true?'show':''">
			<view class="cu-dialog">
				<view class="cu-bar bg-white justify-end">
					<view class="content">互联网医院正在更新</view>
				</view>
				<view class="padding-sm bg-white">
					<view class="flex margin-top" style="flex-direction: column;">
						<view class="cu-progress round">
							<view class="bg-blue" :style="[{ width: rogress + '%'}]"></view>
						</view>
						<text class="margin-left">{{ rogress }}%</text>
						<view class="dltext">
							新版本正在下载,请耐心等待!
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import { mapState } from 'vuex'
	export default {
		computed:{
            // 监听state中属性值的改变
			...mapState({
				hide: state => state.common.hide,
				rogress: state => state.common.rogress,
			})
		}
	}
</script>

<style lang="less">
	.dltext{
		width: 100%;
		margin-top: 20px;
		text-align: center;
		color: #8a8a8a;
	}
</style>

最后一步在项目加载初始化首页中引入组件,并注册引用

<template>
    <view>
        <app-update></app-update>
    </view>
</template>

<script>
	import AppUpdate from '@/components/app-update/app-update.vue'
	
	export default {
		comments:{
			AppUpdate
		}
	}
</script>

上面就已经实现用户打开App自动检测更新机制完整流程和代码。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐