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/ 的更改必须通过应用商店发布。
安装步骤:
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 组件独立。
结构:
features/app-update/model/types.ts— 状态(IDLE、CHECKING、AVAILABLE)和策略(NONE、NATIVE、PATCH)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.2→NATIVE(通过应用商店)1.0.3对比1.0.2→PATCH(OTA 更新)
GitHub Releases 作为单一数据源
GitHub API 返回标签、更新日志和 app-bundle.zip 的链接。用例解析版本并选择资源:
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 组件根据状态(AVAILABLE、DOWNLOADING、DOWNLOADED)条件显示。
关键要点:
- OTA 仅适用于补丁版本;主版本/次版本更新需通过应用商店
- 启动后 10 秒内调用
notifyAppReady()可防止回滚 - GitHub Releases 集版本控制、CDN 和 API 于一体
- 端口/适配器架构简化测试和提供商替换
- 通过原生插件事件实现下载进度显示
— Editorial Team
暂无评论。