返回首页

不通过商店的手动更新 Capacitor 捆绑包

文章描述了 @capgo/capacitor-updater 在 Capacitor 应用中 JS 捆绑包 OTA 更新的手动集成。提供了 provider 的代码示例、通过 CLI 准备 ZIP 存档、检查符合商店规则。适合中高级开发者。

Capacitor:绕过商店审核的捆绑包更新
Advertisement 728x90

无需应用商店的手动 Capacitor 捆绑包更新

移动 Capacitor 应用即使只是小幅调整 JS 代码或配置,也需要完整发布到商店。没有原生代码变更的情况下,Google Play、RuStore、AppGallery 和 App Store 的审核需要数天时间。自动化能帮忙,但审核环节不可避免。

解决方案是更新 dist(或 build)目录的内容,而无需重新构建原生部分。@capgo/capacitor-updater 插件支持手动或自动模式的空中捆绑包替换。

符合商店政策

所有平台都允许 JS 捆绑包更新,前提是满足以下条件:

Google AdInline article slot
  • Google Play:解释型代码(JS)允许,只要不违反资源滥用政策。
  • App Store:下载的代码不会改变应用的核心功能,不会创建代码分发商店,并且不会绕过 WebView 安全机制。

这些条件对于 Capacitor 混合应用来说自动满足。

安装和设置

安装依赖:

npm i @capgo/capacitor-updater compare-versions

capacitor.config.ts 中添加:

Google AdInline article slot
plugins: {
  CapacitorUpdater: {
    autoUpdate: false,
  },
},

autoUpdate: false 模式启用手动更新管理。

为 React 创建 AppUpdateProvider(根据您的框架调整):

const AppUpdateProvider: FC<PropsWithChildren> = ({ children }) => {
  return children;
};

export default AppUpdateProvider;

更新逻辑

在 provider 中,启动后前 10 秒内调用 CapacitorUpdater.notifyAppReady() —— 否则会报错。

Google AdInline article slot

通过 API(GitHub 或内部服务)获取最新发布数据。使用 compare-versions 比较版本。

完整 useEffect 示例:

useEffect(() => {
  if (appRelease === null) {
    dispatch(getAppRelease({ type: ReleaseType.APP, last: true }));
  } else {
    const downloadBundle = async () => {
      dispatch(setAppUpdating(true));
      return CapacitorUpdater.download({
        url: APP_BUNDLE_DOWNLOAD_LINK,
        version: appRelease.version,
      });
    };

    CapacitorUpdater.addListener('downloadComplete', async ({ bundle: downloadedBundle }) => {
      try {
        await CapacitorUpdater.set(downloadedBundle);
        dispatch(setAppUpdating(false));
      } catch (e) {
        console.error(e);
        dispatch(setAppUpdating(false));
      }
    });

    if (compare(String(version), appRelease.version, '<')) downloadBundle();

    return () => {
      CapacitorUpdater.removeAllListeners();
      App.removeAllListeners();
    };
  }
}, [appRelease]);

准备捆绑包

严格使用 Capgo CLI 创建捆绑包归档:

npx @capgo/cli bundle zip [appId] --name [myapp]
  • appId 来自 capacitor.config.ts
  • 构建前更新 package.json 中的 version
  • 将 ZIP 上传到 HTTPS 服务器(GitHub Releases 或自有托管)。

归档链接传递给 CapacitorUpdater.download({ url, version })

下载完成后,downloadComplete 事件触发 CapacitorUpdater.set() —— 捆绑包替换,应用重启。

应用集成

完整 provider:

const AppUpdateProvider: FC<PropsWithChildren> = ({ children }) => {
  CapacitorUpdater.notifyAppReady();
  const dispatch = useAppDispatch();
  const appRelease = useAppSelector(selectAppRelease);

  // useEffect 如上

  return children;
};

main.tsx 中包装 App:

root.render(
  <Provider store={store({})}>
    <AppUpdateProvider>
      <App />
    </AppUpdateProvider>
  </Provider>
);

要点

  • 更新仅适用于 JS 捆绑包,不涉及原生插件。
  • 捆绑包必须通过 npx @capgo/cli bundle zip 归档,其他方式无效。
  • 必须在启动前 10 秒内调用 notifyAppReady()
  • 版本比较:compare(currentVersion, newVersion, '<')
  • 自托管 Capgo —— 追求完全控制的替代方案。

— Editorial Team

Advertisement 728x90

继续阅读