Architektura aktualizacji OTA dla Capacitor: strategie i GitHub Releases
Capacitor umożliwia aktualizację pakietu JavaScript aplikacji mobilnej bez recenzji w Google Play czy App Store. Natywna powłoka pozostaje niezmieniona, a kod produktu jest zastępowany przez archiwum ZIP. System wykorzystuje GitHub Releases jako źródło wersji i @capgo/capacitor-updater do pobierania. Automatyczny powrót do poprzedniej wersji w przypadku awarii zapewnia notifyAppReady() w ciągu pierwszych 10 sekund uruchomienia.
Legalność i ograniczenia
Google Play zezwala na aktualizacje interpretowanego kodu (JavaScript), jeśli nie zmienia się główne przeznaczenie aplikacji. Apple dopuszcza pobieranie pakietów JS przy zachowaniu funkcjonalności i bez omijania mechanizmów bezpieczeństwa. Granica jest jasna: zmiany w android/ lub ios/ wymagają publikacji przez sklep.
Instalacja:
npm install @capgo/capacitor-updater
npx cap sync
W capacitor.config.ts wyłączamy autoaktualizację:
const config: CapacitorConfig = {
plugins: {
CapacitorUpdater: {
autoUpdate: false,
},
},
};
Budowa pakietu:
npm run build:dist
npx @capgo/cli bundle zip io.your.app --name app-bundle.zip
Nowa architektura: FSD i Ports & Adapters
Kod jest podzielony na src/features/app-update/ (logika biznesowa) i src/shared/api/ (adaptery). Funkcjonalność działa przez interfejsy, nie znając Capgo czy GitHub. Stan zarządzany jest przez Zustand-store, komponenty UI są izolowane.
Struktura:
features/app-update/model/types.ts— statusy (IDLE,CHECKING,AVAILABLE) i strategie (NONE,NATIVE,PATCH)features/app-update/model/contracts.ts— interfejsy zależnościshared/api/app-updater/capgo-updater-runtime.ts— opakowanie nad wtyczkąshared/api/github/github-runtime.ts— zapytania do GitHub API
Strategie aktualizacji według semver
Określenie typu aktualizacji:
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.0vs1.0.2→NATIVE(sklep)1.0.3vs1.0.2→PATCH(OTA)
GitHub Releases jako jedno źródło
GitHub API zwraca tag, changelog i link do app-bundle.zip. Use-case parsuje wersje i wybiera zasób:
export const checkForAvailableUpdate = async (deps: AppUpdateDependencies): Promise<CheckResult> => {
const releaseResult = await deps.githubRuntime.getLatestReleaseInfo();
// ...
const bundleAsset = assets.find(a => a.name === 'app-bundle.zip');
// ...
};
Adapter dla 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 };
},
});
Adapter Capgo i obsługa zdarzeń
Interfejs izoluje logikę biznesową od wtyczki:
export const createCapgoUpdaterRuntime = (): CapgoUpdaterRuntime => ({
downloadBundle: (url, version) => CapacitorUpdater.download({ url, version }),
notifyAppReady: () => CapacitorUpdater.notifyAppReady(),
addDownloadListener: (listener) => CapacitorUpdater.addListener('download', listener),
});
Zustand-store subskrybuje postęp:
startDownloadUpdate: async () => {
set({ status: APP_UPDATE_STATUSES.DOWNLOADING, downloadProgress: 0 });
await capgoRuntime.addDownloadListener(({ percent }) => {
set({ downloadProgress: percent });
});
const bundle = await capgoRuntime.downloadBundle(bundleDownloadUrl, remoteVersion);
},
Zastosowanie: CapacitorUpdater.set(bundle) + App.minimizeApp() dla płynnego restartu.
Inicjalizacja i UI
W main.tsx po renderowaniu:
await initializeUpdater();
initializeUpdater() tworzy zależności, wywołuje notifyAppReady() i sprawdza aktualizacje. Komponent AppUpdateInfo wyświetla się warunkowo według statusu (AVAILABLE, DOWNLOADING, DOWNLOADED).
Co jest ważne:
- OTA tylko dla wersji patch; major/minor — przez sklep
notifyAppReady()w ciągu pierwszych 10s zapobiega powrotowi do poprzedniej wersji- GitHub Releases — wersjonowanie, CDN i API w jednym
- Architektura przez porty/adaptery upraszcza testy i wymianę dostawców
- Postęp pobierania przez natywne zdarzenia wtyczki
— Editorial Team
Brak komentarzy.