← Nesim Apps

Dos docenas de apps Android mantenidas por un solo dev

Por Nesim Razon, desarrollador Android independiente · 2026-11-12

#Notas de desarrollo#Android#Herramientas y calculadoras

Mantengo yo solo unas dos docenas de apps y juegos Android pequeños: una mezcla de juegos de puzles y utilidades cotidianas. Eso solo funciona porque casi todo lo que se repite se copia de un patrón conocido y probado, o se saca de la app por completo. Esta entrada describe los patrones que han sobrevivido y los hábitos que los rodean.

La regla de fondo: escribirlo una vez y copiar la forma

Con una sola app te puedes permitir ser ingenioso. Con dos docenas, cada caso especial que inventas es un caso especial que olvidarás. Por eso cada función que aparece en más de una app tiene una implementación de referencia, y las apps nuevas la copian en lugar de reinventarla. La referencia vive en uno de los juegos más recientes, y la siguiente app parte de ese archivo, con su prueba incluida.

Copiar no es elegante, y una biblioteca compartida quedaría más ordenada sobre el papel. En la práctica las apps difieren en nombres de paquete, configuración de anuncios y pantallas, se publican según su propio calendario, y un módulo compartido obligaría a publicar todas a la vez cada vez que cambiara. Copiar un archivo pequeño y bien probado mantiene cada app independiente. Cuando el patrón mejora, las apps antiguas reciben el cambio en su próxima versión natural, sin prisas.

La promoción cruzada como dato, no como código

Cada juego tiene una ventana de Otros juegos que lista al resto de la familia. Al principio esa lista estaba compilada dentro de cada app, de modo que lanzar un juego nuevo significaba publicar una actualización de todos los antiguos. Eso no escala.

Ahora la lista es un pequeño archivo JSON servido desde un sitio web estático. Una sola clase en cada app lo descarga como máximo cada 48 horas y lo guarda en caché en el dispositivo. Si no hay red, o el archivo en caché falta o está dañado, la app recurre a una copia incluida en sus recursos, así que la ventana nunca queda vacía. Un juego nuevo es una fila nueva en el JSON más un icono, y ninguna app antigua necesita una versión nueva.

Como el archivo llega por la red, la app lo trata como no fiable. Solo abre enlaces de Google Play, comprueba el nombre del paquete y la clave con patrones estrictos, limita el número de entradas y el tamaño del archivo, y rechaza cualquier servidor distinto del esperado. La ventana lee el idioma del dispositivo y, si no lo encuentra, usa inglés. El archivo lo genera un script breve a partir de una lista de juegos, así que nunca edito el JSON a mano.

Aviso de actualización y guardado en la nube, copiados de una referencia

Hay dos funciones fáciles de olvidar cuando uno se concentra en la jugabilidad y caras de añadir más tarde: avisar al usuario de que existe una versión nueva y conservar su progreso cuando cambia de teléfono. Las dos están ya en mi lista de comprobación para la primera versión de cualquier app nueva.

Para las actualizaciones uso la API de actualización dentro de la app de Google Play en modo flexible. Un objeto pequeño comprueba al volver a primer plano. Solo pregunta si de verdad hay una actualización disponible, solo cuando la versión nueva lleva al menos un día publicada, porque Google Play despliega de forma gradual, y como máximo una vez cada tres días por la misma versión. Cuando termina la descarga, ofrece reiniciar. Si la app no se instaló desde Google Play, o el dispositivo no tiene conexión, la comprobación no hace nada en silencio. La lógica de decisión es una función pura, por eso tiene pruebas unitarias, y los textos del diálogo están en cuatro idiomas.

Para el progreso uso las partidas guardadas de Play Games en los juegos que tienen un estado de progreso significativo, de modo que un teléfono nuevo continúa donde terminó el anterior. Que cada juego nuevo lo tenga desde la primera versión es una decisión deliberada, tomada una sola vez. Un par de juegos antiguos son excepciones a propósito, porque su estado es trivial.

Una clave de subida y Play App Signing

Las apps nuevas usan Play App Signing. Google guarda la clave de firma real y yo solo tengo una clave de subida, compartida entre las apps más recientes. Si una clave de subida se pierde o se compromete, se puede restablecer desde Play, lo cual da mucho menos miedo que perder una clave de firma real. Las apps anteriores a este sistema conservan su firma original y se gestionan aparte; mantengo ambos grupos claramente separados en mis notas para no confundirlos.

Los scripts de publicación piden la contraseña de la clave en el momento de firmar, y no se escribe nada secreto en ningún archivo, repositorio ni código.

Un sitio web que se construye solo

Cada app necesita una página de presentación, una de privacidad y otra de condiciones de uso, y para los juegos escribo además guías y artículos de blog. Hacer eso a mano para dos docenas de apps en cuatro idiomas es una forma segura de quedarse atrás, así que el sitio se genera.

Un solo comando lo reconstruye todo. Ejecuta los generadores en un orden fijo: la página de inicio, las páginas de detalle de cada app, las guías de los juegos y el blog, y al final un paso que divide una única fuente en cuatro idiomas en páginas separadas por idioma. El inglés queda en la raíz y los demás en carpetas de idioma. Ese paso también escribe los enlaces hreflang, las direcciones canónicas, un mapa del sitio con fechas de última modificación y datos estructurados. Los datos de la página de inicio están en un único archivo JSON: una app nueva es una fila más, y una app aún sin publicar se puede marcar como próxima, de modo que su tarjeta aparece sola el día del lanzamiento.

Una regla que mantengo: los archivos generados nunca se editan a mano. Si una página está mal, corrijo el generador o los datos y reconstruyo. Las carpetas de idioma se borran y se reescriben en cada compilación, así que una edición manual desaparecería de todos modos, y esa es la idea. Mantiene la salida coherente, y la coherencia es lo único que un desarrollador en solitario no se puede permitir perder.

Scripts para lo aburrido

Todo lo que hago más de dos veces se convierte en un script. Un script de sincronización actualiza todos los repositorios, uno por app, e informa de cuáles tienen trabajo sin confirmar o sin enviar, de modo que veo en una sola pantalla si es seguro cambiar de equipo. Cada app tiene un script de compilación y otro de publicación que genera el paquete firmado, y la salida de la compilación va a un archivo de registro con nombre único, donde busco las palabras que importan en lugar de mirar cómo se desplaza el texto.

Trabajo con dos ordenadores en dos lugares distintos, así que el script de sincronización me ha salvado más de una vez de confirmaciones olvidadas. Es algo pequeño y se amortiza cada semana.

Notas y lista de tareas, mantenidas con honestidad

La memoria no da para dos docenas de proyectos. Cada app tiene en su raíz un archivo de notas con el estado actual: qué se publicó, qué versión está activa, qué está pendiente y por qué se tomó una decisión pasada. Una única lista de tareas general recoge todo lo abierto en todas las apps, y un breve registro continuo anota lo que pasó en cada sesión de trabajo.

Lo importante es la disciplina de mantenerlos veraces. Cuando termino una tarea, actualizo la lista y las notas de la app en la misma sesión, y antes de planificar nada contrasto lo escrito con lo real; por ejemplo, pregunto a Google Play qué versión está activa en lugar de fiarme de lo que anoté la semana pasada. Una lista que muestra como abierto lo que ya está hecho, o al revés, es peor que no tener lista, porque te hace desconfiar de toda ella.

Lo que cuesta este enfoque

No es gratis. Los archivos copiados se desvían con el tiempo, así que una app antigua puede tener una versión algo más vieja de un patrón hasta su próxima publicación. Un sitio generado implica que el propio generador es un software que debo mantener y probar. Y una lista remota es una cosa más que puede fallar, por eso cada función remota tiene una copia de respaldo incluida y una validación estricta.

A cambio obtengo previsibilidad. Una app nueva empieza con las actualizaciones, el guardado en la nube, un menú, una página de privacidad, la promoción cruzada y una entrada en el sitio ya resueltos, y puedo dedicar mi tiempo a lo que hace que la app valga la pena instalar. Si mantienes más de unas pocas apps, mi consejo es elegir las dos o tres cosas que repites una y otra vez, dar a cada una una implementación de referencia y sacar del binario todo lo que pueda ser un dato.

Preguntas frecuentes

¿Cuántas apps abarca este enfoque?

Unas dos docenas de apps y juegos, entre juegos de puzles y pequeñas utilidades cotidianas. Los patrones importan sobre todo en las más recientes.

¿Por qué no usar una biblioteca compartida en lugar de copiar archivos?

Las apps independientes se publican en calendarios distintos. Un módulo compartido obligaría a lanzamientos coordinados, mientras que un archivo pequeño, copiado y probado mantiene cada app independiente.

¿Cómo se mantiene segura la lista remota de Otros juegos?

La app la descarga solo de un servidor esperado, la guarda 48 horas en caché, valida cada campo, limita su tamaño y recurre a una copia incluida si algo falla.

¿Cuándo debe una app pedir al usuario que actualice?

El flujo flexible de actualización dentro de la app funciona bien si pregunta solo cuando la versión lleva un día publicada, no más de una vez cada pocos días y en un momento tranquilo, como cuando la app vuelve a primer plano.

¿Editas a mano el sitio web generado?

Nunca. Las correcciones van al generador o al archivo de datos, y todo el sitio se reconstruye con un solo comando.

Más del blog