uni-app App升级功能实现

因为uni-app提供的 uni-upgrade-center 需要配合uniCloud使用,所以,需要寻找在不使用 uniCloud 的情况下实现 App 的版本检查和自动更新功能方法。在 uni-app 中实现 App 更新功能,主要依赖于 HTML5+ 规范提供的 API 和 uni-app 的跨平台能力。

1. 整体流程

需要更新 已是最新 立即更新 成功 失败 稍后更新 启动检查更新 请求服务器版本信息 版本比较 显示更新对话框 提示已是最新版本 用户选择 下载更新文件 显示下载进度 安装更新 安装结果 重启应用 提示安装失败 继续使用

2. 核心 API 详解

2.1 uni.getSystemInfoSync()

功能:获取获取系统信息

关键返回值:

javascript 复制代码
{
  appName: "宠医宝",
  appVersion: "1.0.0",
  appVersionCode: 100,
  appWgtVersion: "1.0.0",
  platform: '',      // 客户端平台(ios/android)
  system: '',        // 操作系统版本
  model: '',         // 设备型号
  screenWidth: 375,  // 屏幕宽度
  screenHeight: 667  // 屏幕高度
}

使用示例

javascript 复制代码
const systemInfo= uni.getSystemInfoSync();
console.log('运行平台:', systemInfo.platform);   // "ios" 或 "android"
console.log('当前版本:', systemInfo.appVersion); // 如: "1.2.0"
console.log('版本码:', systemInfo.appVersionCode);  // 如: "120"

2.2 uni.downloadFile()

功能:下载文件资源到本地

语法

javascript 复制代码
const downloadTask = uni.downloadFile({
  url: '',           // 下载资源的 URL(必需)
  header: {},        // HTTP 请求 Header
  timeout: 60000,    // 超时时间,单位 ms
  success: function (res) { },  // 下载成功的回调函数
  fail: function (err) { },     // 下载失败的回调函数
  complete: function () { }     // 接口调用结束的回调函数
});

返回值 downloadTask 对象方法:

json 复制代码
{
  onProgressUpdate: Function,  // 监听下载进度变化
  abort: Function,             // 中断下载任务
  onHeadersReceived: Function, // 监听 HTTP Response Header
  offProgressUpdate: Function, // 取消监听下载进度变化
  offHeadersReceived: Function // 取消监听 HTTP Response Header
}

使用示例

javascript 复制代码
// 1. 基础下载
const downloadTask = uni.downloadFile({
  url: 'https://example.com/app-release.apk',
  success: (res) => {
    if (res.statusCode === 200) {
      console.log('下载成功,临时文件路径:', res.tempFilePath);
    }
  }
});

// 2. 监听下载进度
downloadTask.onProgressUpdate((res) => {
  console.log('下载进度:', res.progress + '%');
  console.log('已下载:', res.totalBytesWritten + ' bytes');
  console.log('总大小:', res.totalBytesExpectedToWrite + ' bytes');
});

// 3. 中断下载
downloadTask.abort();

2.4 plus.runtime.install()

功能:安装下载的文件

语法

javascript 复制代码
plus.runtime.install(filePath, options, successCB, errorCB);

参数说明

  • filePath {String}:安装文件路径(必需)
  • options {Object}:安装选项
    • force {Boolean}:是否强制安装(默认 false)
  • successCB {Function}:安装成功回调函数
  • errorCB {Function}:安装失败回调函数

使用示例

javascript 复制代码
plus.runtime.install(res.tempFilePath, {
  force: false
}, (installRes) => {
  console.log('安装成功');
  // 通常在此处重启应用
  plus.runtime.restart();
}, (error) => {
  console.error('安装失败:', error.message);
});

注意事项

  • 需要文件读写权限
  • Android 需要特殊权限才能安装 APK
  • iOS 由于系统限制无法直接安装,通常跳转到 App Store

2.5 plus.runtime.restart()

功能:重启当前应用

使用示例

javascript 复制代码
// 安装成功后重启应用
plus.runtime.install(filePath, {}, () => {
  plus.runtime.restart(); // 重启应用使更新生效
}, (error) => {
  console.error('安装失败:', error);
});

2.6 plus.runtime.quit()

功能:退出应用

使用场景

javascript 复制代码
// 强制更新时用户拒绝更新,退出应用
if (this.updateInfo.forceUpdate) {
  plus.runtime.quit();
}

注意事项

  • 会完全退出应用进程

3. 权限配置

Android 平台需要配置相应权限:

json 复制代码
{
  "app-plus": {
    "permissions": {
      "android": {
        "permissions": [
          "<uses-permission android:name=\"android.permission.INTERNET\"/>",
          "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
          "<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>"
        ]
      }
    }
  }
}

4. 组件化设计

html 复制代码
<template>
  <view class="update-manager">
    <!-- 检查更新按钮 -->
    <button class="check-update-btn" @click="checkUpdate">
      <text>检查更新</text>
    </button>

    <!-- 更新进度弹窗 -->
    <uni-popup ref="progressPopup" type="center">
      <view class="progress-popup">
        <view class="progress-content">
          <text class="progress-title">正在下载更新...</text>
          <progress :percent="downloadProgress" show-info stroke-width="8" class="progress-bar" />
          <button type="warn" @click="cancelDownload">取消下载</button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

5. 核心实现

5.1 版本检查流程

javascript 复制代码
// 检查更新 - 完整流程
async checkUpdate() {
  try {
    // 步骤1: 请求服务器获取最新版本信息
    const res = await new Promise((resolve, reject) => {
      uni.request({
        url: "http://192.168.6.222/check-version",
        method: "GET",
        success: (res) => resolve(res),
        fail: (err) => reject(err),
      });
    });

    if (res.data.code === 200) {
      // 步骤2: 保存服务端版本信息
      this.updateInfo = res.data.data;
      
      // 步骤3: 获取系统信息
      const systemInfo = uni.getSystemInfoSync();
      
      // 步骤4: 版本比较
      const updateResult = this.checkVersionUpdate(systemInfo);

      if (updateResult.needsUpdate) {
        // 需要更新,显示更新对话框
        this.showUpdateDialog(updateResult.platform);
      } else {
        // 已是最新版本
        uni.showToast({
          title: "当前已是最新版本",
          icon: "success",
        });
      }
    }
  } catch (error) {
    console.error("检查更新失败:", error);
    uni.showToast({
      title: "检查更新失败",
      icon: "none",
    });
  }
}

// 版本比较逻辑
checkVersionUpdate(systemInfo) {
  // 使用版本码进行数值比较(推荐)
  const needsUpdate = this.updateInfo.versionCode > systemInfo.appVersionCode;
  
  // 获取平台信息
  const platform = systemInfo.platform;

  return {
    needsUpdate,
    platform,
  };
}

要点:

  • 使用 versionCode 而非 version 进行版本比较更准确:版本码是数字,便于比较,避免了版本号字符串比较的复杂性(如 1.10 < 1.2 的问题)
  • Promise 封装 uni.request 使代码更清晰

5.2 下载与安装流程

javascript 复制代码
// 下载并更新 (Android专用) - 详细解析
async downloadAndUpdate() {
  // 步骤1: 显示下载进度弹窗
  this.showProgress();
  this.downloadProgress = 0;

  // 步骤2: 开始下载文件
  this.downloadTask = uni.downloadFile({
    url: this.updateInfo.url,  // 从服务端获取的下载地址
    success: (res) => {
      if (res.statusCode === 200) {
        // 步骤3: 下载成功,开始安装
        plus.runtime.install(
          res.tempFilePath,        // 下载得到的临时文件路径
          { force: false },        // 安装选项
          (installRes) => {
            // 安装成功回调
            this.hideProgress();
            uni.showModal({
              title: "更新下载完成",
              content: "是否立即重启应用?",
              success: (modalRes) => {
                if (modalRes.confirm) {
                  plus.runtime.restart(); // 重启应用使更新生效
                }
              },
            });
          },
          (error) => {
            // 安装失败回调
            this.hideProgress();
            console.error("安装失败:", error);
            this.handleInstallError(error);
          }
        );
      } else {
        this.handleDownloadError();
      }
    },
    fail: (err) => {
      // 下载失败处理
      this.handleDownloadError();
    },
  });

  // 步骤4: 监听下载进度并更新 UI
  this.downloadTask.onProgressUpdate((res) => {
    this.downloadProgress = res.progress;
  });
}

5.3 平台差异化处理

javascript 复制代码
// 显示更新对话框 - 平台适配
showUpdateDialog(platform) {
  const content = `发现新版本 ${this.updateInfo.title},此版本为重要更新,请及时升级!\n\n更新内容:\n${this.updateInfo.updateInfo || "功能优化与bug修复"}`;

  uni.showModal({
    title: "发现新版本",
    content: content,
    showCancel: true,
    confirmText: "立即更新",
    cancelText: "稍后更新",
    success: (res) => {
      if (res.confirm) {
        // 根据平台执行不同更新操作
        if (platform === "ios") {
          this.goToAppStore();      // iOS跳转App Store
        } else if (platform === "android") {
          this.downloadAndUpdate(); // Android下载安装
        }
      } else if (res.cancel && this.updateInfo.forceUpdate) {
        // 强制更新时用户取消则退出应用
        plus.runtime.quit();
      }
    },
  });
}

// 跳转到App Store
goToAppStore() {
  if (this.updateInfo.appStoreUrl) {
    plus.runtime.openURL(this.updateInfo.appStoreUrl);
  } else {
    const appStoreUrl = "https://apps.apple.com/app/id您的应用ID";
    plus.runtime.openURL(appStoreUrl);
  }
}

5.4 取消下载

javascript 复制代码
// 取消下载
cancelDownload() {
  if (this.downloadTask) {
    this.downloadTask.abort();
    this.hideProgress();
    uni.showToast({
      title: '已取消下载',
      icon: 'none'
    });
  }
}

5.5 错误处理

javascript 复制代码
// 处理下载错误
handleDownloadError() {
  this.hideProgress();
  uni.showModal({
    title: "下载失败",
    content: "更新文件下载失败,请检查网络连接后重试",
    showCancel: true,
    success: (res) => {
      if (this.updateInfo.forceUpdate) {
        plus.runtime.quit();
      }
    },
  });
},
相关推荐
CS Beginner5 小时前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
reept6 小时前
Pytorch常用函数学习摘录
人工智能·pytorch·学习
老程序员刘飞6 小时前
node.js 和npm 搭建项目基本流程
前端·npm·node.js
歪歪1006 小时前
在C#中除了按属性排序,集合可视化器还有哪些辅助筛选的方法?
开发语言·前端·ide·c#·visual studio
jamesge20107 小时前
zookeeper学习笔记
笔记·学习·zookeeper·1024程序员节
Century_Dragon7 小时前
比亚迪秦新能源汽车动力系统拆装与检测实训MR软件介绍
学习
wangbing11257 小时前
开发指南139-VUE里的高级糖块
前端·javascript·vue.js
半桶水专家7 小时前
Vue 3 动态组件详解
前端·javascript·vue.js
Yupureki7 小时前
从零开始的C++学习生活 19:C++复习课(5.4w字全解析)
c语言·数据结构·c++·学习·1024程序员节