基于Spring的Uniapp自动更新实现方法

Uniapp自动更新

   本文介绍了基于rouyi-uniapp的更新包版本自动推送更新。结合minio和网址下载地址两种方式,计算版本号大小后,可选是否强制更新。

一、表结构和后端版本号检测设计

1、版本更新控制表结构

主要字段和设计思路:

fileUrl:直接下载地址,用于网址直接下载,uniapp可直接访问(isUrlDownload=”Y“)

filePath:minio下载地址, 存储minio文件管理系统表的关键字,uniapp走本地minio文件下载地址(isUrlDownload=”N“)

version:版本号3位,eg:4.0.1,与uniapp的manifest.Json的versionName对应。

versionValue:版本号值,类似于二进制值转化,在更新版本时,比价用户当前版本信息和发布的有效最高版本号,如果当前版本号低于发布的最高版本号,进行更新提示。

Eg:Version=4.0.1; versionValue = 1*Math.power(10,0)+0*Math.power(10,1)+1*Math.power(10,2)。平方基数值不得小于10,否则值计算的最终大小会不符合。

isUrlDownload:是否使用直接地址下载还是minio,更加灵活

Status:版本是否可用。‘Y’为可用,即使用户安装的是旧版本,也可以不更新。‘N’为版本停用,如果用户当前安装的版本状态为停用,则强制更新到最新版(状态为‘Y’,且版本号值最高)

package com.inspur.factory.factoryAppManage.domain;

import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.inspur.common.annotation.Excel;
import com.inspur.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * app版本管理对象 factory_app_manage
 *
 */
@TableName("factory_app_manage")

@Data
public class FactoryAppManage extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 主键 */
    @TableId
    private Long id;

    /** 版本号名称 */
    @Excel(name = "版本号名称")
    private String version;

    /** 版本号值 */
    @Excel(name = "版本号值")
    private Long versionValue;

    /** 手机品牌 */
    @Excel(name = "手机品牌")
    private String phoneBrand;

    /** 文件名(安装包名称) */
    @Excel(name = "文件名(安装包名称)")
    private String fileName;

    /** 安装包地址 */
    @Excel(name = "安装包地址")
    private String filePath;

    /** 下载地址 */
    @Excel(name = "下载地址")
    private String fileUrl;

    /** 上传时间 */
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Excel(name = "上传时间", width = 30, dateFormat = "yyyy-MM-dd")
    private Date fileTime;

    /** 状态 */
    @Excel(name = "状态")
    private String status;

    /** 更新说明 */
    @Excel(name = "更新说明")
    private String upgradeDescription;

    /** 文件大小 */
    @Excel(name = "文件大小")
    private String fileSize;

    /** 使用临时地址 */
    @Excel(name = "使用临时地址",readConverterExp = "Y=是,N=否")
    private String isUrlDownload;

    }


    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("id", getId())
            .append("version", getVersion())
            .append("versionValue", getVersionValue())
            .append("phoneBrand", getPhoneBrand())
            .append("fileName", getFileName())
            .append("filePath", getFilePath())
            .append("fileUrl", getFileUrl())
            .append("fileTime", getFileTime())
            .append("status", getStatus())
            .append("upgradeDescription", getUpgradeDescription())
            .append("fileSize", getFileSize())
            .append("createTime", getCreateTime())
            .append("createBy", getCreateBy())
            .append("updateTime", getUpdateTime())
            .append("updateBy", getUpdateBy())
            .append("remark", getRemark())
            .toString();
    }
}

2、检查版本更新

    检查用户当前的版本是否可用。‘Y’为可用,即使用户安装的是旧版本,也可以不更新。‘N’为版本停用,如果用户当前安装的版本状态为停用,则强制更新到最新版(状态为‘Y’,且版本号值最高)。

//获取应当安装的app版本

@Override
public FactoryAppManage getAppVersion(FactoryAppManage factoryAppManage){
    //传入版本号、手机系统类型
    List oldVersion = factoryAppManageMapper.selectFactoryAppManageList(factoryAppManage);
    if(oldVersion!=null && oldVersion.size()!=0){
        //如果当前版本还可使用,返回当前版本
        if(oldVersion.get(0).getStatus().equals("Y")){
            return oldVersion.get(0);
        }else{
            //如果当前版本不可使用强制更新,返回最新版本
            FactoryAppManage factoryAppManageQuery = new FactoryAppManage();
            factoryAppManageQuery.setStatus("Y");
            factoryAppManageQuery.setPhoneBrand(factoryAppManage.getPhoneBrand());
            List newVersion = factoryAppManageMapper.selectFactoryAppManageList(factoryAppManageQuery);
            if(newVersion!=null){
                return newVersion.get(0);
            }
        }
    }
    return null;
}

二、前端uniapp设计

版本号比较后,更新包安装提示弹窗,点击确认下载文件。

文件下载和打开主要方法如下:

1、主要应用技术

(1)直接地址下载:

uni.saveFile({})

(2)Minio下载:

Url为本地接口地址

plus.downloader.createDownload(url, {})

plus.io.convertLocalFileSystemURL

plus.runtime.openFile(d.filename); //选择软件打开文件

(3)H5平台下载:

主要用于电脑调试,BLOB转化,具体不做解释

(4)软件信息获取

uni.getSystemInfoSync()

获取:phoneBrand(版本)version(版本号)

2、实现方法(***重点***)

App.vue根组件,每次打开任何页面都会执行到,在此文件下检测版本和更新包安装。

(1)版本检测

当前版本号为参数,后台请求对比最新版本号(版本号值最大为最新版本),返回应当安装的版本。

如果需要更新,则弹窗显示,点击确定进行安装。

根据web前台配置的是否用直接地址下载,进入安装包下载安装。

      checkUploadVersion(){
        //检测更新
        let server = config.baseUrl +'/factory/factoryAppManage/getAppVersion'; //检查更新地址(minio检测地址)
        let info = uni.getSystemInfoSync()
        uni.request({
          url: server,
          data: {
            phoneBrand: info.platform,
            version: info.appVersion
          },
          success: (res) => {
            if (res.data.data.version != info.appVersion) {
            // if (1) {
              let upgradeDescription = res.data.data.upgradeDescription
              uni.showModal({ //提醒用户更新
                title: "更新提示",
                content: '版本更新内容:'+ upgradeDescription,
                showCancel:false,
                success: (e) => {
                  if (e.confirm) {
                    if(info.uniPlatform=='web'){
                      //h5平台调用后端minio接口下载
                      this.downloadApp2(res.data.data)
                    }else if(info.platform!='windows' && info.uniPlatform!='web' && res.data.data.isUrlDownload == 'Y'){
                      //app手机端使用临时地址下载
                      this.downloadApp1(res.data.data)
                    }else if(info.platform!='windows' && info.uniPlatform!='web' && res.data.data.isUrlDownload == 'N'){
                      //app手机端调用后端minio接口下载
                      this.downloadApp3(res.data.data)
                    }
                  }
                }
              })
            }
          }
        })
      },

(2) minio下载

此方式具有参考意义,可以不用购买云空间存放安装包文件,直接使用minio文件存储。


   

   /** app安装包下载-(下载方式3-APP调用后端minio下载接口下载)*/
      downloadApp3(appVersionInfo) {

        var url = config.baseUrl +'/fileManage/downloadFile'+'?filePath=' + appVersionInfo.filePath+'&fileName=' + appVersionInfo.fileName; //请求下载接口地址
        var name = appVersionInfo.fileName;
        // console.log('method', reqMethod)
        uni.showLoading({
          title: '正在下载'
        });
// 本地路径开头使用file://,跟上手机文件本地目录storage/emulated/0,
// 这时用户文件管理器能看到的了,之后创建 京唐港app 作为文件夹,
        let dtask = plus.downloader.createDownload(url, {
          filename: "file://storage/emulated/0/京唐港app/" + name //利用保存路径,实现下载文件的重命名
        },(d, status)=> {
          //d为下载的文件对象
          if (status == 200) {
            uni.hideLoading();
            uni.showToast({
              icon: 'none',
              mask: true,
              title: '已保存到文件夹:/京唐港app/' + name, //保存路径
              duration: 3000,
            });
            //下载成功,d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径
            let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);
            setTimeout(()=>{
              plus.runtime.openFile(d.filename); //选择软件打开文件
            },1500)
          } else {
            //下载失败
            uni.hideLoading();
            plus.downloader.clear(); //清除下载任务
            uni.showToast({
              icon:'none',
              mask:true,
              title: '下载失败,请稍后重试',
            });
          }
        })
        dtask.start();
      },

(3)直接地址下载

此方式需要云空间

  

    /** app安装包下载-(下载方式1-APP指定url下载)*/
      downloadApp1(appVersionInfo){
        //下载方式1:指定url下载
        let downloadUrl = appVersionInfo.fileUrl
        // let downloadUrl = 'https://mp-fdbd529e-1d38-4f4a-bf37-72ba880de14a.cdn.bspapp.com/cloudstorage/00b0e017-b375-4758-88c8-4acfab810d7a.apk'
         uni.downloadFile({
          url: downloadUrl,
/*          data:{
            filePath:'mnQ0lCrayctz3TkHxB4rB0PeVTD7fbXNhULFZo4g+iPK0KXkzzzYJWCIJ5vxfiu1a8fzsYOb07weXbcXd92dkw==',
            fileName: '3.jpg'
          },
          method: 'POST',*/
          success: (res) => {
            console.log('downloadFile success, res is', res)
            //文件保存到本地
            uni.saveFile({
              tempFilePath: res.tempFilePath, //临时路径
              success: function(re) {
                uni.showToast({
                  icon: 'none',
                  mask: true,
                  title: '文件已保存:' + re.savedFilePath, //保存路径
                  duration: 3000,
                });
                setTimeout(() => {
                  //打开查看
                  uni.openDocument({
                    filePath: re.savedFilePath,
                    success: function(res) {
                      // console.log('打开成功');
                    }
                  });
                }, 3000)
              }
            });

            uni.hideLoading();
          },
          fail: (err) => {
            console.log('downloadFile fail, err is:', err)
            uni.hideLoading();
          }
        })
      },

(4) H5平台电脑端下载

      /** app安装包下载-(下载方式2-h5平台web使用后端minio后端接口下载)*/
      downloadApp2(appVersionInfo){
        //下载方式2:请求接口下载
        let server = config.baseUrl +'/fileManage/downloadFile'+'?filePath=' + appVersionInfo.filePath+'&fileName=' + appVersionInfo.fileName; //请求下载接口地址
        uni.request({
          url: server,
          method: 'post',
          success: (res) => {
            /** h5 平台下载*/
            try {
              // const res = await exportOrderById({ id });//获取返回的二进制数据
              const blob = new Blob([res.data]); // 通过返回的流数据 手动构建blob 流
              const reader = new FileReader();
              reader.readAsDataURL(blob); // 转换为base64,可以直接放入a标签的href
              reader.onload = (e) => {
                // 转换完成,创建一个a标签用于下载
                const a = document.createElement("a");
                a.download = appVersionInfo.fileName; // 构建 下载的文件名称以及下载的文件格式(可通过传值输入)
                if (typeof e.target.result === "string") {
                  a.href = e.target.result;
                }
                a.click();
              };
            } catch (err) {
              this.$message.error("遇到错误!");
            }
          }
        })
      },

三、前端web设计

1、版本页面展示





2、文件上传组件




你可能感兴趣的:(uni-app)