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

目录

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

准备工作

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

原理分析

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

安装包版本更新

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

资源包版本更新

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

实战演练

模板使用

  • 比较版本号
<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>
  • 获取线上版本
<!-- #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 -->
  • 检测更新
<!-- #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 -->

样式编写

.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%;
    }
  }
}

脚本使用

定义数据

  • 比较版本信息
const versionInfo = reactive({
  v1: "", // 版本1
  v2: "", // 版本2
  text: "", // 检测结果
});
  • 检测版本信息
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, // 下载定时器
});

方法调用

  • 模拟版本更新数据

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

{
  "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"
  }
}
  • 比较版本号封装方法
// 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;
}
  • 比较版本操作
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;
  }
}
  • 获取在线版本操作
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);
}
  • 检测更新方法
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();
  }
}
  • 获取资源包版本
//
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;
}
  • 资源包版本检测
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);
}
  • 文件安装操作
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",
      });
    },
  });
}
  • 下载文件操作
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);
  }
}
  • 下载定时器
function downloadTime() {
  checkInfo.downloader = setInterval(() => {
    if (checkInfo.currentProgress < 90) {
      let randomNum = Math.ceil(Math.random() * 5);
      checkInfo.currentProgress += randomNum;
    } else {
      clearInterval(checkInfo.downloader);
    }
  }, 1000);
}
  • 安装下载的文件
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",
    });
  }
}

微信小程序更新

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

微信小程序检测更新文档

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

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

最后

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


MarkGuan
108 声望8 粉丝

Talk is cheap, show me the code.