返回首页

OTA 更新 Capacitor:架构和 GitHub

本文描述了使用 GitHub 发行版和干净架构对 Capacitor 应用的 OTA 更新系统的重构。NATIVE/PATCH 策略、Capgo 的适配器、Zustand store 和下载进度处理均已考虑。

Capacitor 应用的干净 OTA 架构
Advertisement 728x90

Capacitor OTA 更新架构:策略与 GitHub Releases 实践

Capacitor 允许在不经过 Google Play 或 App Store 审核的情况下,更新移动应用的 JavaScript 代码包。原生外壳保持不变,产品代码通过 ZIP 压缩包替换。该系统使用 GitHub Releases 作为版本源,并通过 @capgo/capacitor-updater 进行下载。启动后 10 秒内调用 notifyAppReady() 可确保失败时自动回滚。

合法性与限制

Google Play 允许更新解释型代码(如 JavaScript),只要应用的主要功能未改变。Apple 允许下载 JS 代码包,前提是功能保持不变且未绕过安全机制。界限明确:对 android/ios/ 的更改必须通过应用商店发布。

安装步骤:

Google AdInline article slot
npm install @capgo/capacitor-updater
npx cap sync

capacitor.config.ts 中,禁用自动更新:

const config: CapacitorConfig = {
  plugins: {
    CapacitorUpdater: {
      autoUpdate: false,
    },
  },
};

构建代码包:

npm run build:dist
npx @capgo/cli bundle zip io.your.app --name app-bundle.zip

新架构:FSD 与端口适配器模式

代码分为 src/features/app-update/(业务逻辑)和 src/shared/api/(适配器)。功能通过接口操作,不依赖 Capgo 或 GitHub。Zustand 状态管理库管理状态,UI 组件独立。

Google AdInline article slot

结构:

  • features/app-update/model/types.ts — 状态(IDLECHECKINGAVAILABLE)和策略(NONENATIVEPATCH
  • features/app-update/model/contracts.ts — 依赖接口
  • shared/api/app-updater/capgo-updater-runtime.ts — 插件封装
  • shared/api/github/github-runtime.ts — GitHub API 请求

基于语义化版本的更新策略

确定更新类型:

const isReleaseHasNativeUpdate = (current: SemVer, remote: SemVer): boolean =>
  remote.major > current.major || remote.minor > current.minor;

const isReleaseHasPatchUpdate = (current: SemVer, remote: SemVer): boolean =>
  remote.major === current.major &&
  remote.minor === current.minor &&
  remote.patch > current.patch;
  • 1.1.0 对比 1.0.2NATIVE(通过应用商店)
  • 1.0.3 对比 1.0.2PATCH(OTA 更新)

GitHub Releases 作为单一数据源

GitHub API 返回标签、更新日志和 app-bundle.zip 的链接。用例解析版本并选择资源:

Google AdInline article slot
export const checkForAvailableUpdate = async (deps: AppUpdateDependencies): Promise<CheckResult> => {
  const releaseResult = await deps.githubRuntime.getLatestReleaseInfo();
  // ...
  const bundleAsset = assets.find(a => a.name === 'app-bundle.zip');
  // ...
};

GitHub 适配器:

export const createGithubRuntime = (): GithubRuntime => ({
  getLatestReleaseInfo: async () => {
    const response = await fetch(config.APP_RELEASE_URL);
    const data: GithubLatestReleaseResponse = await response.json();
    return { status: true, data };
  },
});

Capgo 适配器与事件处理

接口将业务逻辑与插件隔离:

export const createCapgoUpdaterRuntime = (): CapgoUpdaterRuntime => ({
  downloadBundle: (url, version) => CapacitorUpdater.download({ url, version }),
  notifyAppReady: () => CapacitorUpdater.notifyAppReady(),
  addDownloadListener: (listener) => CapacitorUpdater.addListener('download', listener),
});

Zustand 状态库订阅下载进度:

startDownloadUpdate: async () => {
  set({ status: APP_UPDATE_STATUSES.DOWNLOADING, downloadProgress: 0 });
  await capgoRuntime.addDownloadListener(({ percent }) => {
    set({ downloadProgress: percent });
  });
  const bundle = await capgoRuntime.downloadBundle(bundleDownloadUrl, remoteVersion);
},

应用:CapacitorUpdater.set(bundle) + App.minimizeApp() 实现平滑重启。

初始化与用户界面

main.tsx 渲染后:

await initializeUpdater();

initializeUpdater() 创建依赖项,调用 notifyAppReady(),并检查更新。AppUpdateInfo 组件根据状态(AVAILABLEDOWNLOADINGDOWNLOADED)条件显示。

关键要点:

  • OTA 仅适用于补丁版本;主版本/次版本更新需通过应用商店
  • 启动后 10 秒内调用 notifyAppReady() 可防止回滚
  • GitHub Releases 集版本控制、CDN 和 API 于一体
  • 端口/适配器架构简化测试和提供商替换
  • 通过原生插件事件实现下载进度显示

— Editorial Team

Advertisement 728x90

继续阅读