Zpět na domů

OTA aktualizace Capacitor: architektura a GitHub

Článek popisuje refaktoring systému OTA-aktualizací pro aplikace Capacitor s použitím GitHub Releases a čisté architektury. Jsou zváženy strategie NATIVE/PATCH, adaptéry pro Capgo, Zustand-store a zpracování průběhu stahování.

Čistá architektura OTA pro aplikace Capacitor
Advertisement 728x90

Architektura OTA aktualizací pro Capacitor: strategie a GitHub Releases

Capacitor umožňuje aktualizovat JavaScriptový balíček mobilní aplikace bez nutnosti schvalování v Google Play nebo App Store. Nativní obálka zůstává nezměněna, zatímco produktový kód je nahrazen prostřednictvím ZIP archivu. Systém využívá GitHub Releases jako zdroj verzí a @capgo/capacitor-updater pro stahování. Automatický rollback při selhání zajišťuje notifyAppReady() během prvních 10 sekund spuštění.

Legalita a omezení

Google Play povoluje aktualizace interpretovaného kódu (JavaScript), pokud se nezmění hlavní účel aplikace. Apple umožňuje stahování JS balíčků při zachování funkcionality a bez obcházení bezpečnostních mechanismů. Hranice je jasná: změny v android/ nebo ios/ vyžadují publikování přes obchod.

Instalace:

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

V capacitor.config.ts vypneme automatické aktualizace:

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

Sestavení balíčku:

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

Nová architektura: FSD a Ports & Adapters

Kód je rozdělen na src/features/app-update/ (obchodní logika) a src/shared/api/ (adaptéry). Funkce pracuje přes rozhraní, aniž by znala Capgo nebo GitHub. Zustand store spravuje stav, UI komponenty jsou izolované.

Google AdInline article slot

Struktura:

  • features/app-update/model/types.ts — stavy (IDLE, CHECKING, AVAILABLE) a strategie (NONE, NATIVE, PATCH)
  • features/app-update/model/contracts.ts — rozhraní závislostí
  • shared/api/app-updater/capgo-updater-runtime.ts — obálka nad pluginem
  • shared/api/github/github-runtime.ts — požadavky na GitHub API

Strategie aktualizací podle semver

Určení typu aktualizace:

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 vs 1.0.2NATIVE (obchod)
  • 1.0.3 vs 1.0.2PATCH (OTA)

GitHub Releases jako jednotný zdroj

GitHub API vrací tag, changelog a odkaz na app-bundle.zip. Use-case parsuje verze a vybírá asset:

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');
  // ...
};

Adaptér pro 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 };
  },
});

Adaptér Capgo a zpracování událostí

Rozhraní izoluje obchodní logiku od pluginu:

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

Zustand store se přihlašuje k průběhu:

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

Aplikace: CapacitorUpdater.set(bundle) + App.minimizeApp() pro plynulý restart.

Inicializace a UI

V main.tsx po vykreslení:

await initializeUpdater();

initializeUpdater() vytváří závislosti, volá notifyAppReady() a kontroluje aktualizace. Komponenta AppUpdateInfo se zobrazuje podmíněně podle stavu (AVAILABLE, DOWNLOADING, DOWNLOADED).

Co je důležité:

  • OTA pouze pro patch verze; major/minor — přes obchod
  • notifyAppReady() v prvních 10s zabraňuje rollbacku
  • GitHub Releases — verzování, CDN, API v jednom
  • Architektura přes porty/adaptéry zjednodušuje testy a výměnu poskytovatelů
  • Průběh stahování přes nativní události pluginu

— Editorial Team

Advertisement 728x90

Číst dál