uniapp項目實踐總結(十九)版本更新和熱更新實現方法

導語:當一個 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 端效果

  • 比較版本方法示例
    image

APP 端效果

  • 已是最新版本
    image

  • 安裝包新版本更新
    image

  • 資源包新版本更新
    image

最後

以上就是版本更新和熱更新實現方法的主要內容,有不足之處,請多多指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章