Migrar una app antigua de Ionic/Angular de plugins Cordova obsoletos a Capacitor



Si tu app Ionic/Angular todavia tiene paquetes cordova-plugin-* en el lockfile, eso suele ser lo que hoy te esta bloqueando una actualizacion de Xcode o del target SDK de Android -- la mayor parte de ese ecosistema quedo sin mantenimiento real desde 2021-2022, y Capacitor es el runtime por defecto de Ionic desde la v6. La buena noticia: los plugins que aparecen en casi toda app Ionic antigua -- camara, geolocalizacion, splash screen, status bar, notificaciones locales, estado de red -- tienen reemplazos directos en Capacitor y con mantenimiento activo. La migracion es mecanica en la mayor parte. Un par de puntos se rompen de verdad.

mapa plugin por plugin

Plugin CordovaReemplazo CapacitorQue cambia realmente
cordova-plugin-camera@capacitor/cameraBasado en promesas en vez de callbacks; la clave de Info.plist en iOS no cambia
cordova-plugin-geolocation@capacitor/geolocationEl id de watchPosition ahora es string, no numero
cordova-plugin-splashscreen@capacitor/splash-screenLa config pasa de las etiquetas <preference> a capacitor.config.ts
cordova-plugin-statusbar@capacitor/status-barEl estilo ahora es un enum con nombre, no un booleano
cordova-plugin-local-notification@capacitor/local-notificationsLa programacion usa un objeto trigger en vez de una fecha at suelta
cordova-plugin-network-information@capacitor/networkLas constantes Connection.* desaparecen; el tipo de conexion es un string union

cordova-plugin-camera → @capacitor/camera

Antes:

navigator.camera.getPicture(
  (imageData) => { this.photo = 'data:image/jpeg;base64,' + imageData; },
  (err) => { console.error(err); },
  { quality: 75, destinationType: Camera.DestinationType.DATA_URL }
);

Despues:

import { Camera, CameraResultType } from '@capacitor/camera';

const photo = await Camera.getPhoto({
  quality: 75,
  resultType: CameraResultType.Base64,
});
this.photo = `data:image/jpeg;base64,${photo.base64String}`;

El punto donde se rompe no es la forma de la API, es Android. Si tu platforms/android/AndroidManifest.xml tenia permisos o entradas de FileProvider agregadas a mano, eso vivia en una carpeta que Cordova regeneraba en cada build, y Capacitor no la toca de la misma manera -- hay que volver a agregar esas entradas en el android/app/src/main/AndroidManifest.xml real y permanente que ahora vive en tu repo.

cordova-plugin-geolocation → @capacitor/geolocation

Antes:

navigator.geolocation.watchPosition(
  (pos) => this.updatePosition(pos.coords),
  (err) => console.error(err),
  { enableHighAccuracy: true }
);

Despues:

import { Geolocation } from '@capacitor/geolocation';

const watchId = await Geolocation.watchPosition(
  { enableHighAccuracy: true },
  (position, err) => {
    if (position) this.updatePosition(position.coords);
  }
);
// mas tarde
await Geolocation.clearWatch({ id: watchId });

El punto de ruptura: watchId ahora es string, no numero. El codigo que lo guardaba en un number[], o lo usaba como clave numerica de un mapa, falla en silencio en un proyecto sin TypeScript en modo estricto -- que es el caso de muchas apps Ionic antiguas.

los puntos de ruptura comunes, mas alla de un plugin puntual

  • Los callbacks se vuelven promesas. Todo lo que asumia un callback de sensacion sincrona dentro de un binding de template de Angular merece una segunda mirada a la deteccion de cambios -- las respuestas del puente nativo a veces llegan fuera de la zona de Angular, y un valor que en silencio nunca actualiza la UI suele ser un NgZone.run() faltante, no un plugin roto.
  • La carpeta platforms/ desaparece. platforms/android y platforms/ios de Cordova, con lo que hayas editado a mano en AndroidManifest.xml, Info.plist o el Podfile, no existen en el modelo de Capacitor. Los proyectos nativos (android/, ios/) se suben al repo y se editan de forma permanente -- encontra cada edicion manual en el viejo arbol platforms/ antes de borrarlo, porque despues se pierde.
  • Los hooks no tienen equivalente directo. Las entradas <hook> de config.xml (scripts de before_build, after_prepare) hay que migrarlas al ciclo de vida nativo propio de un plugin de Capacitor, o a un script postbuild de npm comun.
  • Las variables de plugin desaparecen. Los valores <preference name="..."> de Cordova, pasados como --variable al instalar, no tienen un mecanismo equivalente en tiempo de instalacion -- esos valores pasan a capacitor.config.ts.

pasar config.xml a capacitor.config.ts

Antes:

<preference name="SplashScreenDelay" value="3000" />
<preference name="StatusBarStyle" value="lightcontent" />
<allow-navigation href="https://api.myapp.com/*" />

Despues:

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.codeceibe.myapp',
  appName: 'MyApp',
  webDir: 'www',
  server: {
    allowNavigation: ['api.myapp.com'],
  },
  plugins: {
    SplashScreen: {
      launchShowDuration: 3000,
    },
    StatusBar: {
      style: 'DARK',
    },
  },
};

export default config;
Cordova's regenerated platform folders versus Capacitor's checked-in native projectsCordovaWebView + cordova.js bridgeplugins/ (config.xml references)platforms/android, platforms/iosregenerated on everycordova prepare -- edits get lostCapacitorWebView + native bridgenpm plugin packages call native codeandroid/, ios/ checked into the repoedited directly, kept permanently,never regenerated

un orden de migracion que no te deja la build rota a mitad de camino

  1. Agrega Capacitor junto a tus dependencias Cordova existentes (ionic integrations enable capacitor) sin sacar nada todavia -- ambos pueden convivir un rato.
  2. Cambia los plugins de a uno, empezando por el menos usado en la app, y hace una build real a dispositivo despues de cada cambio en vez de agruparlos.
  3. Una vez que todos los plugins estan cambiados y los dos proyectos nativos compilan limpio desde android/ y ios/, saca platforms/ y las dependencias cordova-* que queden.
  4. Borra config.xml al final, solo cuando cada ajuste que tenia ya tiene un lugar confirmado en capacitor.config.ts o directamente en los archivos del proyecto nativo.

Hacerlo en ese orden significa que si un paso falla, te queda una app funcionando en el stack viejo, no una a medio migrar que no compila para ninguna de las dos plataformas.

Dejar un comentario

Los comentarios anónimos se publican tras ser revisados.