Triển khai tính năng cập nhật ứng dụng trong uni-app

Giới thiệu

uni-app cung cấp uni-upgrade-center nhưng yêu cầu sử dụng uniCloud. Bài viết này sẽ hướng dẫn cách triển khai tính năng kiểm tra và tự động cập nhật ứng dụng mà không cần phụ thuộc vào uniCloud. Chúng ta sẽ tận dụng các API từ chuẩn HTML5+ và khả năng đa nền tảng của uni-app.

Luồng làm việc chung

  1. Kiểm tra phiên bản mới trên máy chủ.
  2. So sánh phiên bản hiện tại của ứng dụng với phiên bản mới nhất.
  3. Nếu có phiên bản mới, hiển thị thông báo cho người dùng.
  4. Nếu người dùng đồng ý, tải xuống gói cập nhật.
  5. Cài đặt gói cập nhật và khởi động lại ứng dụng.

Giải thích các API cốt lõi

2.1 uni.getSystemInfoSync()

API này dùng để lấy thông tin về hệ thống thiết bị.

const thongTinHeThong = uni.getSystemInfoSync();
console.log('Nền tảng:', thongTinHeThong.platform); // "ios" hoặc "android"
console.log('Phiên bản ứng dụng:', thongTinHeThong.appVersion); // Ví dụ: "1.2.0"
console.log('Mã phiên bản:', thongTinHeThong.appVersionCode); // Ví dụ: 120

2.2 uni.downloadFile()

Dùng để tải tài nguyên về thiết bị.

// Bắt đầu một tác vụ tải xuống
const nhiemVuTaiXuong = uni.downloadFile({
  url: 'https://example.com/app-update.apk', // URL tài nguyên
  success: (res) => {
    if (res.statusCode === 200) {
      console.log('Tải xuống thành công, đường dẫn tạm:', res.tempFilePath);
    }
  },
  fail: (err) => {
    console.error('Tải xuống thất bại:', err);
  }
});

// Lắng nghe tiến độ tải xuống
nhiemVuTaiXuong.onProgressUpdate((res) => {
  console.log('Tiến độ:', res.progress + '%');
});

// Hủy tác vụ tải xuống
nhiemVuTaiXuong.abort();

2.3 plus.runtime.install()

Dùng để cài đặt file đã tải xuống.

plus.runtime.install(
  duongDanFile, // Đường dẫn file cần cài đặt
  { force: false }, // Tùy chọn cài đặt
  (thongTin) => {
    console.log('Cài đặt thành công');
    // Khởi động lại ứng dụng
    plus.runtime.restart();
  },
  (loi) => {
    console.error('Cài đặt thất bại:', loi.message);
  }
);

2.4 plus.runtime.restart()

Khởi động lại ứng dụng hiện tại.

// Sau khi cài đặt thành công, khởi động lại ứng dụng
plus.runtime.install(duongDanFile, {}, () => {
  plus.runtime.restart(); // Khởi động lại để áp dụng cập nhật
}, (error) => {
  console.error('Lỗi cài đặt:', error);
});

2.5 plus.runtime.quit()

Thoát hoàn toàn ứng dụng.

// Trong trường hợp cập nhật bắt buộc, nếu người dùng từ chối
if (this.thongTinCapNhat.batBuocCapNhat) {
  plus.runtime.quit();
}

Cấu hình quyền

Đối với nền tảng Android, cần khai báo các quyền sau trong file manifest:

{
  "app-plus": {
    "permissions": {
      "android": {
        "permissions": [
          "",
          "",
          ""
        ]
      }
    }
  }
}

Thiết kế component

<template>
  <view class="quan-ly-cap-nhat">
    <!-- Nút kiểm tra cập nhật -->
    <button class="nut-kiem-tra" @click="kiemTraCapNhat">
      <text>Kiểm tra cập nhật</text>
    </button>

    <!-- Popup hiển thị tiến độ tải xuống -->
    <uni-popup ref="popupTiennDo" type="center">
      <view class="popup-tien-do">
        <view class="noi-dung-tien-do">
          <text class="tieu-de-tien-do">Đang tải xuống...</text>
          <progress :percent="tienDoTaiXuong" show-info stroke-width="8" class=" thanh-tien-do" />
          <button type="warn" @click="huyTaiXuong">Hủy</button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

Triển khai cốt lõi

5.1 Kiểm tra phiên bản

// Hàm kiểm tra cập nhật
async kiemTraCapNhat() {
  try {
    // Bước 1: Gửi yêu cầu đến máy chủ để lấy thông tin phiên bản mới
    const ketQua = await uni.request({
      url: "http://mayserv/cap-nhat-phien-ban",
      method: "GET"
    });

    if (ketQua.data.code === 200) {
      // Bước 2: Lưu thông tin phiên bản từ máy chủ
      this.thongTinCapNhat = ketQua.data.data;
      
      // Bước 3: Lấy thông tin hệ thống
      const thongTinHeThong = uni.getSystemInfoSync();
      
      // Bước 4: So sánh phiên bản
      const ketQuaSoSanh = this.soSanhPhienBan(thongTinHeThong);

      if (ketQuaSoSanh.canCapNhat) {
        // Cần cập nhật, hiển thị hộp thoại
        this.hienThiHopThoaiCapNhat(ketQuaSoSanh.nenTang);
      } else {
        // Đã là phiên bản mới nhất
        uni.showToast({
          title: "Ứng dụng đã là phiên bản mới nhất",
          icon: "success",
        });
      }
    }
  } catch (error) {
    console.error("Lỗi kiểm tra cập nhật:", error);
    uni.showToast({
      title: "Không thể kiểm tra cập nhật",
      icon: "none",
    });
  }
}

// Logic so sánh phiên bản
soSanhPhienBan(thongTinHeThong) {
  // Sử dụng mã phiên bản để so sánh (khuyến nghị)
  const canCapNhat = this.thongTinCapNhat.maPhienBan > thongTinHeThong.appVersionCode;
  const nenTang = thongTinHeThong.platform;

  return {
    canCapNhat,
    nenTang,
  };
}

5.2 Tải xuống và cài đặt

// Tải xuống và cài đặt (chỉ dành cho Android)
async taiXuongVaCapNhat() {
  // Bước 1: Hiển thị popup tiến độ
  this.hienThiPopupTiennDo();
  this.tienDoTaiXuong = 0;

  // Bước 2: Bắt đầu tải file
  this.nhiemVuTaiXuong = uni.downloadFile({
    url: this.thongTinCapNhat.duongDan, // Đường dẫn từ máy chủ
    success: (res) => {
      if (res.statusCode === 200) {
        // Bước 3: Tải xuống thành công, bắt đầu cài đặt
        plus.runtime.install(
          res.tempFilePath, // Đường dẫn file tạm
          { force: false }, // Tùy chọn cài đặt
          (thongTin) => {
            // Callback khi cài đặt thành công
            this.anPopupTiennDo();
            uni.showModal({
              title: "Cập nhật hoàn tất",
              content: "Bạn có muốn khởi động lại ứng dụng ngay bây giờ?",
              success: (hopThoai) => {
                if (hopThoai.confirm) {
                  plus.runtime.restart(); // Khởi động lại để áp dụng cập nhật
                }
              },
            });
          },
          (loi) => {
            // Callback khi cài đặt thất bại
            this.anPopupTiennDo();
            console.error("Lỗi cài đặt:", loi);
            this.xuLyLoiCaiDat(loi);
          }
        );
      } else {
        this.xuLyLoiTaiXuong();
      }
    },
    fail: (err) => {
      // Xử lý lỗi tải xuống
      this.xuLyLoiTaiXuong();
    },
  });

  // Bước 4: Lắng nghe tiến độ tải xuống và cập nhật UI
  this.nhiemVuTaiXuong.onProgressUpdate((res) => {
    this.tienDoTaiXuong = res.progress;
  });
}

5.3 Xử lý khác biệt giữa các nền tảng

// Hiển thị hộp thoại cập nhật - tùy chỉnh theo nền tảng
hienThiHopThoaiCapNhat(nenTang) {
  const noiDung = `Đã có phiên bản mới ${this.thongTinCapNhat.tieuDe}, vui lòng cập nhật!\\n\\nNội dung cập nhật:\\n${this.thongTinCapNhat.noiDungCapNhat || "Tối ưu hóa và sửa lỗi"}`;

  uni.showModal({
    title: "Cập nhật mới",
    content: noiDung,
    showCancel: true,
    confirmText: "Cập nhật ngay",
    cancelText: "Sau",
    success: (hopThoai) => {
      if (hopThoai.confirm) {
        // Thực hiện hành động cập nhật khác nhau tùy nền tảng
        if (nenTang === "ios") {
          this.chuyenHuongAppStore(); // Chuyển đến App Store trên iOS
        } else if (nenTang === "android") {
          this.taiXuongVaCapNhat(); // Tải xuống và cài đặt trên Android
        }
      } else if (hopThoai.cancel && this.thongTinCapNhat.batBuocCapNhat) {
        // Nếu là cập nhật bắt buộc và người dùng hủy
        plus.runtime.quit();
      }
    },
  });
}

// Chuyển hướng đến App Store
chuyenHuongAppStore() {
  if (this.thongTinCapNhat.duongDanAppStore) {
    plus.runtime.openURL(this.thongTinCapNhat.duongDanAppStore);
  } else {
    const duongDanAppStore = "https://apps.apple.com/app/idID-cua-ban";
    plus.runtime.openURL(duongDanAppStore);
  }
}

5.4 Hủy tải xuống

// Hủy tác vụ tải xuống
huyTaiXuong() {
  if (this.nhiemVuTaiXuong) {
    this.nhiemVuTaiXuong.abort();
    this.anPopupTiennDo();
    uni.showToast({
      title: 'Đã hủy tải xuống',
      icon: 'none'
    });
  }
}

5.5 Xử lý lỗi

// Xử lý lỗi khi tải xuống
xuLyLoiTaiXuong() {
  this.anPopupTiennDo();
  uni.showModal({
    title: "Lỗi tải xuống",
    content: "Không thể tải xuống gói cập nhật. Vui lòng kiểm tra kết nối mạng và thử lại.",
    showCancel: true,
    success: (hopThoai) => {
      if (this.thongTinCapNhat.batBuocCapNhat) {
        plus.runtime.quit();
      }
    },
  });
}

Thẻ: uni-app HTML5+ Android iOS cập nhật ứng dụng

Đăng vào ngày 7 tháng 8 lúc 16:00