Automatizar los releases de iOS y Android: qué ganamos frente a hacerlo a mano
ChronoFlow es una sola app Flutter que llega a Android, Android TV e iOS. Cada versión hay que compilarla, firmarla, numerarla y subirla a su tienda. Este artículo cuenta cómo lo automatizamos con GitHub Actions, qué cambia frente a hacerlo a mano, sobre todo en iOS, y qué no se puede automatizar. Seguimos en ese camino: lo usamos con nuestras compilaciones de prueba y con el primer envío a las tiendas.
Cómo es hacerlo a mano
En Android compilas el paquete, lo firmas con tu llave de subida, subes el número de versión a ojo y lo cargas en la consola de Play. En iOS, además, necesitas una Mac con Xcode: el certificado y el perfil de aprovisionamiento tienen que estar en el llavero correcto, archivas la app, la subes y llevas la cuenta de los números de build en la cabeza.
Funciona, pero tiene un costo escondido: la Mac se convierte en el proceso de release. Guarda las llaves, tiene la versión de Flutter que toca, y solo una persona sabe qué pasos seguir. Si esa máquina falla, o esa persona no está, no hay release.
Lo que automatizamos
Por plataforma hay dos flujos de GitHub Actions, y los dos se lanzan a mano con un botón, no con cada cambio:
- Compilación de pruebas. Compila el commit que quieres probar con la API de staging y lo sube al canal de pruebas: TestFlight en iOS y las pruebas internas en Play.
- Compilación de tienda. Cuando los testers aprueban, toma el mismo commit, lo recompila con la configuración de producción y un número de build nuevo, y lo sube a la tienda. Deja una etiqueta en git y un release en GitHub con el binario adjunto.
Las pruebas y el análisis no se repiten en el release: ya pasaron en el pull request que llevó el cambio a la rama principal. El release solo compila, firma y sube.
El caso de iOS: sin una Mac en el camino
Lo que más pesa de iOS es que compilar y firmar exige macOS. Nuestros flujos corren en un runner macOS que GitHub pone a disposición, así que el día del release no hay ninguna Mac nuestra en el camino: se compila, se firma y se sube desde la nube. El material de firma vive cifrado en los secretos del repositorio, se escribe en el trabajo y se borra al terminar.
Hay una salvedad honesta. Crear el certificado de distribución la primera vez es el paso que tradicionalmente pide el Acceso a Llaveros de una Mac. Es un paso que se hace una vez; después, nada de lo que se repite en cada versión lo necesita. También hay un costo: los minutos de macOS en GitHub cuestan más que los de Linux. Por eso el análisis y las pruebas de cada pull request corren en Linux y solo el release de iOS usa macOS.
Lo que aprendimos
- El build de la tienda no es el build de pruebas. Uno compilado con la API de staging nunca puede ser el que se publica. En lugar de una regla que alguien tiene que recordar, el flujo lo hace imposible: la compilación de tienda parte del commit que le indicas, el que pasó las pruebas, pero siempre recompila con producción y un número nuevo.
- Los números de build son sagrados. Las tiendas exigen que crezcan y no aceptan reutilizar uno. Los guardamos en un solo lugar, separados por plataforma. Cada release lee el contador y lo incrementa antes de subir, y solo corre un release a la vez. Un release fallido deja un hueco, y no pasa nada.
- Automatiza la compilación, no la decisión. El envío a revisión sigue siendo manual a propósito. Es más seguro y deja claro quién dijo «adelante».
- Todo deja rastro. Cada release tiene su etiqueta, su binario y su registro de ejecución. Si alguien pregunta qué hay exactamente en la tienda, la respuesta está en el repositorio.
Un detalle práctico: el token que GitHub da a cada ejecución no puede modificar variables del repositorio, así que para actualizar el contador usamos un token personal con un único permiso. Y en iOS, el registro de la app en App Store Connect tiene que existir antes de subir la primera compilación.
Lo que sigue siendo manual
La ficha de la tienda y sus capturas, los formularios de privacidad, las respuestas a la revisión y el botón de enviar. Nada de eso es una tarea de compilación, y tampoco queremos que lo sea. Lo que sí hicimos fue ordenarlo: lo contamos en un checklist para enviar tu primera app a las tiendas.
Lo que descartamos
- Publicar desde una Mac personal. Convierte a una persona y una máquina en un punto único de falla.
- Enviar a revisión de forma automática. Por ahora, la última decisión sigue siendo humana.
- Reutilizar el binario de pruebas. Tiene la configuración equivocada y no existe forma segura de cambiarla después.
Para seguir leyendo
Por qué una sola app es consola y pantalla: Controller y Player en una app. Dónde viven los archivos y por qué: dos proveedores de almacenamiento. El mapa de las guías: Construyendo ChronoFlow. Si necesitas llevar tu app a las tiendas: Servicios.