Arquitectura de Actualizaciones OTA en Capacitor: Estrategias y Lanzamientos en GitHub
Capacitor permite actualizar el paquete JavaScript de una aplicación móvil sin necesidad de revisión en Google Play o la App Store. La capa nativa permanece sin cambios, mientras que el código del producto se reemplaza mediante un archivo ZIP. El sistema utiliza GitHub Releases como fuente de versiones y @capgo/capacitor-updater para la descarga. La reversión automática en caso de fallos está garantizada por notifyAppReady() dentro de los primeros 10 segundos del inicio.
Legalidad y Limitaciones
Google Play permite actualizaciones de código interpretado (JavaScript) siempre que no se altere el propósito principal de la aplicación. Apple permite descargar paquetes JS siempre que se preserve la funcionalidad y no se eludan los mecanismos de seguridad. La línea es clara: los cambios en android/ o ios/ requieren publicación a través de la tienda.
Instalación:
npm install @capgo/capacitor-updater
npx cap sync
En capacitor.config.ts, desactiva la actualización automática:
const config: CapacitorConfig = {
plugins: {
CapacitorUpdater: {
autoUpdate: false,
},
},
};
Construye el paquete:
npm run build:dist
npx @capgo/cli bundle zip io.your.app --name app-bundle.zip
Nueva Arquitectura: FSD y Puertos y Adaptadores
El código se divide en src/features/app-update/ (lógica de negocio) y src/shared/api/ (adaptadores). La funcionalidad opera a través de interfaces, sin conocimiento de Capgo o GitHub. Un almacén Zustand gestiona el estado, con componentes de UI aislados.
Estructura:
features/app-update/model/types.ts— estados (IDLE,CHECKING,AVAILABLE) y estrategias (NONE,NATIVE,PATCH)features/app-update/model/contracts.ts— interfaces de dependenciashared/api/app-updater/capgo-updater-runtime.ts— envoltorio sobre el pluginshared/api/github/github-runtime.ts— solicitudes a la API de GitHub
Estrategias de Actualización por Semver
Determinación del tipo de actualización:
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(tienda)1.0.3vs1.0.2→PATCH(OTA)
GitHub Releases como Fuente Única
La API de GitHub devuelve la etiqueta, el registro de cambios y el enlace a app-bundle.zip. El caso de uso analiza versiones y selecciona el recurso:
export const checkForAvailableUpdate = async (deps: AppUpdateDependencies): Promise<CheckResult> => {
const releaseResult = await deps.githubRuntime.getLatestReleaseInfo();
// ...
const bundleAsset = assets.find(a => a.name === 'app-bundle.zip');
// ...
};
Adaptador para 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 };
},
});
Adaptador de Capgo y Manejo de Eventos
La interfaz aísla la lógica de negocio del plugin:
export const createCapgoUpdaterRuntime = (): CapgoUpdaterRuntime => ({
downloadBundle: (url, version) => CapacitorUpdater.download({ url, version }),
notifyAppReady: () => CapacitorUpdater.notifyAppReady(),
addDownloadListener: (listener) => CapacitorUpdater.addListener('download', listener),
});
El almacén Zustand se suscribe al progreso:
startDownloadUpdate: async () => {
set({ status: APP_UPDATE_STATUSES.DOWNLOADING, downloadProgress: 0 });
await capgoRuntime.addDownloadListener(({ percent }) => {
set({ downloadProgress: percent });
});
const bundle = await capgoRuntime.downloadBundle(bundleDownloadUrl, remoteVersion);
},
Aplicación: CapacitorUpdater.set(bundle) + App.minimizeApp() para un reinicio suave.
Inicialización y UI
En main.tsx después del renderizado:
await initializeUpdater();
initializeUpdater() crea dependencias, llama a notifyAppReady() y verifica actualizaciones. El componente AppUpdateInfo se muestra condicionalmente según el estado (AVAILABLE, DOWNLOADING, DOWNLOADED).
Puntos Clave:
- OTA solo para versiones de parche; actualizaciones mayores/menores van por la tienda
notifyAppReady()dentro de los primeros 10s evita la reversión- GitHub Releases combina versionado, CDN y API en un solo lugar
- Arquitectura de puertos/adaptadores simplifica pruebas y reemplazo de proveedores
- Progreso de descarga mediante eventos del plugin nativo
— Editorial Team
Aún no hay comentarios.