Feature Flags para Apps Móviles: Guía Práctica
Feature flags para apps móviles: kill switches, rollouts por fases, caché de remote config y cómo esquivar trampas de revisión en iOS y Android.

📚 Este artículo es parte de la guía Feature Flags: la Guía Completa.
Los feature flags para apps móviles resuelven un problema que el desarrollo web no tiene: una vez que un build llega a la App Store o a Google Play, no puedes editarlo, solo puedes envolverlo. Un feature flag ya enviado dentro de un binario revisado activa o desactiva una parte del comportamiento desde tu servidor, en minutos, sin un envío nuevo, sin una revisión nueva y sin una instalación nueva. Esa única propiedad, cambiar el comportamiento sin enviar código nuevo, es lo que convierte a los flags en la columna vertebral de los kill switches, los rollouts por fases y el remote config en iOS y Android.
Esta guía se queda específicamente en el lado móvil de esa historia: por qué el retraso de la revisión en las tiendas hace inviable la mentalidad de “solo publico un hotfix”, cómo se comporta realmente un kill switch en un dispositivo que ya tiene el código viejo instalado, la diferencia real entre un rollout por fases de la tienda y uno controlado por flags, cómo Firebase Remote Config, los SDK móviles de LaunchDarkly, ConfigCat y Unleash manejan la caché y los dispositivos sin conexión de forma distinta, y las trampas de revisión y fragmentación que atrapan a los equipos móviles que copian un manual web sin ajustarlo.
Por qué las apps nativas no pueden hacer hotfix como una página web
En la web, un deploy está a un git push de distancia de cada visitante. En móvil, un cambio de código tiene que sobrevivir a una tubería que la web no tiene: construir el binario, enviarlo, esperar la revisión humana o automatizada, y después esperar otra vez mientras la tienda va entregando gradualmente la actualización a los dispositivos instalados. La propia Apple publica que, en promedio, el 90% de los envíos se revisan en menos de 24 horas, en su página de App Review. Es un promedio, no un compromiso, y la propia formulación deja al 10% de los envíos fuera de esa ventana sin plazo declarado. Google Play documenta su parte de forma todavía menos determinista: las actualizaciones de apps existentes se procesan y publican tan pronto como sea posible, pero ciertas apps pasan por revisiones extendidas, que pueden tardar hasta 7 días o más en casos excepcionales, según el Centro de Ayuda de Play Console. Ninguna de las dos tiendas promete un plazo del que puedas depender en medio de un incidente, y ese es justamente el punto.
Incluso después de la aprobación, la actualización no llega a todos al instante. La propia documentación de App Store Connect de Apple describe un phased release que reparte una actualización de versión a lo largo de 7 días en pasos diarios fijos: 1%, 2%, 5%, 10%, 20%, 50% y 100% de los dispositivos elegibles con actualizaciones automáticas activadas. El staged rollout de Google Play funciona con el mismo principio pero le da al desarrollador el control directo del porcentaje, ajustable en incrementos desde el 1% hasta el 100%, y solo puede usarse en actualizaciones, no en un primer envío.
Esa brecha entre “quiero esto apagado ahora mismo” y “el arreglo tiene que pasar otra vez por la tienda” es exactamente lo que un feature flag existe para cerrar. Nada en un flag se salta la revisión de código nuevo: simplemente mueve la decisión de qué mostrar hacia un interruptor que la tienda ya aprobó, así que cambiarlo después no exige volver a pasar por la tubería de arriba.
Qué cambia realmente un flag en un dispositivo que ya tiene el código viejo
Un feature flag móvil no descarga código nuevo. La Guideline 2.5.2 de Apple es explícita en que una app no puede “descargar, instalar o ejecutar código que introduzca o cambie funciones o funcionalidades de la app”, con una excepción estrecha reservada a apps educativas que enseñan o permiten a los estudiantes probar código, y solo si el código fuente queda totalmente visible y editable por el usuario. Lo que un flag cambia, en cambio, es un booleano, un número o una pequeña carga JSON que una condicional ya compilada dentro de la app lee y sobre la que se ramifica. El código de la ruta “apagada” y de la “encendida” se envió junto, en el mismo binario revisado; el flag solo decide, en tiempo de ejecución, qué ruta se ejecuta para un dispositivo dado.
Esa distinción también es la que mantiene el comportamiento gobernado por flags del lado correcto de la Guideline 2.3.1. La orientación de Apple, repetida en sus propios foros de desarrolladores, es que una función puede activarse remotamente después del lanzamiento siempre que se le haya revelado a App Review y se le haya dado acceso para probarla antes de la aprobación, idealmente a través de una puerta trasera documentada en las notas de revisión. Un flag que revela silenciosamente una función no declarada después de que la app pasa la revisión es exactamente la discrepancia entre lo que vieron los revisores y lo que los usuarios experimentan después que la 2.3.1 existe para atrapar.
Kill switches: el superpoder específicamente móvil
Un kill switch es un flag cuyo único trabajo es desactivar al instante una función, o una dependencia de terceros entera, sin una release nueva. En móvil esto importa más que en la web justamente por el retraso de publicación de arriba: si un SDK de pagos se porta mal, si un proveedor de mapas se cae o si una pantalla nueva rompe en una clase específica de dispositivos, esperar una revisión acelerada, incluso la vía de emergencia más rápida de Apple, se mide en horas en el mejor de los casos. Un kill switch ya cableado en el código antes de que ocurra el incidente convierte ese tiempo de respuesta en minutos.
El mismo mecanismo de rollout que alimenta un kill switch también alimenta un despliegue gradual, solo que corriendo en la dirección opuesta: en lugar de expandir la exposición del 1% hacia el 100%, un incidente la colapsa desde donde estuviera directo al 0%, para todos los dispositivos que ya corren el binario, con independencia del porcentaje que la propia tienda hubiera alcanzado en su phased release.
Dos porcentajes de rollout, controlados por dos partes distintas
Esta es la parte que hace tropezar a los equipos que pasan de web a móvil: una sola app puede tener dos porcentajes de rollout independientes corriendo al mismo tiempo, y confundirlos lleva a leer la señal equivocada. Uno le pertenece a la tienda; el otro le pertenece a tu propio backend.
| Rollout por fases de la tienda | Rollout por feature flag | |
|---|---|---|
| Quién controla el porcentaje | Apple o Google (Apple lo fija automáticamente a lo largo de 7 días; Google te deja fijarlo manualmente) | Tu propio backend o el panel del proveedor de flags |
| Qué controla | Qué dispositivos reciben siquiera el binario nuevo de la app | Qué comportamiento está activo dentro de un binario que ya tiene todo el código |
| ¿Puede retroceder al instante? | Solo pausando la distribución posterior; los dispositivos que ya se actualizaron se quedan con ese binario | Sí, un kill switch puede bajar la exposición al 0% para dispositivos ya actualizados en minutos |
| Cronograma típico | Apple: 1%, 2%, 5%, 10%, 20%, 50%, 100% fijos a lo largo de 7 días. Google: incrementos elegidos por el desarrollador del 1% al 100% | De minutos a días, enteramente a criterio del operador |
| ¿Atado a una versión de la app? | Sí, por definición | No, puede aplicarse a todas las versiones que aún sean capaces de leer ese flag |
Un error común es leer un cambio de métrica durante un rollout sin saber cuál de esos dos porcentajes se estaba moviendo en ese momento. Si el phased release de la tienda todavía está subiendo, también estás mezclando usuarios que se actualizaron en momentos distintos y que quizá corren rutas de código algo diferentes más allá del propio flag, lo cual es una confusión que el cambio del flag por sí solo no explica.
Herramientas de remote config: en qué se diferencian de verdad las principales opciones móviles
“Remote config” y “feature flag” se usan casi como sinónimos en móvil, pero las herramientas detrás de ellos difieren en modelo de hosting, experimentación nativa y, sobre todo, en cómo se comportan cuando un dispositivo no tiene conexión de red.
| Herramienta | Modelo | Lectura A/B nativa | Comportamiento sin conexión / caché |
|---|---|---|---|
| Firebase Remote Config | Gestionada, parte de la suite Firebase de Google | Vía Google Analytics y Firebase A/B Testing, montado sobre los valores de Remote Config | El intervalo de fetch por defecto en producción es de 12 horas; pedir con más frecuencia que la ventana de throttle configurada devuelve una excepción del lado del cliente en vez de un valor fresco, y el SDK siempre evalúa primero desde la última config cacheada con éxito |
| SDK móviles de LaunchDarkly (iOS/Android) | SaaS comercial, conexión en streaming cuando la app está en primer plano | Nativa, frecuentista y bayesiana, integrada en la misma plataforma | Transmite actualizaciones en tiempo real mientras la app está en primer plano; el SDK de iOS no soporta background fetch en absoluto, así que las apps de iOS en segundo plano no reciben actualizaciones en vivo, mientras que Android cae automáticamente a polling en segundo plano |
| ConfigCat | SaaS gestionado con una config respaldada por CDN, SDK para iOS, Android y Kotlin Multiplatform | No nativa; la propia documentación de ConfigCat se centra en la entrega de flags y deja la lectura estadística a una herramienta externa | Tres modos explícitos de polling (auto polling, lazy loading, manual polling) más un modo offline dedicado que sirve solo desde una caché local pre-poblada y nunca llama a la red |
| Unleash (con Unleash Edge) | Open source en el núcleo, autoalojado o nube Enterprise; Edge es una capa de caché y evaluación en el borde delante de los SDK | No nativa; la propia guía de Unleash recorre el reparto de usuarios más los eventos de impresión, y después entrega la lectura de significancia a una herramienta de analítica externa | Edge evalúa localmente y, según la propia documentación de Unleash, una sola instancia puede servir de decenas de miles a cientos de miles de peticiones por segundo desde caché, con el modo streaming reduciendo el retraso de replicación de un intervalo de polling a algo casi en tiempo real |
Ninguna de estas cuatro es universalmente correcta para una app móvil. Un equipo que ya está dentro del ecosistema Firebase o Google obtiene remote config, analítica y una lectura básica de experimentos sin sumar un proveedor. Un equipo que quiere un motor estadístico nativo y maduro y que está cómodo pagando por él suele aterrizar en LaunchDarkly. Un equipo pequeño que quiere un SDK ligero y un comportamiento de polling predecible sin un lock-in profundo de plataforma suele preferir ConfigCat. Un equipo que ya corre Unleash para sus servicios web y quiere los mismos flags en su app móvil, sin enviar datos de usuario final más arriba de lo necesario, es aquel para el que se construyó Unleash Edge.
Caché y comportamiento sin conexión: la parte que la mayoría de las guías se salta
Todas las herramientas de arriba comparten una regla innegociable: un SDK móvil nunca puede bloquear la interfaz esperando una llamada de red que quizá no llegue a completarse. Un dispositivo puede perder conectividad a mitad de camino, quedarse en modo avión o simplemente arrancar en frío antes de que un fetch resuelva, y la app igual tiene que dibujar algo.
Las herramientas de arriba codifican esta regla de formas distintas pero compatibles. Firebase Remote Config limita los fetch repetidos (cinco peticiones por hora en versiones antiguas del SDK, más permisivo en las nuevas) y solo reemplaza la config en memoria tras un fetch más una llamada explícita de activate, así que un fetch lento o fallido nunca bloquea el dibujado: simplemente significa que la app sigue usando lo que ya tenía. Los SDK móviles de LaunchDarkly mantienen un almacén persistido en el dispositivo, de modo que un arranque en frío ya tiene los últimos valores conocidos antes de que se complete cualquier ida y vuelta de red. El modo offline de ConfigCat lleva esto a su extremo lógico: una app puede correr enteramente contra una caché sembrada localmente y no llamar nunca a la red, útil para un build que necesita funcionar en un entorno genuinamente desconectado. En todos los casos, la disciplina que importa es la misma: envía un valor por defecto sensato para cada flag dentro del binario, porque la red es lo único que ninguna de estas herramientas puede garantizar.
Combinar feature flags con un test A/B real en móvil
Un rollout de flag te dice qué porcentaje de dispositivos ve un comportamiento. No te dice, por sí solo, si ese comportamiento mejoró algo. Como se cubre con más profundidad en nuestra guía sobre feature flags frente a test A/B, un flag es un mecanismo de entrega y un test es un método de medición, y el móvil no cambia esa frontera, solo le suma dos arrugas extra.
La primera arruga es qué capa cierra el bucle estadístico. Como muestra la tabla de arriba, LaunchDarkly calcula la significancia de forma nativa sobre los mismos datos de flags; Firebase Remote Config normalmente se apoya en Firebase A/B Testing o Google Analytics para esa lectura; ConfigCat y Unleash entregan la señal cruda de exposición a la analítica que ya tengas montada. Antes de confiar en un porcentaje de rollout como si fuera un resultado terminado, confirma de qué lado de esa línea está tu stack, la misma distinción que recorre nuestra guía para implementar pruebas A/B en el servidor para los experimentos de backend en general.
La segunda arruga es específicamente móvil: la fragmentación de versiones de la app. Un rollout que abarca dispositivos con varias versiones instaladas distintas al mismo tiempo está comparando más que el flag, porque los builds más viejos pueden llevar arreglos de bugs distintos, una interfaz distinta o un conjunto de rutas de código enteramente distinto. La lectura más limpia sale de un rollout de flag corriendo dentro de una sola versión estable de la app, una vez que el phased release de la tienda para esa versión ya terminó de subir, no mientras los dos porcentajes se mueven a la vez. Nuestra guía sobre rollout progresivo y canary release cubre la disciplina de métricas de guardarraíl que mantiene honesta una expansión por fases, en móvil o en cualquier otro sitio.
Trampas que atrapan específicamente a los equipos móviles
| Trampa | Por qué pasa | Corrección |
|---|---|---|
| Rechazo en la App Store por una función escondida | Un flag revela funcionalidad que los revisores nunca vieron, violando la Guideline 2.3.1 | Declara la función y una forma de activarla en las Notes for Review antes del envío, incluso si sale desactivada |
| Confundir un flag con la excepción de descarga de código | La Guideline 2.5.2 prohíbe descargar y ejecutar código nuevo; un flag que trae lógica nueva, no solo un valor, cruza esa línea | Envía solo comportamiento totalmente compilado en el binario revisado; un flag debe elegir entre rutas, no traer rutas nuevas |
| Leer resultados a través de versiones de la app | Un rollout abarca varios binarios instalados con código distinto, enturbiando la comparación | Lee resultados solo dentro de una versión estable de la app, una vez que su propio rollout de tienda terminó |
| Sin valor por defecto escrito en duro para un flag | La app asume que la llamada de red siempre resolverá antes de dibujar | Todo flag necesita un valor por defecto seguro enviado en el propio binario, según la lógica de caché y sin conexión de arriba |
| Throttling de fetch durante el QA | Las pruebas manuales rápidas chocan con el throttling del proveedor (el intervalo mínimo de fetch de Firebase, por ejemplo) y el QA ve valores viejos | Usa un intervalo de fetch reducido solo en builds de desarrollo, nunca en producción, como la mayoría de los proveedores documenta explícitamente |
| Flags huérfanos que quedan en binarios viejos | Un flag eliminado del backend sigue siendo evaluado por usuarios atascados en una versión vieja que nunca se actualizó | Mantén una fecha de retirada documentada, y confirma que el valor por defecto en los binarios viejos sigue siendo seguro indefinidamente |
Automatiza esto con Donnu
Donnu A/B no es un SDK móvil y no evalúa flags en un dispositivo: es un motor de experimentación web, y no va a pretender otra cosa. Pero el dolor que recorre esta guía, desplegar con seguridad, vigilar un guardarraíl y confiar en un resultado solo cuando es estadísticamente real, es exactamente el mismo dolor que siente tu equipo web en cuanto un rollout de flag móvil pasa de “publícalo y observa” a “¿podemos probar que esto ayudó de verdad?”. Si la superficie que toca tu rollout incluye una página web, un flujo de checkout o un sitio de marketing junto a tu app, Donnu te da el tamaño de muestra calculado, la lectura bayesiana honesta y los datos aislados por cuenta que un porcentaje de rollout crudo no ofrece por sí solo. Empieza una prueba gratis de 14 días para la mitad web de esa historia, y combínala con la herramienta de flags móvil de esta guía que ya controla tu app.
Lee también: Feature Flags: la guía completa · Feature Flags frente a Test A/B · Rollout progresivo y canary release explicados · Herramientas de feature flag comparadas.
Referencias
- Apple. App Review Guidelines (2.3.1 metadatos precisos y funcionalidad oculta, 2.5.2 requisitos de software sobre código descargado). developer.apple.com/app-store/review/guidelines.
- Apple. App Review (fuente del dato de que, en promedio, el 90% de los envios se revisan en menos de 24 horas). developer.apple.com/app-store/review.
- Google. Prepara y lanza tu app: revisiones extendidas, Centro de Ayuda de Play Console. support.google.com/googleplay/android-developer/answer/9859751.
- Apple. Release a version update in phases, App Store Connect Help. developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases.
- Google. Release app updates with staged rollouts, Play Console Help. support.google.com/googleplay/android-developer/answer/6346149.
- Firebase. Remote Config loading strategies, documentación oficial. firebase.google.com/docs/remote-config/loading.
- Firebase. Empezar con Remote Config en Android (fuente del intervalo minimo de fetch de 12 horas en produccion y del error de throttle). firebase.google.com/docs/remote-config/use-config-android.
- LaunchDarkly. Using mobile SDKs, documentación oficial. launchdarkly.com/docs/guides/sdk/mobile.
- ConfigCat. Polling Modes and Caching, documentación oficial. configcat.com/docs/advanced/caching.
- Unleash. Unleash Edge overview, documentación oficial. docs.getunleash.io/unleash-edge.
- Fowler, M. Feature Toggles (aka Feature Flags). martinfowler.com/articles/feature-toggles.html.
Preguntas frecuentes
- ¿Un feature flag puede hacer que rechacen mi app en la App Store?
- Un flag en sí no hace que rechacen una app, pero cómo lo uses sí puede. Las App Store Review Guidelines de Apple (2.3.1) exigen que toda la funcionalidad se describa con especificidad en las Notes for Review y sea accesible para los revisores, así que una función escondida detrás de un flag y activada solo después de la aprobación viola esa regla salvo que se le haya informado a Apple y se le haya dado una forma de revisarla antes. Por separado, la Guideline 2.5.2 prohíbe descargar y ejecutar código nuevo después de la aprobación, así que un flag solo es seguro cuando alterna una ruta de código que ya se envió dentro del binario revisado, no cuando trae lógica nueva desde tu servidor.
- ¿Cuál es la diferencia entre un rollout por fases de la App Store y un rollout por feature flag?
- Un rollout por fases (el phased release de Apple o el staged rollout de Google Play) controla cuántos dispositivos instalados reciben un binario nuevo de la app, y está atado a la versión de la app: una vez que un dispositivo se actualiza, se queda con ese código hasta la próxima actualización, y revertir significa publicar otra release. Un rollout por feature flag controla en cuántos de esos dispositivos ya actualizados se activa un comportamiento dado, y vive en tu servidor, así que puedes subirlo, bajarlo o matarlo en minutos, para todos los dispositivos que ya corren ese binario, sin tocar la tienda de apps.
- ¿Necesito Firebase Remote Config, LaunchDarkly o ConfigCat si mi app ya usa phased release?
- Normalmente sí, porque resuelven problemas distintos. El phased release te protege de que un binario roto llegue a todos de golpe, pero una vez que un build está fuera no puedes cambiar su comportamiento sin un envío nuevo y otro ciclo de revisión. Una herramienta de flags remotos te deja cambiar el comportamiento dentro de un binario que ya pasó la revisión, al instante y sin la tienda en el medio, que es exactamente lo que necesitas para un kill switch o para un porcentaje de rollout que se mueve rápido.
- ¿Qué le pasa a un feature flag móvil cuando el dispositivo está sin conexión?
- Cae al valor que quedó en caché de la última descarga exitosa o, si la app nunca descargó con éxito, a un valor por defecto escrito en duro en el binario. Por eso toda integración de flags móvil necesita un valor por defecto seguro para cada flag: los clientes de Firebase Remote Config, LaunchDarkly, ConfigCat y Unleash Edge evalúan primero localmente desde la caché, y ninguno de ellos puede bloquear la app esperando una llamada de red que quizá nunca se complete.
- ¿Puedo correr un test A/B real usando feature flags en una app móvil?
- Sí, pero la herramienta de flags normalmente solo se encarga del reparto de usuarios y del evento de exposición, no de la lectura estadística. LaunchDarkly y, del lado web, herramientas como PostHog calculan la significancia de forma nativa sobre sus propios datos de flags, pero muchos montajes centrados en móvil (Firebase Remote Config más Google Analytics, o Unleash más una herramienta de analítica externa) solo emiten la señal cruda y esperan que un motor de estadística aparte declare al ganador. Confirma de qué lado de esa línea está tu stack antes de confiar en un porcentaje de rollout como si fuera un experimento terminado.