Saltar al contenido
Volver al inicio
Volver al blog
Tutorial

Workflows: automatiza tareas de desarrollo en Android, sin servidor

Automatiza tareas en Android con los Workflows de PocketCode: 25 disparadores, ramas y bucles, cron con zonas horarias, permisos por workflow y secretos cifrados. Sin servidor.

13 min
Por Pelayo Naredo
Workflows: automatiza tareas de desarrollo en Android, sin servidor

Todo desarrollador acumula las mismas pequeñas tareas repetitivas: lanzar los tests después de un push, hacer una copia de seguridad de la base de datos cuando sale un deploy, formatear al guardar, avisarte cuando falla un build. En un portátil lo unes todo con runners de CI, tareas cron y un par de scripts de shell en algún servidor. En un móvil, la respuesta de siempre es «no se puede». Pocket Code cambia eso con los Workflows: un motor de automatización basado en eventos que te permite automatizar tareas en Android por completo en el dispositivo, sin ningún servidor que alquilar ni nada que mantener vivo en la nube.

Un workflow es sencillo de describir: un disparador (un evento dentro del IDE o una programación) más una secuencia de pasos que se ejecutan sobre un contexto compartido. Eso basta para construir flujos de desarrollo reales —del tipo para el que normalmente montarías un pipeline de CI— justo al lado de tu editor, tu terminal y tu gestor de base de datos.

Cuatro formas de crear uno

Nunca tienes que empezar desde un lienzo en blanco:

ModoCómo lo creasEjemplo
PlantillaToca Activar en una de las 17 plantillas integradas"Tests y, si pasan, deploy", "Auto-deploy al push a main", "Copia de la base de datos tras el deploy"
Describírselo a la IAEscribes una frase y obtienes un esqueleto editable"cuando haya push a main, despliega y notifica" se convierte en un workflow con su rama de error
EditorEl botón "+" para el formulario completoConstrúyelo desde cero, con expresiones y política de reintento
Importar un ficheroAbres un .pcwf.json que te pasó alguienLlega apagado y con identificador nuevo, así que no se ejecuta hasta que lo has leído

Activar una plantilla la clona en una copia editable con un identificador nuevo, así que puedes ajustarla sin tocar el original.

Disparadores: qué despierta a un workflow

Los workflows escuchan los eventos que fluyen por el IDE. El motor se suscribe al bus interno de la app y asocia cada evento a un tipo de disparador. Hay veinticinco tipos, y un workflow puede llevar un disparador principal y tantos extra como quieras:

FamiliaDisparadores
GitPush, commit
FicherosGuardado, creado, borrado, renombrado
Proyecto y buildProyecto abierto o cerrado, build terminado, ejecución terminada, comando de terminal terminado
Deploy y datosDeploy completado, deploy fallido, consulta de base de datos ejecutada
Otros módulosRespuesta del API Tester, diseño exportado, el agente de IA tocó un fichero, el agente de IA terminó un turno
Desde el propio móvilAcceso directo, tile de ajustes rápidos, texto compartido, fichero compartido, app en primer plano
Encadenar y manualError detectado (otro workflow falló), manual o programado

El filtro es tipado, y esto es un cambio importante respecto a versiones anteriores: cada disparador declara sus campos, y comparas campo contra valor con operadores —igual, contiene, empieza por, coincide, rutas glob—. Ya no es buscar una subcadena en el texto del evento. Y como acertar a la primera con un filtro es difícil, el editor trae un botón de capturar el siguiente evento: haces la acción, y te enseña la carga real que trae el disparador para que escribas el filtro contra algo que existe.

No todos los tipos tienen todavía quien los emita. En vez de esconderlos, el panel de problemas te avisa cuando un workflow usa un disparador que hoy no se dispararía nunca — un disparador que existe y no se puede usar es peor si no se dice.

Programación: cron en tu móvil, sin servidor

Aquí es donde la «automatización sin servidor» se vuelve concreta. Cualquier workflow puede llevar uno o varios horarios: un intervalo, o una expresión cron de cinco campos con comodines *, listas N,M, rangos N-M y pasos */N. Mientras escribes, la pantalla te enseña el siguiente disparo o te dice que la expresión está mal.

Tres cosas que suelen faltar en este tipo de programadores y aquí están:

  • Zona horaria por horario, con el cambio de hora resuelto. En marzo, a la hora que no existe, dispara en el salto; en octubre, a la hora que ocurre dos veces, dispara una sola. Está probado.
  • Política de lo perdido. Tú eliges: saltarte lo que cayó con el dispositivo apagado, o recuperarlo una vez al volver. Una, no las cuarenta y ocho de un fin de semana largo.
  • Condiciones del dispositivo. Cualquier conexión, solo Wi-Fi o ninguna; solo mientras carga; no con la batería baja; solo con el dispositivo inactivo. Una condición retrasa el disparo, no lo cancela, y la pantalla lo dice con esas palabras.

Y una honestidad incómoda: Android no ejecuta trabajo en segundo plano más a menudo que cada quince minutos. Un intervalo por debajo se sube y la app te da la cifra exacta. Un cron por debajo no lo sube nadie, así que lo único cierto es que no hay garantía — y eso es lo que dice la pantalla, en vez de un número que sería inventado.

Los horarios se persisten y se vuelven a encolar al arrancar la app, así que la muerte de un proceso no vacía tu automatización sin que te enteres.

Ramas, bucles y subflujos

El editor no es una lista de pasos en fila. Hay siete formas de paso, de las cuales seis son control de flujo, y las ramas se anidan dentro de ramas: lo que construyes es un árbol.

  • Si / si no — dos ramas. La condición es un árbol, no un hueco único: And, Or y Not se anidan, así que «pasaron los tests y la rama es main» es una condición, no dos workflows.
  • En paralelo — N ramas a la vez, juntadas de tres formas: cuando acaben todas, con la primera que termine, o con la primera que salga bien. Las dos últimas cancelan las ramas perdedoras para que dejen de provocar efectos.
  • Para cada — itera una lista con un alias por elemento, un tope de seguridad de iteraciones y un número opcional de iteraciones a la vez.
  • Intentar / si falla — si algo del primer bloque falla, el segundo se ejecuta con el mensaje de error ligado a una variable que tú nombras.
  • Subflujo — ejecuta otro workflow entero dentro de este, con sus propias entradas. Es lo que convierte un workflow largo en piezas reutilizables.
  • Espera — un tiempo, o hasta que ocurra un evento con el tiempo como tope. «Espera a que acabe el deploy» en vez de «espera dos minutos y cruza los dedos».

Y sin montar un paso de control: cada paso lleva una condición propia opcional. Si es falsa el paso se salta, sin envolverlo en un si / si no entero.

Quince acciones, todas cableadas

Los pasos de acción son quince, y las quince están conectadas a algo que se ejecuta de verdad: ejecutar un comando, una petición HTTP, una operación de git, un deploy, una consulta o copia de la base de datos, leer, escribir o comprobar un fichero, abrirlo en el editor, analizar o generar con IA, transformar un valor, guardar una variable y notificar.

Que las quince tengan implementación no es un detalle de presentación: hay un test que se pone rojo nombrando cualquier tipo que se quede sin ella. Un tipo sin nada detrás falla en voz alta en vez de dar éxito en silencio.

Que un paso sea destructivo se calcula con sus parámetros delante, no por su tipo: git status no es git push, y crear un fichero nuevo no es sobrescribir uno. Etiquetar el tipo entero como destructivo obligaría a confirmar hasta un status, y pedir confirmación para todo enseña a aceptar sin leer.

Pasar datos entre pasos

Los pasos comparten un contexto, y cualquier campo puede referenciar a otro con una expresión entre llaves dobles:

ExpresiónSe resuelve a
{{var.nombre}}Una entrada declarada o un valor que puso un paso
{{step.<id>.status}}El estado de un paso
{{step.<id>.output.json.items[0].name}}Un campo de la salida, navegando dentro del JSON
{{step.<id>.error}}El mensaje de error de un paso
{{item.<alias>}}El elemento de la iteración viva
{{trigger.<campo>}}La carga tipada del evento que lo disparó
{{secret.NOMBRE}}Un secreto guardado. Terminal: no se puede navegar dentro

Y trece filtros encadenables: lines, first, last, trim, upper, lower, length, json, default, split, join, date, replace. Así, la primera línea de la salida de un comando es {{step.sh.output.stdout | lines | first | trim}}.

Una expresión que no resuelve devuelve cadena vacía a propósito, para que una referencia a un paso de una rama que no se ejecutó no tumbe el run. Si prefieres lo contrario, hay un interruptor por workflow: en modo estricto, no resolver es un error con motivo, y el motivo llega al detalle del run.

Fiabilidad: reintentos, topes de tiempo y qué hacer al fallar

Cada paso admite una política de reintentos (con espera fija, lineal o exponencial y un tope para esa espera), un tope de tiempo y una política de qué hacer si falla: cortar el run o seguir.

Dos detalles que cuestan encontrarse:

  • Seguir ante un fallo no tiñe el run. El paso queda en rojo con su error, pero el run sale verde — la misma distinción que hace continue-on-error en Acciones de GitHub.
  • Un tope de tiempo no se reintenta. Vuelve marcado como agotado y ese resultado se devuelve tal cual.

Y un paso se puede desactivar sin borrarlo, que es lo que uno quiere mientras depura, en vez de borrarlo y volver a escribirlo.

Además, en vez de correr el workflow entero —con sus despliegues y sus notificaciones— cada vez que ajustas un parámetro, puedes probar un paso suelto con los datos fijados como contexto. Un paso que no se puede simular no se simula: el botón pasa a decir «ejecutar este paso de verdad» y pregunta antes. Un botón que diga «correcto» sin haber ejecutado nada es peor que no tener botón.

Permisos y secretos

Un workflow declara lo que se le permite hacer: salir a la red, escribir ficheros, ejecutar comandos, y una lista de dominios a los que puede llegar. Las implementaciones lo comprueban antes de tocar nada, y el rechazo dice qué permiso fue, qué iba a ejecutarse y dónde se cambia. Un subflujo hereda la intersección de los permisos: no puede abrir lo que el padre cerró.

No es un cajón de arena, y la pantalla lo dice: quien pueda editar el workflow puede abrir el cinturón. Protege del descuido — un workflow que abriste a la IA, uno que te mandó otra persona, o la curl que alguien pegó «solo para probar» y se quedó ahí.

Los secretos van en un almacén cifrado por cuenta. Los referencias como {{secret.NOMBRE}} y el valor no se vuelve a enseñar, tampoco en su propia pantalla. Solo se resuelven en un run de verdad; el tapado cubre todos los valores guardados, no solo los que leyó un paso; y ocurre antes de escribir en la base de datos, no al pintar — tapar al pintar llegaría tarde, el valor ya estaría en el fichero y en cualquier copia de seguridad.

Historial de ejecuciones que puedes inspeccionar

Cada ejecución se anota entera, con el resultado de cada paso, lo que tardó, cuántos intentos necesitó y su error si lo hubo. Sobrevive a los cierres y a los fallos de la app. La pestaña de Actividad es la vista global de todos los workflows, filtrable por estado, por fecha, por workflow y por el texto del error.

La retención la pones tú: 100 runs y 30 días por defecto, configurable entre 1 y 1.000 runs y entre 1 y 365 días.

Compartir uno

Un workflow viaja como un fichero .pcwf.json. Lo que no viaja: el historial, las salidas fijadas, los horarios y el interruptor de activación. Lo que llega llega apagado y con identificador nuevo.

Los valores de parámetros marcados como secretos se vacían antes de escribir el fichero y se listan, para que quien lo abra sepa qué tiene que rellenar. Una referencia {{secret.X}} sí viaja: es un nombre, no el secreto, y vaciarla rompería el workflow de forma irreparable.

Descríbelo en lenguaje natural

Si prefieres no ensamblar los pasos a mano, escribes una frase. La respuesta del modelo se corrige donde se puede, pasa por el linter, se prueba en seco, y se te enseña el resultado antes de guardar nada. También puedes pedirle que cambie uno que ya tienes: se fusiona la respuesta encima conservando identificador, activación y fecha, y se te enseña el diff.

Si no tienes modelo configurado hay un respaldo heurístico local, que es lo único que funciona para quien todavía no ha puesto su clave. El documento que se le manda al modelo no lleva valores de parámetros secretos: se sustituyen por un marcador.

Y al revés: cualquier workflow que marques como «disponible para el agente de IA» se expone como herramienta en el chat, y el agente puede llamarlo.

Tu automatización se queda en tu dispositivo

Las definiciones, el historial y los horarios viven en una base de datos local en tu móvil. Las definiciones pueden respaldarse en la nube para restaurarlas, pero nunca se lee nada de la nube para ejecutar tu automatización: el motor se ejecuta localmente, punto. El historial y los horarios no se sincronizan en absoluto: el historial es local del dispositivo, y los horarios son estado de WorkManager específico de cada dispositivo.

Una última nota de honestidad, por si estás comparando con n8n o Make: aquí las ramas son un árbol anidado, no nodos que cableas en un lienzo. No hay switch de N salidas ni forma de unir una rama a un nodo concreto de más abajo. Tampoco hay disparador por webhook, y los workflows todavía no se instalan ni se publican en el Marketplace: hoy compartir uno es compartir el fichero.

PocketCode va camino de Google Play, llevando un motor de automatización completo —veinticinco disparadores, ramas, cron en el móvil, permisos y secretos— a la misma app donde escribes y publicas el código. Apúntate al preregistro para estar entre los primeros en probarlo en tu propio dispositivo.

La herramienta detrás de este artículo

Workflows

¿Listo para probar PocketCode?

Descarga la app y empieza a programar desde tu móvil.