android:exported: salvando del crash en Android 12 con Kotlin

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué su aplicación dejó de ejecutarse repentinamente en Android 12?

\n\n

¿Actualizó targetSdkVersion a 31 o superior, compiló el APK, lo ejecuta y obtiene un crash con un mensaje misterioso?

\n\n
android:exported needs to be explicitly specified for <activity>. \nApps targeting Android 12 and higher are required to specify \nan explicit value for `android:exported` when the corresponding \ncomponent has an intent filter defined.
\n\n

¿Le suena familiar? Si ha mirado en Stack Overflow, habrá visto que esta pregunta ha acumulado miles de visitas. Los desarrolladores están en pánico y los usuarios, desconcertados. Pero no se apresure a eliminar el proyecto. En este artículo, entenderemos qué es este android:exported, por qué Google endureció los requisitos y cómo solucionar rápidamente el error en Kotlin. ¡Allá vamos!

\n\n

¿Qué es android:exported y para qué sirve?

\n\n

android:exported es un atributo en AndroidManifest.xml que controla si otras aplicaciones (o el propio sistema) pueden iniciar su componente (Activity, Service, BroadcastReceiver o ContentProvider). Si el atributo está establecido en true, el componente es accesible desde el exterior. Si es false, solo dentro de su aplicación.

\n\n

Antes de Android 12 (API 31), este atributo era opcional. Si no lo especificaba, el sistema decidía por sí mismo si el componente era accesible:

\n
    \n
  • Si la Activity tiene un <intent-filter>, el sistema consideraba que exported = true.
  • \n
  • Si no tiene filtro, exported = false.
  • \n
\n\n

Pero este comportamiento "automático" es un agujero de seguridad. Imagine: escribió una Activity para iniciar sesión en la aplicación y accidentalmente agregó un intent-filter. Cualquier aplicación de terceros puede invocar su Activity y robar tokens. Por eso Google decidió: a partir de Android 12, debe especificar explícitamente android:exported para cualquier componente que tenga un <intent-filter>.

\n\n

¿Cómo se ve el error en la práctica?

\n\n

Supongamos que tiene un manifiesto simple:

\n\n
<activity android:name=".MainActivity">\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n</activity>
\n\n

Si targetSdkVersion = 31 o superior, obtendrá un error al compilar o ejecutar. La solución es agregar android:exported:

\n\n
<activity \n    android:name=".MainActivity"\n    android:exported="true">\n    <intent-filter>\n        <action android:name="android.intent.action.MAIN" />\n        <category android:name="android.intent.category.LAUNCHER" />\n    </intent-filter>\n</activity>
\n\n

Para la Activity principal que se inicia desde el escritorio, exported debe ser true; de lo contrario, el launcher no podrá abrirla.

\n\n

Cómo corregirlo correctamente: instrucciones paso a paso

\n\n

Paso 1. Abra AndroidManifest.xml

\n

Encuentre todos los <activity>, <service>, <receiver> y <provider> que tengan un <intent-filter>. Para cada uno de ellos, agregue android:exported.

\n\n

Paso 2. Determine el valor del atributo

\n

Aquí hay una regla simple:

\n
    \n
  • true — si el componente debe ser accesible desde otras aplicaciones (por ejemplo, Activity para iniciar sesión con Google, BroadcastReceiver para eventos del sistema, Activity principal con filtro LAUNCHER).
  • \n
  • false — si el componente se usa solo dentro de su aplicación (por ejemplo, una Activity que se abre al presionar un botón en su propio código).
  • \n
\n\n

Paso 3. Ejemplos para diferentes escenarios

\n\n

Escenario 1: Activity principal (Launcher)

\n
                

Blogs

Book Recommendations