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 端效果

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

最后

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

相关推荐
cwj&xyp4 分钟前
Python(二)str、list、tuple、dict、set
前端·python·算法
dlnu20152506226 分钟前
ssr实现方案
前端·javascript·ssr
古木201910 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端