uniapp项目实践总结(十九)版本更新和热更新实现方法

导语:当一个 APP 应用开发完成以后,就要上架应用商店,但有时候修改一些小问题或者推出一些活动,又不想频繁地提交应用商店审核,那么就可以使用应用内更新功能来进行应用的版本升级更新或热更新,下面就介绍一下实现的方法。

目录

  • 准备工作
  • 原理分析
  • 实战演练
  • 案例展示

准备工作

  • /pages/index文件夹下面新建一个version.vue的组件;
  • 按照前面文章所说的页面结构,编写好预定的页面;

原理分析

下面是应用更新的原理总结。

安装包版本更新

  • 通过uni.getSystemInfoSync方法的appVersion属性获取到应用当前安装包版本号;
  • 通过请求版本更新接口获取线上的安装包版本号;
  • 比较两个安装包版本号的大小,如果一致不更新,如果不一致,线上大于当前更新版本,线上小于当前不更新;

资源包版本更新

  • 通过uni.getStorage获取本地资源包版本号,如不存在,则通过uni.setStorage设置默认版本号;
  • 通过请求版本更新接口获取线上的资源包版本号;
  • 比较两个资源包版本号的大小,如果一致不更新,如果不一致,线上大于当前更新版本,线上小于当前不更新;

实战演练

模板使用

  • 比较版本号
html 复制代码
<view class="version-box">
  <view class="version-item">
    版本1:
    <input
      class="version-item-ipt"
      type="text"
      placeholder="请输入版本1"
      v-model="versionInfo.v1" />
  </view>
  <view class="version-item">
    版本2:
    <input
      class="version-item-ipt"
      type="text"
      placeholder="请输入版本2"
      v-model="versionInfo.v2" />
  </view>
  <view class="version-item">
    <button class="version-item-btn" type="primary" size="mini" @click="compareVersion('test')">
      比较版本
    </button>
  </view>
  <view class="version-item" v-show="versionInfo.text">
    <text>比较结果:</text>
    <text class="version-item-txt">{{ versionInfo.text }}</text>
  </view>
</view>
  • 获取线上版本
html 复制代码
<!-- #ifdef APP-PLUS -->
<view class="version-box">
  <view class="version-item">
    <button class="version-item-btn" type="primary" size="mini" @click="getVersion">
      获取版本
    </button>
  </view>
  <view class="version-item"> 当前版本: {{ checkInfo.current }} </view>
  <view class="version-item"> 线上版本: {{ checkInfo.online }} </view>
  <view class="version-item"> 当前资源包版本: {{ checkInfo.currentSource }} </view>
  <view class="version-item"> 线上资源包版本: {{ checkInfo.onlineSource }} </view>
</view>
<!-- #endif -->
  • 检测更新
html 复制代码
<!-- #ifdef APP-PLUS -->
<view class="version-box">
  <view class="version-item">
    <button class="version-item-btn" type="primary" size="mini" @click="checkUpdate">
      检测更新
    </button>
  </view>
  <view class="version-item" v-show="checkInfo.showProgress">
    <progress
      :percent="checkInfo.currentProgress"
      show-info
      :stroke-width="8"
      active-color="#24afd6" />
  </view>
</view>
<!-- #endif -->

样式编写

scss 复制代码
.version-box {
  padding: 10rpx;
  .version-item {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    margin-bottom: 20rpx;
    padding: 0 10rpx;
    .version-item-ipt {
      margin-left: 20rpx;
      padding: 10rpx;
      border: 3rpx solid $e;
      font-size: 27rpx;
    }
    .version-item-btn {
      margin: 0;
    }
    .version-item-txt {
      color: $mainColor;
    }
    .uni-progress {
      width: 100%;
    }
  }
}

脚本使用

定义数据

  • 比较版本信息
js 复制代码
const versionInfo = reactive({
  v1: "", // 版本1
  v2: "", // 版本2
  text: "", // 检测结果
});
  • 检测版本信息
js 复制代码
const checkInfo = reactive({
  current: "0.0.0", // 当前版本
  online: "0.0.0", // 线上版本
  currentSource: 0, // 当前资源包
  onlineSource: 0, // 线上资源包
  result: "", // 检测结果
  data: null, // 在线信息
  type: "", // 安装类型
  showProgress: false, // 显示进度条
  currentProgress: 0, // 当前进度
  downloader: null, // 下载定时器
});

方法调用

  • 模拟版本更新数据

使用之前介绍的静态服务器放置版本更新配置文件,格式如下:

json 复制代码
{
  "install": {
    "version": "1.0.0",
    "des": "亲爱的用户:\n有新的安装包发布了\n是否更新?",
    "url": "http://192.168.1.11:3000/xxx-1.0.0.apk"
  },
  "source": {
    "version": 1,
    "des": "亲爱的用户:\n有新的资源包发布了\n是否更新?",
    "url": "http://192.168.1.11:3000/xxx-001.wgt"
  }
}
  • 比较版本号封装方法
js 复制代码
// scripts/utils.js
// 比较版本号
function compareVersion(v1, v2) {
  v1 = v1.split(".");
  v2 = v2.split(".");
  let len = Math.max(v1.length, v2.length);
  while (v1.length < len) {
    v1.push("0");
  }
  while (v2.length < len) {
    v2.push("0");
  }

  for (let i = 0; i < len; i++) {
    let num1 = parseInt(v1[i]),
      num2 = parseInt(v2[i]);

    if (num1 > num2) {
      return 1;
    } else if (num1 < num2) {
      return -1;
    }
  }

  return 0;
}
  • 比较版本操作
js 复制代码
function compareVersion() {
  if (versionInfo.v1 == "") {
    uni.showToast({
      title: "请输入版本1!",
      icon: "error",
    });
    return;
  }
  if (versionInfo.v2 == "") {
    uni.showToast({
      title: "请输入版本2!",
      icon: "error",
    });
    return;
  }
  let res = proxy.$apis.utils.compareVersion(versionInfo.v1, versionInfo.v2);
  switch (res) {
    case 0:
      versionInfo.text = "版本1和版本2相同!";
      break;
    case 1:
      versionInfo.text = "版本1比版本2要新!";
      break;
    case -1:
      versionInfo.text = "版本1比版本2要老!";
      break;
    default:
      break;
  }
}
  • 获取在线版本操作
js 复制代码
async function getVersion() {
  let system = uni.getSystemInfoSync();
  let opts = {
    url: proxy.$apis.urls.version,
    method: "get",
  };
  let data = await proxy.$http.request(opts),
    v1 = system.appVersion,
    v2 = data.install.version;
  versionInfo.v1 = v1;
  versionInfo.v2 = v2;
  checkInfo.current = v1;
  checkInfo.online = v2;
  checkInfo.data = data;
  getSource();
  console.log("请求结果:", data);
}
  • 检测更新方法
js 复制代码
function checkUpdate() {
  let result = proxy.$apis.utils.compareVersion(checkInfo.current, checkInfo.online);
  checkInfo.result = result;
  // 本地版本最新
  if (checkInfo.result == 1) {
    uni.showToast({
      title: "已是最新版本!",
      icon: "success",
    });
    return;
  }
  // 线上版本最新
  if (checkInfo.result == -1) {
    let { des, url } = checkInfo.data.install;
    checkInfo.type = "install";
    installSet(des, url);
  }
  // 本地和线上版本相同
  if (checkInfo.result == 0) {
    checkSource();
  }
}
  • 获取资源包版本
js 复制代码
//
async function getSource() {
  let { source } = checkInfo.data,
    v1 = 0,
    v2 = 0,
    local = await proxy.$apis.utils.storeage({
      type: "get",
      isSync: true,
      key: "source",
    });
  if (local.code == 1) {
    v1 = local.data;
  } else {
    proxy.$apis.utils.storeage({
      type: "set",
      isSync: true,
      key: "source",
      val: 0,
    });
    v1 = 0;
  }
  let { version } = source;
  v2 = version;
  checkInfo.currentSource = v1;
  checkInfo.onlineSource = v2;
}
  • 资源包版本检测
js 复制代码
function checkSource() {
  if (checkInfo.currentSource >= checkInfo.onlineSource) {
    uni.showToast({
      title: "已是最新版本!",
      icon: "success",
    });
    return;
  }
  let { des, url } = checkInfo.data.source;
  checkInfo.type = "source";
  installSet(des, url);
}
  • 文件安装操作
js 复制代码
function installSet(content, url) {
  uni.showModal({
    title: "系统消息",
    content,
    cancelText: "取消更新",
    cancelColor: "#333",
    confirmText: "立马更新",
    confirmColor: "#24afd6",
    success(res) {
      if (res.confirm) {
        downloadFile(url);
      }
    },
    fail() {
      uni.showToast({
        title: "更新失败!",
        icon: "error",
      });
    },
  });
}
  • 下载文件操作
js 复制代码
async function downloadFile(url) {
  checkInfo.showProgress = true;
  downloadTime();
  let opts = {
    url,
  };
  let data = await proxy.$http.download(opts);
  if (data.code === 103) {
    checkInfo.showProgress = false;
    checkInfo.currentProgress = 0;
    uni.showToast({
      title: "下载失败!",
      icon: "error",
    });
    return;
  }
  if (data) {
    checkInfo.currentProgress = 100;
    installFile(data);
  }
}
  • 下载定时器
js 复制代码
function downloadTime() {
  checkInfo.downloader = setInterval(() => {
    if (checkInfo.currentProgress < 90) {
      let randomNum = Math.ceil(Math.random() * 5);
      checkInfo.currentProgress += randomNum;
    } else {
      clearInterval(checkInfo.downloader);
    }
  }, 1000);
}
  • 安装下载的文件
js 复制代码
function installFile(file) {
  if (plus) {
    uni.showLoading({
      title: "文件安装中...",
    });
    plus.runtime.install(
      file,
      {
        force: true,
      },
      (res) => {
        uni.hideLoading();
        checkInfo.showProgress = false;
        checkInfo.currentProgress = 0;
        proxy.$apis.utils.storeage({
          type: "set",
          isSync: true,
          key: "source",
          val: checkInfo.data.source.version,
        });
        plus.runtime.restart();
      },
      (err) => {
        uni.hideLoading();
        checkInfo.showProgress = false;
        checkInfo.currentProgress = 0;
        uni.showToast({
          title: "安装失败!",
          icon: "error",
        });
      }
    );
  } else {
    uni.showToast({
      title: "此版本不支持!",
      icon: "error",
    });
  }
}

微信小程序更新

根据微信小程序官网的文档,更新方法如下:

微信小程序检测更新文档

js 复制代码
const updateManager = wx.getUpdateManager();

updateManager.onCheckForUpdate(function (res) {
  // 请求完新版本信息的回调
  console.log(res.hasUpdate);
});

updateManager.onUpdateReady(function () {
  wx.showModal({
    title: "更新提示",
    content: "新版本已经准备好,是否重启应用?",
    success: function (res) {
      if (res.confirm) {
        // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
        updateManager.applyUpdate();
      }
    },
  });
});

updateManager.onUpdateFailed(function () {
  // 新版本下载失败
});

案例展示

h5 端效果

  • 比较版本方法示例

APP 端效果

  • 已是最新版本
  • 安装包新版本更新
  • 资源包新版本更新

最后

以上就是版本更新和热更新实现方法的主要内容,有不足之处,请多多指正。

相关推荐
神仙别闹16 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
aPurpleBerry40 分钟前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子1 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0011 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端1 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x1 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
木舟10091 小时前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤43912 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢2 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安2 小时前
前端第二次作业
前端·css·css3