De Android 2017 a Android 2025: Cómo migrar un proyecto (y no morir en el intento)

El escenario: un proyecto que nadie quería tocar

Hace unos días, me enfrenté a algo que muchos desarrolladores temen: un proyecto Android de 2017.

Sí, 2017.

Parte de un sistema universitario multi-módulo (PencaUy) desarrollado para un laboratorio de la facultad. Un proyecto nacido para gestionar pencas deportivas, con un componente mobile que se integraba con el módulo local.

Este sistema cuenta de tres partes principales:

  • Módulo Central: Ejecutándose en la Nube.

  • Módulo Local: Instalado on premise en distintas organizaciones, compuesto por un backoffice y un frontoffice para administración. Cada instancia local se ejecuta sobre WildFly 14 (ya migrado a WildFly 23) y utiliza una base de datos PostgreSQL.

  • Módulo Mobile: La aplicación Android que estuve migrando, permitiendo a los usuarios participar en las pencas.

Era un proyecto escrito en Java, con compileSdkVersion 27, minSdkVersion 16, dependencias de android.support.*, Gradle 4.4… y un AndroidManifest.xml que parecía un relicario de la era pre-AndroidX :)
Nadie lo había tocado desde su creación. El código dormía tranquilo, esperando a que alguien lo despertara. Y ese alguien fui yo… con la misión de hacerlo funcionar en Android 14, preparándolo para integrarse con APIs modernas de partidos y torneos...


El objetivo: hacerlo funcionar en 2025

No quería reescribirlo.
No quería empezar desde cero (aunque lo pensé).
Quería migrar.
Con todos sus bugs, sus APIs REST, sus AsyncTask, sus ListView… y su alma de Java 8 que en parte se mantiene en la lógica del código, por ahora.

Mi objetivo era claro: actualizar la infraestructura del proyecto para que pudiera compilar y ejecutarse en entornos modernos (Android Studio Flamingo, Gradle 8.x, Android 14), manteniendo la funcionalidad original intacta y preparándolo para futuras integraciones con APIs.


La migración: 10 horas de caos, 2 días de paciencia, 1 victoria

Aquí te cuento cómo lo logré!

Paso 1: El primer error fue el más común — Cannot resolve symbol 'R'

Todo empezó con esto.
Nada compilaba.
R no existía.
Las clases android.support.* no se encontraban.

Solución:

  • Actualicé Gradle a 8.7

  • Cambié build.gradle para usar namespace 'penca.pencauy'

  • Eliminé el package del AndroidManifest.xml

  • Agregué android.useAndroidX=true y android.enableJetifier=true en gradle.properties

Pero… seguía sin funcionar.

“¿Por qué no genera R.java?”


Paso 2: El enemigo invisible — Java 11 vs Java 17

El error más silencioso, el que me hizo perder 8 horas:

Android Gradle plugin requires Java 17 to run. You are currently using Java 11.

Mi sistema linux tenía instalado Java 8 (configurado para desarrollos específicos en Eclipse) y Java 11 (por defecto del S.O).

AGP 8.x requiere Java 17 para compilar el proyecto.
Y Android Studio… no lo sabía, o al menos Gradle no lo estaba usando.

Es importante aclarar: el código Java del proyecto sigue siendo compatible con Java 8 (y eso no lo cambié).
Lo que necesitaba actualizar era la versión de Java usada por el proceso de compilación de Gradle.
Gradle 8.7 y AGP 8.x+ necesitan Java 17 o superior para funcionar.

Solución:

  • Instalé OpenJDK 17:

sudo apt install openjdk-17-jdk

Agregué en gradle.properties

org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64

Y ¡sí! Funcionó.
Gradle pudo ejecutarse correctamente, y el proceso de generación de recursos (y por ende R.java) pudo iniciar.

Lección clave: La versión de Java en la que escribes tu código (Source & Target Compatibility en Project Structure) puede ser diferente a la versión de Java que usa Gradle para compilar.
Para usar AGP moderno, asegúrate de que Gradle use Java 17+.


Paso 3: El “constant expression required” — el más frustrante

En MainActivityDrawer.java, esta línea:

case R.id.nav_pencas:

…me decía:

“No puedo usar esto como constante. ¿Qué demonios?”

nopuedousarestocomoconstante.png¿Por qué? Porque el archivo R.java no contenía los IDs nav_pencas, nav_ranking, etc. como constantes válidas para un switch.

¿Por qué no los tenía? Parecía haber un error silencioso en el procesamiento de recursos, o una generación incorrecta de R.java, que impedía que los IDs del archivo activity_main_drawer_drawer.xml fueran reconocidos como constantes en tiempo de compilación. A pesar de intentar múltiples veces limpiar, reconstruir, eliminar la carpeta build, reiniciar Android Studio, y hasta usar el AGP Upgrade Assistant, el error persistió como un misterio.

Solución temporal:

Dado que el objetivo inmediato era ver la aplicación corriendo, comenté las líneas del switch en el método onNavigationItemSelected

Con esto, el proyecto compiló y la aplicación se ejecutó en el emulador. El botón de "Entrar" funcionó, el login se conectó a la API REST... ¡La base estaba lista!

Lección clave (parcial): A veces, para avanzar, hay que dar un paso atrás. Si algo no funciona, aíslo temporalmente y resuelve lo demás. El problema del R.id.nav_... queda pendiente para resolverlo con una estrategia más profunda o incluso reconsiderando la estructura del menú.


Paso 4: Migrar todo el código — de android.support.* a androidx.*

Cada clase Java tenía import android.support.v7.app.AppCompatActivity;
Cada layout tenía android.support.design.widget.TextInputLayout

Solución:

  • Reemplacé manualmente cada import y cada tag XML.

  • Usé el AGP Upgrade Assistant (Tools → AGP Upgrade Assistant) para actualizar de AGP 8.5.2 → 8.13.1.

  • Esto actualizó automáticamente las dependencias y me ayudó a evitar errores de compatibilidad con Gradle 8.7.

Lo más valioso: el asistente no arregló todo, pero me guió.
Me mostró qué cambiar, por qué, y qué versiones eran compatibles.


¿Funcionó? Sí. Y esto es lo que logré
pencaUY.png

Al final del camino, tengo un proyecto nacido en 2017 corriendo en 2025, completamente actualizado en su infraestructura:

  • compileSdkVersion 27compileSdk 34

  • targetSdkVersion 27targetSdk 34

  • android.support.*androidx.*

  • Gradle 4.48.7

  • AGP 3.x8.13.1

  • El antiguo package en AndroidManifest.xmlnamespace en build.gradle

  • Y el proceso de compilación ahora corre sobre Java 17, aunque el código sigue en Java 8 (¡sí, se puede!).

Lo más importante:
El emulador funciona con KVM.
El login se conecta a la API REST.
La aplicación se ejecuta correctamente en Android 14.
El proyecto compila (aunque con el switch de navegación temporalmente comentado).
Y, sobre todo, está listo para integrarse con las APIs del módulo local de Penca, tal como fue diseñado originalmente por el laboratorio.


Lecciones aprendidas (para ti, que estás en el mismo barco)

  • No necesitas reescribir un proyecto viejo para hacerlo moderno.
    Puedes migrarlo. Solo se necesita paciencia, método… y saber que el cache a veces miente.

  • Java 8 + AndroidX + Java 17 es posible.
    Tu lógica puede vivir en Java 8, mientras Gradle usa Java 17 para compilar. Son mundos distintos que conviven.

  • ¿El R.java no aparece?
    No es tu código. Es el estado interno de Android Studio.
    → Borra app/build/
    → Cierra el IDE
    → Abre de nuevo
    → Rebuild
    (Sí, a veces es así de simple… y frustrante).

  • El AGP Upgrade Assistant no es un “botón mágico”.
    Es un guía inteligente. Úsalo como un aliado, no como una solución automática.

  • Android Studio y Gradle evolucionan rápido.
    Lo que funcionaba en 2017 hoy es obsoleto…
    Pero no imposible. Solo requiere entender los cambios, uno a uno.


¿Qué sigue?

Ahora que el proyecto levanta y se puede ver en el emulador, el siguiente paso es reintegrar la navegación del Drawer (resolviendo el misterio del R.id.nav_...) y empezar a consumir las APIs del módulo local para gestionar pencas, participantes, partidos, y tablas de posiciones.


¡Salud y buen blogging!
— Valerka (Montevideo, Uruguay)
¿Te gustó el post? ¿Tenés dudas, comentarios o querés compartir tu experiencia?
Escribime a: valerkasystem@protonmail.com — ¡Siempre leo los mails y trato de responder cuando puedo!