Saltar al contenido

Guías de configuración · Flutter

Prueba cerrada de Google Play para apps de Flutter

De flutter build appbundle a Solicitar acceso a producción: compilar y firmar un bundle de release, configurar el canal cerrado, mantener a 12 testers con opt-in durante 14 días y evitar los errores de Flutter que cuestan una semana.

Compilación
flutter build appbundle
Código de versión
pubspec.yaml → version: 1.0.0+1
API objetivo
targetSdk ≥ 36

Compila un app bundle de release

Google Play solo acepta Android App Bundles (.aab) para apps nuevas. Flutter compila uno con un único comando y el modo release es el predeterminado. Antes, revisa dos cosas: ambas son difíciles de arreglar cuando los testers ya tienen la app.

  1. Define el ID de aplicación

    En android/app/build.gradle.kts, da a applicationId un valor único con dominio invertido, como com.yourcompany.app. No se puede cambiar después de la primera subida a Google Play.

  2. Revisa el permiso INTERNET

    Si la app usa la red, android/app/src/main/AndroidManifest.xml debe declarar android.permission.INTERNET. Los manifiestos de debug y profile lo incluyen; el de release, solo si lo añades tú.

  3. Compila el bundle

    Ejecuta el comando de abajo en la raíz del proyecto. Flutter guarda el bundle en build/app/outputs/bundle/release/.

Terminal
flutter build appbundle

¿Usas flavors? Compila el que vas a publicar, por ejemplo flutter build appbundle --flavor production, y comprueba que usa el nombre de paquete y las claves de API de producción.

Fírmalo: clave de subida y firma de aplicaciones de Play

La firma de aplicaciones de Play es obligatoria para apps nuevas: Google guarda la clave de firma de la app y tú firmas cada subida con tu propia clave de subida. Si alguna vez la pierdes, puedes pedir a Google que la restablezca; tu app no se pierde con ella. Crea la clave con keytool:

Terminal (macOS / Linux)
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
        -storetype JKS -keysize 2048 -validity 10000 -alias upload

Después crea android/key.properties con las contraseñas y la ruta del keystore. Ni este archivo ni el .jks deben entrar en el control de versiones:

android/key.properties
storePassword=<keystore password>
keyPassword=<key password>
keyAlias=upload
storeFile=/Users/<you>/upload-keystore.jks

Carga el archivo en android/app/build.gradle.kts y haz que el tipo de build release use la nueva configuración de firma:

android/app/build.gradle.kts
import java.util.Properties
import java.io.FileInputStream

val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

android {
    // ...
    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties.getProperty("keyAlias")
            keyPassword = keystoreProperties.getProperty("keyPassword")
            storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) }
            storePassword = keystoreProperties.getProperty("storePassword")
        }
    }
    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
        }
    }
}

Los proyectos antiguos usan build.gradle (Groovy) en lugar de build.gradle.kts; los campos son los mismos. Ejecuta flutter clean después de cambiar archivos de Gradle.

Código de versión y nivel de API objetivo

Cada subida necesita un código de versión mayor que el de cualquier bundle que hayas subido antes, en cualquier canal. En Flutter es el número que va después del + en pubspec.yaml:

pubspec.yaml
version: 1.0.0+1

1.0.0 es el nombre de versión que ven los usuarios y 1 es el código de versión. Súbelo a +2, +3, etc., o sobrescribe ambos al compilar con --build-name y --build-number.

Desde el 31 de agosto de 2026, las apps nuevas y las actualizaciones deben apuntar a Android 16 (nivel de API 36) o superior. El archivo de Gradle usa targetSdk = flutter.targetSdkVersion, así que actualizar Flutter es la forma habitual de subirlo. Si tu versión de Flutter es antigua, pon targetSdk = 36 tú mismo y prueba en una versión reciente de Android antes de subir.

Trampas de Flutter que retrasan la prueba cerrada

  • Número de build repetido. Play Console rechaza un bundle cuyo código de versión ya se usó. Sube el +N de pubspec.yaml antes de cada build que pienses subir.
  • Ofuscación sin símbolos. --obfuscate solo funciona junto con --split-debug-info. Guarda la carpeta de símbolos de cada build que subas; sin ella no podrás leer los fallos que reporten los testers.
  • Flavor equivocado. Con flavors es fácil subir el build de staging con los endpoints de staging. Los testers reportan entonces errores que los usuarios de producción nunca verían.
  • Sin red en release. Si falta el permiso INTERNET en el manifiesto principal, la app funciona en debug y falla en silencio a los testers.
  • Bundle firmado en debug. Si el tipo de build release sigue usando la firma de debug, Play Console rechaza la subida.
  • Plugins con código nativo antiguo. Los plugins que incluyen bibliotecas .so deben admitir páginas de memoria de 16 KB. Play Console avisa de ello y, a partir del 1 de febrero de 2027, no se podrán publicar actualizaciones sin esa compatibilidad. Actualiza plugins y el SDK de Flutter antes de la prueba, no a mitad.
Terminal
flutter build appbundle --obfuscate --split-debug-info=build/symbols

Lee los informes de fallos de tus testers

Los testers pegan stack traces en sus informes de errores, y Play Console reúne los fallos en Supervisar y mejorar → Android vitals → Fallos y ANR. Un stack trace de Flutter tiene dos mitades: la parte de Dart, que --obfuscate convierte en nombres cortos y sin sentido, y la parte de Android, que R8 reduce. Flutter activa siempre la reducción de código en los builds de release, así que prepárate para ambas.

  1. Guarda los símbolos de Dart

    Un build hecho con --split-debug-info escribe un archivo de símbolos por arquitectura, como app.android-arm64.symbols. Guarda la carpeta junto al código de versión al que pertenece: el archivo de otro build no puede descifrar el stack trace.

  2. Descifra los stack traces de Dart

    Guarda el stack trace en un archivo y pásalo a flutter symbolize junto con el archivo de símbolos de la arquitectura del dispositivo. La mayoría de los teléfonos actuales son arm64.

  3. Deja la parte Java a Play Console

    Con el plugin de Android para Gradle 4.1 o posterior, el archivo de mapeo de R8 viaja dentro del .aab, así que Play Console desofusca las líneas Java y Kotlin de los plugins sin subir nada aparte.

Terminal
flutter symbolize -i crash.txt -d build/symbols/app.android-arm64.symbols

La ofuscación solo renombra símbolos; no cifra nada y no es un lugar para secretos. El código que compara runtimeType.toString() con un nombre de clase se rompe al ofuscar, mientras que los nombres de los enum siguen siendo legibles.

Play Console en breve: de la prueba cerrada a producción

En cuanto tu bundle de Flutter esté compilado y firmado, el resto ocurre en Play Console y funciona igual con cualquier framework. Esta es la lista de comprobación; cada menú y cada pantalla están en la guía completa de Play Console.

  • Termina la configuración de la app en el Panel: política de privacidad, acceso a la app, anuncios, clasificación de contenido, público objetivo, seguridad de los datos y ficha de Play Store.
  • Crea una versión de prueba cerrada en Probar y publicar → Pruebas → Prueba cerrada: elige los países de tus testers, sube el .aab y envíalo a revisión.
  • Añade testers con un Google Group en la pestaña Testers y comparte el enlace de opt-in. Funciona en cuanto el canal muestra Publicado.
  • Mantén al menos 12 testers con opt-in durante 14 días seguidos. Las pruebas internas no cuentan, y quien sale y vuelve empieza sus 14 días de nuevo.
  • Publica al menos una actualización durante la prueba y apunta qué encontraron los testers y qué cambiaste.
  • Solicita acceso a producción desde el Panel y responde las tres secciones sobre tu prueba, tu app y tu preparación. La decisión es de Google; nadie puede garantizar la aprobación.

Cuenta con bajas: recluta más de 12 testers para que una baja no retrase tu calendario. Ver todos los pasos de Play Console.

La guía completa de Play Console

Canal cerrado, Google Group y enlace de opt-in, la regla de 12 testers / 14 días y la solicitud de producción, paso a paso en una sola página.

Abrir los pasos de Play Console

Envía correcciones a los testers durante la prueba

En Flutter: sube el número de build, vuelve a compilar y sube el nuevo bundle al mismo canal cerrado.

Terminal
flutter build appbundle --build-name=1.0.1 --build-number=2

Antes de cada subida, ejecuta el build de release en un teléfono real. flutter install instala el APK de release en un dispositivo conectado y detecta en minutos permisos que faltan, flavors equivocados y fallos que solo ocurren en release:

Terminal
flutter build apk
flutter install

Para probar el bundle exacto que vas a subir, conviértelo en APK de dispositivo con bundletool de Google, o súbelo al canal cerrado e instálalo desde Google Play con una cuenta de tester. Así pruebas lo que reciben los testers, incluidos los APK divididos por dispositivo de Play.

  • Un cambio concreto por actualización. Las versiones pequeñas dejan claro qué corrección respondió a qué informe de un tester y te dan ejemplos concretos para el formulario de acceso a producción.
  • No cambies de versión de Flutter a mitad de la prueba, salvo que un error informado por los testers lo exija. Una actualización del SDK cambia a la vez el motor, el código nativo de cada plugin y quizá targetSdk.
  • Deja tiempo para la revisión. Cada nueva versión del canal cerrado se envía a Google antes de llegar a los testers, así que no dejes tu última corrección para el último día.

Preguntas frecuentes

¿Necesito --obfuscate para una prueba cerrada?

No. La ofuscación es opcional y solo hace que los símbolos de Dart sean más difíciles de leer. Si la usas, combínala siempre con --split-debug-info y archiva los símbolos, o los fallos que te envíen los testers serán ilegibles.

¿Qué código de versión ve Google Play?

El número después del + en pubspec.yaml, o el valor de --build-number si lo pasas. Flutter usa el nombre de build como versionName y el número de build como versionCode.

¿Puedo dar un APK a los testers?

No a través de Google Play: las apps nuevas deben subirse como .aab, y solo las instalaciones desde el canal cerrado cuentan para los 12 testers. Aun así, flutter build apk --split-per-abi es útil para pruebas rápidas en tus propios teléfonos.

¿Por qué Play Console avisa sobre las páginas de memoria de 16 KB?

Normalmente un plugin incluye bibliotecas nativas .so que no están alineadas para páginas de 16 KB. Actualiza el plugin y Flutter, vuelve a compilar y compruébalo en un emulador de Android con una imagen de sistema de páginas de 16 KB antes de la próxima subida.

Fuentes

Los detalles técnicos se han comprobado con la documentación oficial de abajo. Los menús y los valores por defecto cambian entre versiones; ante la duda, manda la página oficial.

¿Es tu primera vez con la regla de los 12 testers?

La guía general explica el requisito de Google, cómo avanza día a día una campaña de TestBunny y qué podemos y qué no podemos garantizar.

Leer la guía general

¿Necesitas 12 testers reales durante 14 días?

Añade tu app y tu enlace de prueba cerrada, elige Starter (15 testers) o Pro (25 testers) y sigue la actividad de cada tester día a día en tu panel.

TestBunny no está afiliado a Google. Los testers ganan créditos, nunca dinero. Nadie puede garantizar la decisión de Google sobre el acceso a producción, y nosotros tampoco.