wandres.dev
GOOGLE PLAY · publicar y actualizar

Publicar: el bundle, la ficha, el manifiesto de datos y la revisión

El acto de publicar descompuesto en sus cuatro piezas: el artefacto que subes y los metadatos que lo acompañan, la ficha de tienda como superficie de conversión y de búsqueda, el formulario de seguridad de los datos y su relación con la política de privacidad, y qué mira exactamente la revisión de Google antes de dejar salir una versión.

⏱ 19 min

Publicar no es subir un archivo. Un lanzamiento es la conjunción de cuatro objetos independientes que la tienda valida por separado y que fallan por separado: el artefacto de código, los metadatos de la versión, la ficha visible para el usuario y las declaraciones legales sobre lo que tu app hace con los datos. Cada uno tiene su propio ciclo de revisión, su propia latencia y su propia forma de bloquear un lanzamiento. La mayoría de los retrasos que un equipo atribuye a una revisión lenta son en realidad una declaración incoherente, un metadato inconsistente o un activo que incumple una norma de formato. Separar mentalmente esas cuatro piezas es lo que convierte publicar en un proceso reproducible en lugar de una lotería.

🎯 Al terminar esta lección sabrás
  • Distinguir las cuatro piezas de un lanzamiento y qué valida la tienda en cada una.
  • Entender el papel del código de versión y por qué es irreversible.
  • Rellenar el formulario de seguridad de los datos de forma coherente con el código real.
  • Anticipar qué mira la revisión y qué la alarga de días a semanas.

El artefacto y sus metadatos

Lo que subes es un AAB, y con él viajan tres datos que la tienda trata como inmutables. El identificador de aplicación define la app para siempre: no se puede cambiar, no se puede reutilizar tras una eliminación y determina la ruta de actualización de todos los instalados. El código de versión es un entero que debe crecer estrictamente en cada subida; la tienda rechaza uno repetido o menor, y una vez consumido queda quemado aunque descartes la versión. El nombre de versión es texto libre que solo ven las personas.

// build.gradle.kts del modulo de aplicacion
android {
    defaultConfig {
        applicationId = "com.ejemplo.miapp"   // inmutable de por vida
        versionCode = 412                     // entero estrictamente creciente
        versionName = "3.8.0"                 // cadena para humanos
        targetSdk = 36
        minSdk = 26
    }
    bundle {
        language { enableSplit = true }
        density  { enableSplit = true }
        abi      { enableSplit = true }
    }
}

El identificador merece un momento de reflexión antes de teclearlo, porque es la decisión más permanente de todo el proyecto. Elegir uno que contenga el nombre de un producto que puede cambiar de marca, o el de una empresa que puede ser adquirida, deja una etiqueta visible en la URL de la ficha y en la lista de apps del sistema durante toda la vida del producto. Y como no se puede reutilizar tras una eliminación, quemarlo en un experimento publicado significa perderlo para siempre.

Junto al artefacto conviene subir siempre el mapa de desofuscación que produce el minificador. Sin él, los informes de fallos llegan con nombres de clase de una sola letra y el diagnóstico se vuelve arqueología. La tienda lo asocia al código de versión concreto, así que subirlo tarde no repara los informes ya recibidos.

# Construir el artefacto de publicacion y localizar el mapa
./gradlew :app:bundleRelease
ls app/build/outputs/bundle/release/app-release.aab
ls app/build/outputs/mapping/release/mapping.txt

# Verificar en local que los paquetes generados son los esperados
bundletool build-apks --bundle=app-release.aab --output=salida.apks
bundletool get-size total --apks=salida.apks

Los tres interruptores de división del bloque bundle merecen una decisión consciente y no un valor por defecto heredado. Desactivar la división por idioma, por ejemplo, es lo correcto en apps que permiten cambiar el idioma desde dentro sin depender del ajuste del sistema, porque de lo contrario el usuario selecciona una lengua cuyas cadenas no están instaladas y ve identificadores crudos. Es un fallo que no aparece en ninguna prueba local, porque en desarrollo siempre está todo presente.

El error más caro con el código de versión aparece cuando el proyecto tiene varias variantes que se publican por separado, por ejemplo una compilación con librerías nativas para una arquitectura y otra distinta. Ahí los códigos deben estar escalonados con un esquema que garantice el orden correcto entre variantes, porque el sistema actualizará al paquete de código mayor que el dispositivo pueda instalar, y un escalonado mal diseñado degrada a un usuario a una variante peor sin que nadie lo note.

La ficha: conversión y descubrimiento a la vez

La ficha de tienda hace dos trabajos que compiten entre sí. Es la página de conversión que decide si alguien que ya llegó instala, y es el corpus de texto sobre el que opera el buscador de la tienda. Escribir solo para lo primero produce fichas invisibles; escribir solo para lo segundo produce fichas ilegibles que ahuyentan.

🏷️

Título y descripción breve

Es lo único que se ve en resultados de búsqueda. El título pesa muchísimo en el algoritmo y la descripción breve es el argumento de conversión más leído de toda la ficha.

🖼️

Capturas y vídeo

Se consumen antes que cualquier texto. Las primeras dos capturas determinan la mayor parte de la decisión, y hacen falta juegos distintos por formato de pantalla.

🌍

Traducciones

Cada idioma es una ficha independiente con su propio texto y sus propios activos. Traducir solo el texto y dejar capturas en otro idioma es el desperdicio más común.

🧪

Fichas personalizadas

Variantes de ficha para públicos concretos o para campañas, con sus propios activos, y experimentos que comparan variantes midiendo instalaciones reales.

La tensión entre conversión y descubrimiento se resuelve entendiendo que operan sobre campos distintos. El título y la descripción breve son terreno de conversión y de posicionamiento a la vez, y ahí la restricción de caracteres obliga a elegir; la descripción larga es sobre todo terreno de indexación y casi nadie la lee entera, así que puede cargar el vocabulario que el título no admite. Repetir palabras clave a la fuerza, en cambio, es una práctica explícitamente sancionada que degrada el posicionamiento en lugar de mejorarlo.

Los activos gráficos se rechazan por motivos formales con una frecuencia que sorprende: capturas con marcos de dispositivo simulados que inducen a error, iconos con elementos que imitan insignias del sistema, texto promocional dentro del icono, o capturas que muestran una interfaz que la app no tiene. La regla implícita es que los activos deben representar la app real, y todo lo que se aleje de esa representación es material de rechazo.

💡
La clasificación por contenido y el público objetivo condicionan mucho más de lo que parece

Declarar que tu app está dirigida a menores activa un conjunto de políticas mucho más estricto: restricciones de publicidad, obligación de usar servicios de anuncios certificados, límites al uso de identificadores y requisitos adicionales de consentimiento. Declararlo por error, o marcar un público mixto sin las salvaguardas correspondientes, es una de las causas de suspensión más difíciles de revertir. Estas declaraciones se rellenan en cuestionarios que parecen burocracia y son en realidad la puerta de entrada a regímenes normativos distintos.

El manifiesto de datos y la política de privacidad

El formulario de seguridad de los datos declara qué información recoge tu app, con qué finalidad, si la comparte con terceros, si el usuario puede pedir su eliminación y qué medidas de protección aplicas. Se muestra al usuario como una sección visible de la ficha, y ahí está la clave: es una declaración pública, no un trámite interno.

flowchart TD
COD[Codigo de la app y sus SDK] --> INV[Inventario real de datos recogidos]
INV --> FORM[Formulario de seguridad de los datos]
INV --> POL[Politica de privacidad publicada]
FORM --> FICHA[Seccion visible en la ficha]
POL --> FICHA
FORM --> REV[Revision comprueba coherencia]
REV --> OK[Version aprobada]
REV --> NO[Rechazo por declaracion incoherente]

El inventario, para ser mantenible, tiene que vivir en el repositorio junto al código que lo genera, no en la memoria de quien rellenó el formulario la última vez.

Tipo de dato        Origen                      Recogido  Compartido  Finalidad
Correo electronico  registro propio             si        no          cuenta
Identificador       SDK de analitica            si        si          analitica
Ubicacion aprox     SDK de publicidad           si        si          publicidad
Fotos               seleccionadas por el usuario si       no          funcionalidad
Diagnostico         SDK de informes de fallo    si        si          diagnostico

La incoherencia más frecuente no viene de tu código sino de las librerías que integras. Un SDK de analítica, uno de publicidad o uno de mapas recogen datos por su cuenta, y esa recogida es tuya a efectos de declaración. El inventario honesto exige revisar qué recoge cada dependencia, no solo qué llamadas escribiste tú. Las librerías serias publican una ficha con los tipos de datos que tratan precisamente para que puedas trasladarla al formulario.

Hay una distinción del formulario que se rellena mal con frecuencia. Recoger significa que los datos salen del dispositivo hacia un servidor, tuyo o de un tercero; procesarlos únicamente en el dispositivo y no transmitirlos no cuenta como recogida. Compartir significa transferirlos a otra empresa, y ahí entra el caso incómodo: enviar datos a un proveedor de analítica que los usa para sus propios fines es compartir, aunque tú lo percibas como infraestructura. Marcar recogida donde no la hay asusta al usuario sin motivo; no marcar compartición donde la hay es una declaración falsa.

La política de privacidad es obligatoria, debe estar en una URL pública accesible sin autenticación y debe ser coherente con el formulario. Si el formulario dice que recoges ubicación aproximada y la política no la menciona, es motivo de rechazo. Si la política menciona prácticas que el formulario no declara, también.

Hay dos obligaciones asociadas que se olvidan con facilidad. La primera es ofrecer una vía de eliminación de cuenta y datos accesible tanto dentro de la app como desde una URL externa, para quien ya la desinstaló. La segunda es declarar el cifrado en tránsito y las prácticas de retención de forma que se sostengan si alguien las verifica, porque la revisión sí prueba apps y sí observa tráfico.

Qué hace la revisión y qué la alarga

La revisión combina análisis automático y humano. El análisis automático inspecciona el paquete: permisos declarados, SDK incluidos con vulnerabilidades conocidas, uso de APIs restringidas, comportamiento en instalación y arranque, coherencia entre lo declarado y lo detectado. La revisión humana entra cuando algo se marca, cuando la app cae en una categoría sensible, o cuando es la primera publicación de una cuenta nueva.

Primera publicacion de cuenta nueva      dias, a veces mas de una semana
Actualizacion rutinaria de app establecida  horas o pocos dias
App en categoria sensible                 revision humana casi garantizada
Cambio de permisos delicados              revision adicional con formulario
Respuesta a un rechazo                    reinicia el ciclo desde cero

Un detalle de proceso que ahorra muchos días: la revisión se ejecuta sobre la versión completa, así que corregir un rechazo no es una enmienda parcial sino un ciclo nuevo entero. Por eso conviene agrupar en una sola subida todos los cambios que sospechas que pueden generar fricción, en lugar de ir descubriendo objeciones de una en una a lo largo de varias semanas. Y conviene aportar de antemano el contexto que un revisor necesitaría: credenciales de prueba permanentes, instrucciones para llegar a la pantalla que justifica un permiso delicado, y una nota explicando cualquier cambio brusco respecto a la versión anterior.

Lo que alarga una revisión es casi siempre lo mismo: pedir permisos que la funcionalidad visible no justifica, declarar un uso de datos que no coincide con lo observado, incluir funcionalidad accesible solo tras iniciar sesión sin dar credenciales de prueba, o cambiar de categoría y público objetivo entre versiones. Ese cuarto punto es sutil y frecuente: la revisión compara versiones, y un salto brusco en lo declarado dispara escrutinio incluso si la versión nueva es impecable.

Publicar es firmar un contrato público sobre el comportamiento de tu código

La tentación al empezar es tratar la ficha, el formulario de datos y las declaraciones de público como papeleo que rodea a lo importante, que sería el binario. Es exactamente al revés, y el motivo es estructural: la tienda no puede auditar tu código fuente, así que ha construido todo su modelo de gobierno sobre declaraciones verificables por contraste. Tú declaras qué datos recoges, y la revisión observa tu tráfico y tus permisos para ver si encaja. Tú declaras un público objetivo, y el sistema comprueba si tus anuncios y tus identificadores son coherentes con él. Tú declaras una funcionalidad en la ficha, y un revisor abre la app para ver si existe. Cada declaración es una afirmación falsable, y el mecanismo entero funciona porque mentir es detectable y castigado con una asimetría enorme: aprobar tarda días, suspender es inmediato y apelar tarda semanas. Interiorizar esto cambia cómo trabaja un equipo. El inventario de datos deja de ser algo que se rellena la tarde antes de publicar y pasa a ser un artefacto que se actualiza cada vez que se añade una dependencia, porque una librería nueva puede convertir en falsa una declaración que llevaba dos años siendo verdadera. La ficha deja de ser marketing y pasa a ser parte de la especificación del producto, porque promete comportamiento. Y la revisión deja de parecer un obstáculo arbitrario y se revela como lo que es: el único punto del sistema donde alguien comprueba que lo que dijiste y lo que hiciste son la misma cosa. Los equipos que publican sin sobresaltos no son los que tienen suerte con los revisores, son los que mantienen esas dos cosas alineadas de forma continua.

⚔️ Reconstruye tu lanzamiento pieza a pieza
  1. Enumera todas las dependencias de tu app que envían datos a un servidor de terceros y clasifica qué tipos recogen.
  2. Contrasta ese inventario con lo que declara hoy tu formulario de seguridad de los datos y anota cada divergencia.
  3. Comprueba que tu política de privacidad menciona explícitamente cada tipo declarado y que la URL responde sin iniciar sesión.
  4. Verifica que existe una vía de eliminación de datos dentro de la app y otra accesible desde fuera de ella.
  5. Diseña el esquema de códigos de versión que usarías si mañana tuvieras que publicar dos variantes por arquitectura, y demuestra que ningún dispositivo puede degradarse.