La respuesta corta

Una app privada de managed Google Play es una app que solo existe para las organizaciones que tú autorizas: no aparece en la Play Store pública, no la encuentra nadie buscando y se despliega desde la consola del EMM de la empresa.

Hay dos vías para publicarla y no son intercambiables. Desde el iframe de managed Google Play, integrado en la consola del EMM, basta con el título y el fichero y la app suele estar lista en unos diez minutos. Desde Play Console, se declara la organización destinataria por su Organization ID y se admiten hasta 1.000 organizaciones por app, con un procesamiento de registro de hasta 48 horas.

Y hay una decisión que no tiene marcha atrás: una app privada no se convierte en pública. Si algún día quieres abrirla al mercado, hay que publicar una app nueva con otro nombre de paquete. Esa frase es la que conviene leer dos veces antes de elegir el applicationId.

Las dos vías

Iframe de managed Google PlayPlay Console
Dónde se haceDentro de la consola del EMMPlay Console del desarrollador
Qué pideTítulo y fichero (AAB o APK)Ficha completa y release de producción
Cuánto tarda~10 minutosHasta 48 h de procesamiento de registro
A cuántas organizacionesLa del propio EMMHasta 1.000 por app
Quién la usaEl equipo de IT del clienteEl desarrollador o un tercero
RequisitoQue el EMM soporte el iframeCuenta de Play Console

La primera pregunta operativa no es técnica: ¿el EMM del cliente soporta el iframe? No todos lo hacen. Si no lo soporta, la vía es Play Console y el calendario cambia — cuarenta y ocho horas no caben en el mismo plan de lanzamiento que diez minutos.

Vía 1 — el iframe, cuando el cliente publica lo suyo

Es el camino corto y el que encaja cuando la app es de la propia empresa y su equipo de IT la gestiona: se sube el binario desde la consola del EMM y queda aprobada automáticamente para esa organización.

El detalle que sostiene los diez minutos: las apps privadas no pasan por las mismas comprobaciones que una app pública. Eso es una ventaja de calendario y una responsabilidad añadida — nadie va a avisarte de que has dejado un permiso de más o una clave en el binario. Lo que en una app pública te habría frenado la revisión, aquí sale a producción.

El límite que hay que conocer si el despliegue es masivo o el pipeline reintenta: 15 apps privadas al día por organización.

Vía 2 — Play Console, cuando publicas tú para un cliente

Es la vía del proveedor, y la que se usa cuando quien construye la app no es quien la administra. El camino en la consola:

  1. Crear la app con su título.
  2. Release → Setup → Advanced settings → pestaña Managed Google Play.
  3. Add organization, con el Organization ID y una descripción.
  4. Guardar, crear la release de producción con el bundle y desplegarla.

El Organization ID lo saca el cliente de su managed Google Play store, en los ajustes de administración. Sin ese identificador no hay canal: es el equivalente Android del Organization ID de Apple Business Manager que se necesita para una Custom App en iOS.

Una vez restringida, la app queda privada y disponible solo para esas organizaciones. Se pueden declarar hasta mil, así que la vía sirve tanto para un cliente único como para una red de franquiciados o un producto B2B que se despliega empresa a empresa.

Las tres decisiones sin marcha atrás

Aquí es donde se pagan los errores, y las tres se toman al principio:

No se convierte en pública. Para llevar al mercado una app que nació privada hay que publicar otra app con otro nombre de paquete. Es decir: nueva ficha, nueva instalación, cero valoraciones heredadas y cero continuidad para el usuario.

No es transferible. Una app privada no cambia de cuenta de desarrollador. Si se publicó bajo la cuenta de la agencia y mañana el cliente quiere llevársela, no se mueve: se vuelve a publicar y se vuelve a desplegar en todos los dispositivos. Por eso la cuenta debe ser del cliente desde el día uno, igual que en iOS.

El nombre de paquete es para siempre. Un applicationId del estilo com.agencia.clientex sobrevive al contrato. Ponerlo en el dominio del cliente cuesta cero al empezar y no tiene arreglo después.

Managed configurations: la parte que casi nadie implementa

Este es el diferencial real de una app de empresa en Android, y el que separa una app que IT tolera de una que IT quiere.

Las managed configurations —antes llamadas app restrictions— permiten que el administrador fije ajustes de tu app desde la consola del EMM, sin tocar código y sin pedirle nada al usuario: qué URLs se permiten, si se sincroniza solo por Wi-Fi, qué servidor se usa, qué funciones se apagan.

Se declaran en dos pasos. En el manifiesto:

<application>
  <meta-data
    android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />
</application>

Y en res/xml/app_restrictions.xml:

<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
  <restriction
    android:key="downloadOnCellular"
    android:title="@string/download_on_cell_title"
    android:restrictionType="bool"
    android:description="@string/download_on_cell_description"
    android:defaultValue="true" />
</restrictions>

Los tipos disponibles: bool, string, integer, choice, multi-select, hidden y bundle_array para configuraciones anidadas —listas de servidores, de cuentas, de perfiles VPN— desde API 23.

En ejecución se leen con RestrictionsManager:

val mgr = getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager
val restrictions: Bundle = mgr.applicationRestrictions

val puedeUsarDatos = if (restrictions.containsKey("downloadOnCellular")) {
    restrictions.getBoolean("downloadOnCellular")
} else {
    valorPorDefecto
}

Tres trampas documentadas, y las tres muerden en producción:

  • Las claves no se localizan. Un solo app_restrictions.xml, con claves literales. Nada de versiones por idioma.
  • Que hayas declarado un defaultValue no significa que la clave esté en el bundle. Si el administrador no la ha fijado, no viene. Hay que comprobar containsKey siempre, como arriba.
  • No llames a getApplicationRestrictions() a cada rato. Lee de almacenamiento. Una vez en onResume() y a cachear.

Escuchar los cambios sin romper la app

Cuando el administrador cambia un ajuste, el sistema emite ACTION_APPLICATION_RESTRICTIONS_CHANGED. Y aquí está el detalle que hace perder tardes enteras: ese broadcast solo funciona con registro dinámico. Un receiver declarado en el manifiesto no se entera.

val filtro = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED)
val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        aplicar(mgr.applicationRestrictions)
    }
}
registerReceiver(receiver, filtro)

Y se da de baja al pausar la app. Si además quieres que el administrador vea en su consola si la configuración se aplicó o falló, eso son los keyed app states: el canal por el que la app le devuelve estado al EMM. Es la diferencia entre "he mandado el ajuste y espero que haya ido" y "veo que fue".

Antes de escribir la primera línea

Cinco preguntas, todas de la semana uno:

  1. ¿Qué EMM usa el cliente y soporta el iframe de managed Google Play?
  2. ¿La cuenta de Play Console va a nombre del cliente?
  3. ¿El applicationId está en el dominio del cliente?
  4. ¿Existe alguna posibilidad de que esta app acabe siendo pública? Si la hay, la app privada es el camino equivocado.
  5. ¿Qué debería poder cambiar IT sin una nueva versión? Eso es la lista de managed configurations, y se diseña, no se improvisa.

Cuándo no usar una app privada

  • Si algún día va al mercado. No se convierte. Publica pública y restringe el acceso dentro de la app.
  • Si el cliente no tiene EMM. Sin managed Google Play no hay canal privado; el equivalente es distribuir por enlace y poner tú la barrera de identidad.
  • Si esperas las comprobaciones de Google como red de seguridad. No las hay: las apps privadas no pasan los mismos controles.
  • Si la propiedad de la cuenta no está resuelta. Publicar antes de eso es firmar una dependencia que después no se deshace.

Si estás montando el despliegue interno de una app corporativa y las dos plataformas tienen que salir a la vez, eso es exactamente lo que ordenamos en la primera fase de un proyecto de Flutter para empresas: un solo código, dos canales de distribución que no se parecen en nada.


Fuentes primarias, consultadas el 14 de agosto de 2026: apps privadas en managed Google Play, publicar apps privadas desde Play Console y managed configurations en la documentación de Android.