App Store y Google Play: Guía Completa de Publicación para Desarrolladores
Todo lo que necesitas para publicar apps en Google Play y App Store: firma, tracks, reglas de revisión, ASO, CI/CD con fastlane, rollouts escalonados e incidentes en producción.
Publicar una app móvil no es lo mismo que desplegar un servicio web. Cuando haces push a un servidor, el cambio está en vivo en segundos. Cuando envías a Google Play o la App Store, entras a un sistema con sus propias reglas, sus propios tiempos, sus propios criterios de rechazo y su propia audiencia — la tienda misma, que decide si tu app llega a los usuarios.
La mayoría de los desarrolladores aprende esto de la manera difícil: un binario que funciona perfectamente en cada dispositivo de la oficina es rechazado por una declaración de privacidad faltante, o se publica con la configuración de firma incorrecta, o pasa la revisión pero llega a los usuarios con una tasa de crashes que activa una detención automática. El proceso de publicación no es solo empaquetado — es una serie de decisiones que afectan la visibilidad, las garantías de estabilidad, el cumplimiento legal y la velocidad de lanzamiento.
Esta guía cubre ambas tiendas de extremo a extremo — cuentas, firma, tracks de lanzamiento, listados en tienda, reglas de revisión, automatización y qué hacer cuando algo sale mal después de que el lanzamiento ya está en vivo.
Antes de Enviar: La Capa de Negocio
Tanto Google como Apple requieren una cuenta de desarrollador registrada antes de poder enviar cualquier cosa. No son cuentas técnicas — son acuerdos comerciales con tarifas anuales y obligaciones legales.
Google Play Console — tarifa de registro única de $25 por cuenta de desarrollador. La cuenta puede publicar aplicaciones ilimitadas. Aceptas el Acuerdo de Distribución de Desarrolladores, que incluye políticas de contenido, requisitos de privacidad y restricciones de uso de API. El registro requiere una cuenta de Google, método de pago y verificación de identidad personal o empresarial.
Apple Developer Program — $99 al año por cuenta (individual u organización). Las cuentas de organización requieren un número D-U-N-S de Dun & Bradstreet, que tarda 5–14 días hábiles en obtenerse. Este es un requisito de entidad legal real — Apple verifica que tu organización existe. Planea este tiempo de anticipación antes de tu primera publicación.
Ambas cuentas pueden tener múltiples miembros del equipo con permisos basados en roles. Configura esto desde el primer día: tener a una sola persona como único titular de la cuenta crea un punto único de falla para todo tu pipeline de lanzamiento.
Google Play: De Principio a Fin
Firma de la App
Las apps de Android deben firmarse con una clave privada antes de poder instalarse. Google Play usa Play App Signing — Google guarda la clave de firma de la app, y tú subes tu app firmada con una clave de carga. Esta separación es importante: si tu clave de carga alguna vez se ve comprometida, puedes rotarla sin perder la app.
Genera un keystore de carga con keytool:
keytool -genkey -v \
-keystore upload-keystore.jks \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-alias upload
Guarda el archivo keystore y las contraseñas en algún lugar seguro — un gestor de contraseñas o un vault de secretos, no el repositorio. Si pierdes el keystore antes de inscribirte en Play App Signing, no puedes actualizar tu app. Nunca.
En android/app/build.gradle, configura la firma:
android {
signingConfigs {
release {
storeFile file(System.getenv("KEYSTORE_PATH") ?: "../upload-keystore.jks")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
Nunca pongas credenciales hardcodeadas en build.gradle. Usa variables de entorno, que los sistemas de CI/CD pueden inyectar de forma segura.
AAB vs APK
Google Play requiere el formato Android App Bundle (AAB) para nuevas apps. APK es solo para distribución directa fuera de la tienda.
# Flutter
flutter build appbundle --release
# React Native
cd android && ./gradlew bundleRelease
# Android nativo (Gradle)
./gradlew bundleRelease
El AAB permite que Google genere APKs optimizados por configuración de dispositivo — descargas más pequeñas, instalaciones más rápidas. El archivo de salida típicamente está en build/app/outputs/bundle/release/app-release.aab.
Tracks de Lanzamiento
Google Play tiene cuatro tracks. Úsalos en orden — no saltes directamente a producción.
Pruebas internas — hasta 100 testers, invitados por correo. No requiere revisión. Disponible en minutos después de la carga. Usa este para cada build durante el desarrollo. Configúralo como la salida predeterminada de tu CI.
Pruebas cerradas (Alpha) — grupos de testers más grandes, aún por invitación. Sin revisión para la mayoría de las apps. Usa este para la aprobación de QA.
Pruebas abiertas (Beta) — cualquier usuario puede unirse. Las apps aquí pasan por una revisión automatizada básica. Usa este para retroalimentación beta externa y validación final pre-producción.
Producción — revisión completa. Disponible para todos los usuarios. Controlas el porcentaje de lanzamiento.
Un flujo de lanzamiento realista:
Feature completa → Build interno → QA en track Interno
→ QA aprueba → Promover a track Cerrado
→ Retroalimentación beta externa → Promover a track Abierto (opcional)
→ Aprobación final → Enviar a Producción (10% rollout)
→ Monitorear crash rate por 48h → Expandir a 100%
Versionado
En build.gradle (o pubspec.yaml para Flutter):
android {
defaultConfig {
versionCode 42 // entero, debe aumentar con cada carga
versionName "2.1.0" // legible por humanos, mostrado en la tienda
}
}
versionCode es lo que Google usa internamente. Debe aumentar estrictamente — no puedes reutilizarlo ni decrementarlo. Un esquema común es calcularlo desde los componentes de versión:
// 2.1.0 → 2001000, 2.1.3 → 2001003
def major = 2
def minor = 1
def patch = 0
versionCode = major * 1000000 + minor * 1000 + patch
versionName = "${major}.${minor}.${patch}"
O para entornos CI, usa el número de build del sistema CI:
flutter build appbundle --build-number=$CI_BUILD_NUMBER --build-name=2.1.0
Checklist de Configuración en Play Console
Antes de tu primera publicación, completa todo esto en Play Console:
- Contenido de la app — completa el cuestionario de clasificación de contenido (IARC). Tus respuestas determinan la clasificación por edad mostrada en la tienda.
- Sección de seguridad de datos — declara cada tipo de dato que tu app recopila y comparte, cómo se usa y si está cifrado en tránsito. Esta es una declaración legal. Hazla bien. Las declaraciones de seguridad de datos faltantes o inexactas son una causa creciente de rechazos.
- Listado en tienda — nombre de la app (máx 30 caracteres), descripción corta (máx 80 caracteres), descripción completa (máx 4,000 caracteres), capturas de pantalla (mínimo 2, máximo 8 por tipo de dispositivo), gráfico destacado (1024×500px), ícono de app (512×512px).
- URL de política de privacidad — requerida para cualquier app que recopile datos. Una política de privacidad real, no un placeholder.
- Audiencia objetivo — si tu app está dirigida a niños menores de 13 años, se aplican los requisitos de COPPA y GDPR-K y se activan restricciones adicionales en SDKs y recopilación de datos.
Razones Comunes de Rechazo en Google Play
Violaciones de permisos. Declarar un permiso en AndroidManifest.xml que tu app no usa activamente causará un rechazo. Audita cada etiqueta <uses-permission> y elimina todo lo que no sea necesario. El acceso a ubicación en segundo plano (ACCESS_BACKGROUND_LOCATION) requiere justificación explícita.
Listado en tienda engañoso. Capturas de pantalla que muestran características no presentes en la versión actual, o descripciones que afirman funcionalidad que la app no tiene.
Discrepancia en seguridad de datos. Si tu app usa un SDK de terceros (analytics, anuncios, reporte de crashes) que recopila datos, debes declarar esos datos en la sección de seguridad de datos incluso si tu propio código no los recopila directamente. Revisa la divulgación de seguridad de datos de cada SDK.
Violaciones de política en contenido. Discurso de odio, contenido sexual más allá de la clasificación de contenido, actividades peligrosas. Revisa la política de contenido antes de enviar.
App Store (iOS): De Principio a Fin
Certificados y Perfiles de Aprovisionamiento
La firma de código de iOS es la parte más malentendida del ecosistema de Apple. Los componentes:
Certificado — prueba tu identidad como desarrollador. Dos tipos: Desarrollo (para ejecutar en dispositivos de prueba) y Distribución (para envío a App Store). Se genera en Xcode o en developer.apple.com.
App ID — un identificador único para tu app, que coincide con tu bundle ID (ej. com.tuempresa.tuapp). Se registra en el portal de desarrolladores.
Perfil de aprovisionamiento — combina un certificado + app ID + (para desarrollo) una lista de UDIDs de dispositivos autorizados. El perfil de Distribución para App Store no lista dispositivos específicos — permite la instalación en cualquier dispositivo vía App Store.
El enfoque de gestión más simple para equipos es firma automática de Xcode para desarrollo y firma manual para builds de release en CI:
# En la configuración del proyecto Xcode
CODE_SIGN_STYLE = Automatic # desarrollo
CODE_SIGN_STYLE = Manual # release/CI
PROVISIONING_PROFILE_SPECIFIER = "AppStore Distribution 2026"
CODE_SIGN_IDENTITY = "Apple Distribution"
Para CI, exporta el certificado como archivo .p12 y el perfil de aprovisionamiento como archivo .mobileprovision, codifícalos como base64 y guárdalos como secretos de CI. Tu pipeline los decodifica e instala antes de compilar.
Compilación y Archivado
Una publicación en App Store requiere un archivo compilado con el certificado de Distribución.
# Línea de comandos de Xcode
xcodebuild archive \
-scheme TuApp \
-configuration Release \
-archivePath build/TuApp.xcarchive \
CODE_SIGN_STYLE=Manual \
PROVISIONING_PROFILE_SPECIFIER="AppStore Distribution 2026"
# Exportar IPA desde el archivo
xcodebuild -exportArchive \
-archivePath build/TuApp.xcarchive \
-exportPath build/output \
-exportOptionsPlist ExportOptions.plist
ExportOptions.plist controla el método de exportación:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>teamID</key>
<string>TU_TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>signingStyle</key>
<string>manual</string>
<key>provisioningProfiles</key>
<dict>
<key>com.tuempresa.tuapp</key>
<string>AppStore Distribution 2026</string>
</dict>
</dict>
</plist>
Para Flutter:
flutter build ipa --release
# IPA en build/ios/ipa/TuApp.ipa
Configuración en App Store Connect
Bundle ID — debe coincidir exactamente con lo que está en tu proyecto Xcode. Regístralo en el portal de desarrolladores antes de crear la app en App Store Connect.
Número de build — CFBundleVersion en Info.plist. Debe aumentar con cada build cargado a App Store Connect, incluso los builds de TestFlight. CFBundleShortVersionString es la cadena de versión visible para el usuario.
# Establecer con agvtool
agvtool new-marketing-version 2.1.0
agvtool new-version -all 42
Información de la app — nombre (máx 30 caracteres en la tienda, pero el nombre del bundle puede ser más largo), subtítulo (máx 30 caracteres, mostrado debajo del nombre en la búsqueda), categoría (primaria y secundaria opcional), declaración de derechos de contenido.
Privacidad de la app — declara cada tipo de dato que tu app recopila, el propósito y si está vinculado a la identidad del usuario. Al igual que la sección de seguridad de datos de Google, esto cubre los SDKs de terceros. Apple muestra esto como la “Etiqueta de Nutrición de Privacidad” en la página de la tienda de la app.
Clasificación por edad — basada en un cuestionario sobre contenido: violencia, contenido sexual, juegos de azar, uso de drogas, contenido generado por usuarios. Responde con precisión — representar incorrectamente el contenido apropiado para la edad es motivo de eliminación.
Capturas de pantalla — tamaños requeridos:
- iPhone 6.9” (1320×2868 o 1290×2796) — usada como predeterminada para todos los tamaños de iPhone
- iPad Pro 13” (2064×2752 o 2048×2732) — requerida si tu app soporta iPad
- Cada captura es en realidad una imagen de 1242×2688px mostrada en un marco de dispositivo en la tienda
Las capturas de pantalla deben mostrar la UI real de la app — no imágenes de marketing que no representen la app. Los revisores de Apple verifican esto.
TestFlight
TestFlight es la plataforma de distribución beta de Apple, integrada en App Store Connect. Cada build cargado a App Store Connect está automáticamente disponible en TestFlight antes de ir a revisión.
Testers internos — hasta 100 miembros de tu equipo de App Store Connect. Disponible en minutos de la carga, sin revisión requerida. Los builds expiran después de 90 días.
Testers externos — hasta 10,000 usuarios invitados por correo o un enlace público. Requiere una revisión básica de TestFlight (normalmente dentro de 24 horas, más rápida que la revisión completa de App Store). Usa esto para programas beta.
TestFlight es la manera correcta de distribuir builds pre-release a stakeholders. No uses distribución ad-hoc ni certificados empresariales para esto — viola las directrices de Apple y esos certificados son solo para pruebas internas en dispositivos.
Revisión de App Store
El proceso de revisión de Apple típicamente tarda 24–48 horas para nuevas apps y 24 horas para actualizaciones. La revisión acelerada está disponible para correcciones de bugs críticos — usa el formulario de solicitud en App Store Connect, explica el impacto en el usuario e incluye el build específico. Apple otorga revisión acelerada para problemas reales de producción, no por plazos perdidos.
Razones comunes de rechazo:
Directriz 2.1 — Rendimiento: Completitud de la App. Crashes durante la revisión, contenido placeholder (“Lorem ipsum”), o características de demo/prueba visibles en el build de producción. Los revisores prueban tu app. Los crashes fallan inmediatamente.
Directriz 4.0 — Diseño. Apps demasiado simples — una sola vista web de un sitio web, un lector de PDF sin características adicionales, o apps que replican la funcionalidad de una app integrada de iOS sin añadir valor.
Directriz 5.1.1 — Privacidad: Recopilación de Datos. Solicitar acceso a contactos, ubicación, cámara, micrófono o datos de salud sin una cadena de propósito clara en Info.plist. La cadena de propósito debe explicar específicamente por qué la app necesita acceso — “para una mejor experiencia” se rechaza. Sé específico.
Directriz 3.1.1 — Compras In-App. Vender bienes digitales o suscripciones a través de un método de pago diferente al sistema IAP de Apple. Esto incluye enlazar a un sitio web para comprar una suscripción que luego está disponible en la app.
Directriz 1.4 — Daño Físico. Apps que proporcionan información peligrosa sin advertencias apropiadas: información de dosis médicas, asesoramiento legal, asesoramiento financiero. Añade exenciones de responsabilidad.
Cuando recibes un rechazo, lee la directriz específica citada. Responde en el Centro de Resolución con el cambio exacto que hiciste y dónde encontrarlo en la app. No discutas — aborda la preocupación específica y vuelve a enviar.
Optimización de Tienda de Apps (ASO)
ASO es cómo los usuarios encuentran tu app mediante búsqueda dentro de la tienda. Impacta directamente las descargas orgánicas sin ningún gasto en publicidad.
Nombre de la app. Incluye tu palabra clave principal en el nombre. Los usuarios buscan lo que la app hace, no cómo se llama. “Planify — Planificador de Tareas” aparece en resultados para “Planify” y “planificador de tareas”. Google Play da más peso al nombre que Apple.
Campo de palabras clave (solo iOS). 100 caracteres, separados por comas, sin espacios después de las comas. Apple no muestra esto a los usuarios — es puramente para indexación de búsqueda. No repitas palabras que ya están en tu nombre o subtítulo. Usa los 100 caracteres completos.
tarea,planificador,todo,calendario,recordatorio,horario,productividad,trabajo,metas,hábito
Descripción. Google Play indexa la descripción completa para búsqueda. Pon las palabras clave más importantes en las primeras tres líneas (visibles sin tocar “más”). Apple no indexa la descripción para búsqueda — enfócate en la conversión, no en las palabras clave.
Capturas de pantalla. Las primeras dos capturas se muestran en los resultados de búsqueda antes de que el usuario toque el listado. Estas impulsan la conversión más que cualquier otro activo. Hazlas explicaciones funcionales del valor central de la app, no imágenes decorativas.
Calificaciones. Ambas tiendas usan la calificación promedio y el conteo de reseñas como señales de ranking. Solicita calificaciones en un momento de éxito — después de completar una tarea, después de una interacción positiva — no al lanzar o después de un error. Usa el prompt de calificación nativo de la plataforma (no uno personalizado que filtre reseñas negativas a un formulario en lugar de la tienda — esto viola las directrices de ambas tiendas).
Notas de actualización. Los usuarios leen las notas de actualización antes de actualizar. Escríbelas para usuarios, no para el sistema de tickets interno de tu equipo. “Varias correcciones de bugs y mejoras de rendimiento” es una oportunidad perdida. Describe qué cambió, qué mejoró y qué es nuevo.
Automatizando con Fastlane
Fastlane es la herramienta estándar para automatizar pipelines de lanzamiento móvil. Maneja compilación, firma, generación de capturas de pantalla, gestión de metadatos y carga a ambas tiendas desde un solo Fastfile.
Instalar:
gem install fastlane
# o
brew install fastlane
Inicializar en la raíz del proyecto:
fastlane init
Un Fastfile para una app Flutter con ambas tiendas:
# fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "Ejecutar pruebas"
lane :test do
run_tests(scheme: "Runner")
end
desc "Compilar y subir a TestFlight"
lane :beta do
build_number = ENV["CI_BUILD_NUMBER"] || "1"
increment_build_number(
build_number: build_number,
xcodeproj: "ios/Runner.xcodeproj"
)
sh("flutter build ipa --release --build-number=#{build_number}")
upload_to_testflight(
ipa: "build/ios/ipa/Runner.ipa",
skip_waiting_for_build_processing: true
)
end
desc "Enviar a App Store"
lane :release do
upload_to_app_store(
ipa: "build/ios/ipa/Runner.ipa",
skip_screenshots: false,
skip_metadata: false,
submit_for_review: false,
automatic_release: false
)
end
end
platform :android do
desc "Compilar y subir al track Interno"
lane :internal do
build_number = ENV["CI_BUILD_NUMBER"] || "1"
sh("flutter build appbundle --release --build-number=#{build_number}")
upload_to_play_store(
track: "internal",
aab: "build/app/outputs/bundle/release/app-release.aab",
json_key: ENV["GOOGLE_PLAY_JSON_KEY_PATH"]
)
end
desc "Promover de interno a producción con rollout escalonado"
lane :promote_production do
upload_to_play_store(
track: "internal",
track_promote_to: "production",
rollout: "0.1",
json_key: ENV["GOOGLE_PLAY_JSON_KEY_PATH"]
)
end
end
Para automatización de Google Play, genera una clave JSON de cuenta de servicio en Google Cloud Console con el rol “Service Account” en Play Console. Guarda el JSON como secreto de CI.
Para automatización de App Store, usa claves API de App Store Connect (no tu Apple ID personal). Genera una clave en App Store Connect → Usuarios y Acceso → Integraciones → API de App Store Connect. Guarda la clave privada (archivo .p8), el ID de clave y el ID del emisor como secretos de CI.
Pipeline de GitHub Actions
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.29.0'
- name: Decodificar keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/upload-keystore.jks
- name: Compilar AAB
env:
KEYSTORE_PATH: upload-keystore.jks
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: flutter build appbundle --release --build-number=${{ github.run_number }}
- name: Subir a Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
packageName: com.tuempresa.tuapp
releaseFiles: build/app/outputs/bundle/release/app-release.aab
track: internal
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.29.0'
- name: Instalar certificado y perfil
env:
CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE_BASE64 }}
CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
run: |
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
echo "$CERTIFICATE_BASE64" | base64 -d > certificate.p12
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
echo "$PROVISIONING_PROFILE_BASE64" | base64 -d > profile.mobileprovision
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
- name: Compilar IPA
run: flutter build ipa --release --build-number=${{ github.run_number }}
- name: Subir a TestFlight
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
run: |
xcrun altool --upload-app \
--type ios \
--file build/ios/ipa/Runner.ipa \
--apiKey "$APP_STORE_CONNECT_API_KEY_ID" \
--apiIssuer "$APP_STORE_CONNECT_ISSUER_ID"
Rollouts Escalonados y Monitoreo
Rollout Escalonado en Google Play
Nunca lances al 100% de inmediato. Usa rollouts escalonados — lanza a un porcentaje de usuarios, monitorea la tasa de crashes y la tasa de ANR, luego expande.
En Play Console, establece el porcentaje de rollout al promover a producción. Puedes aumentar o detener el rollout en cualquier momento.
Criterios de detención: si la tasa de sesiones sin crashes cae por debajo del 99.5% o la tasa de ANR aumenta mediblemente, detén el rollout antes de expandirlo. Un rollout detenido no elimina la app de los usuarios existentes — detiene el rollout para nuevos usuarios mientras investigas.
Día 0: Lanzar al 10%
Día 2: Tasa de crashes estable → expandir al 30%
Día 4: Estable → expandir al 50%
Día 6: Estable → expandir al 100%
Con fastlane:
lane :expand_rollout do |options|
upload_to_play_store(
track: "production",
rollout: options[:percentage].to_s,
skip_upload_aab: true,
json_key: ENV["GOOGLE_PLAY_JSON_KEY_PATH"]
)
end
# fastlane expand_rollout percentage:0.5
Lanzamiento por Fases en App Store
El equivalente de Apple es el Lanzamiento por Fases — automáticamente expande al 1%, 2%, 5%, 10%, 20%, 50% y luego 100% durante 7 días. Puedes pausar un lanzamiento por fases hasta 30 días.
Actívalo en App Store Connect al enviar la versión: Lanzamiento por Fases → Activado.
Qué Monitorear Post-Lanzamiento
Configura el monitoreo antes de tu primer lanzamiento a producción — no después de que algo se rompa.
Reporte de crashes. Firebase Crashlytics es el estándar para ambas plataformas. Muestra la tasa sin crashes, el conteo de crashes por versión y stack traces simbolizados. Establece umbrales de alerta al 0.5% de tasa de crashes.
Tasa de ANR (Android). Application Not Responding — el cuelgue específico de Android que ocurre cuando el hilo principal está bloqueado más de 5 segundos. Play Console lo muestra bajo Android Vitals. Las tasas altas de ANR pueden causar que Play reduzca la visibilidad de tu app en la búsqueda.
Android Vitals — umbrales de Play:
- Tasa de crashes < 1.09% (umbral actual de Play para marcar “comportamiento deficiente”)
- Tasa de ANR < 0.47%
- Wakeups excesivos, wake locks parciales bloqueados, escaneos WiFi en segundo plano excesivos
Monitorea esto desde el primer día. Play usa datos de Android Vitals para penalizar apps en el ranking de búsqueda.
Emergencia: Retirar un Lanzamiento
A veces un lanzamiento llega con un bug crítico. Las opciones difieren entre plataformas.
Google Play. No puedes eliminar una versión que ya está instalada en los dispositivos de los usuarios. Puedes:
- Detener el rollout escalonado (detiene la expansión, no elimina de usuarios existentes)
- Enviar una actualización de emergencia inmediatamente — puede pasar revisión en horas si solicitas el indicador de revisión prioritaria
App Store. Después de la aprobación, puedes eliminar la versión de la venta en App Store Connect antes de que más usuarios la descarguen. Los usuarios que ya la tienen instalada la conservan. Envía una actualización acelerada inmediatamente.
El pipeline de hotfix de emergencia:
Detectar problema crítico
→ Detener rollout (Android) o Eliminar de la venta (iOS)
→ Crear rama hotfix desde el tag del lanzamiento
→ Corregir el problema específico — cambio mínimo
→ Incrementar número de build/version code
→ Ejecutar pruebas automatizadas en el hotfix
→ Enviar via CI al track Interno (Android) o TestFlight (iOS)
→ Prueba de humo manual en dispositivos físicos
→ Enviar actualización de emergencia a producción
→ Monitorear por 2 horas
→ Reanudar/expandir rollout
La disciplina clave: la rama hotfix toca solo lo que está roto. No incluyas cambios no relacionados en un lanzamiento de emergencia. Cada cambio adicional es una nueva superficie para nuevos bugs.
Gestión del Ciclo de Vida de la App
Soporte de Múltiples Versiones
Los usuarios no siempre actualizan de inmediato. En Android, puedes alcanzar el 85%+ de tus usuarios activos dentro de 2 semanas de un lanzamiento. En iOS, la adopción de actualizaciones es típicamente más rápida — más del 90% en pocas semanas para usuarios activos. Pero la cola persiste.
Decide tu versión mínima soportada cuidadosamente:
- Establece
minSdkVersion(Android) y el Destino de Despliegue de iOS basándote en tu analytics real de usuarios, no en el SDK más reciente disponible - Las barreras de actualización forzada (mostrar una pantalla de bloqueo “por favor actualiza”) deben usarse solo para problemas críticos de seguridad o incompatibilidad de API — los usuarios abandonan apps que exigen actualizaciones sin razón clara
- Depreca versiones antiguas con gracia: notifica en la app antes de deshabilitar características, da a los usuarios un cronograma
Actualizaciones de Privacidad y Cumplimiento
Ambas tiendas ahora requieren mantenimiento continuo de cumplimiento:
- La sección de Seguridad de Datos de Google debe actualizarse cuando añades nuevos SDKs o cambias las prácticas de recopilación de datos
- La declaración de Privacidad de App de Apple debe actualizarse cuando añades nuevos SDKs — incluso si tu propio código no cambia
- Los flujos de consentimiento GDPR / CCPA deben estar presentes si tu app sirve usuarios de la UE o California y usa cualquier SDK de publicidad o analytics
Una actualización mayor de SDK (Google Analytics, Firebase, Meta SDK) a menudo cambia qué datos se recopilan. Revisa la documentación de seguridad de datos del SDK antes de cada actualización, no solo al enviar una nueva funcionalidad.
Publicar una app móvil es un proceso que aprendes a través de la iteración. La primera publicación siempre es la más difícil — cada requisito desconocido sale a la superficie a la vez. Para el tercer o cuarto ciclo de lanzamiento, el proceso se vuelve rutinario: firmar, compilar, subir, monitorear, expandir, repetir. Los desarrolladores que lo hacen sin problemas son los que automatizaron las partes mecánicas e internalizaron las directrices de revisión lo suficientemente bien como para que los rechazos sean raros y recuperables cuando ocurren.
La tienda no es la línea de llegada. Es el comienzo de la relación entre tu app y sus usuarios. Cada lanzamiento es una promesa sobre calidad, privacidad y confiabilidad. Cúmplela.
Tags
Artículos relacionados
API Versioning Strategies: Cómo Evolucionar APIs sin Romper Clientes
Una guía exhaustiva sobre estrategias de versionado de APIs: URL versioning vs Header versioning, cómo deprecar endpoints sin shock, migration patterns reales, handling de cambios backwards-incompatibles, y decisiones arquitectónicas que importan. Con 50+ ejemplos de código en Go.
Arquitectura de software: Más allá del código
Una guía completa sobre arquitectura de software explicada en lenguaje humano: patrones, organización, estructura y cómo construir sistemas que escalen con tu negocio.
Automatizando tu vida con Go CLI: Guía profesional para crear herramientas de línea de comandos escalables
Una guía exhaustiva y paso a paso sobre cómo crear herramientas CLI escalables con Go 1.25.5: desde lo básico hasta proyectos empresariales complejos con flags, configuración, logging, y ejemplos prácticos para Windows y Linux.