Pourquoi votre application a soudainement cessé de fonctionner sur Android 12 ?
\n\nVous avez mis à jour targetSdkVersion vers 31 ou une version supérieure, compilé l'APK, lancé — et vous obtenez un crash avec un message mystérieux :
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\nCela vous dit quelque chose ? Si vous avez jeté un œil sur Stack Overflow, vous avez vu que cette question a rassemblé des milliers de vues. Les développeurs paniquent, et les utilisateurs sont perplexes. Mais ne vous précipitez pas pour supprimer votre projet. Dans cet article, nous allons comprendre ce qu'est cette bête android:exported, pourquoi Google a renforcé les exigences, et comment corriger rapidement l'erreur en Kotlin. C'est parti !
Qu'est-ce que android:exported et à quoi ça sert ?
\n\nandroid:exported est un attribut dans AndroidManifest.xml qui contrôle si d'autres applications (ou le système lui-même) peuvent lancer votre composant (Activity, Service, BroadcastReceiver ou ContentProvider). Si l'attribut est défini sur true — le composant est accessible de l'extérieur. Si false — uniquement à l'intérieur de votre application.
Avant Android 12 (API 31), cet attribut était optionnel. Si vous ne le spécifiiez pas, le système décidait lui-même si le composant était accessible :
\n- \n
- Si l'Activity a un
<intent-filter>— le système considérait queexported = true. \n - Si pas de filtre —
exported = false. \n
Mais ce comportement « automatique » est une faille de sécurité. Imaginez : vous avez écrit une Activity pour la connexion à l'application et vous avez accidentellement ajouté un intent-filter. N'importe quelle application tierce peut appeler votre Activity et voler les jetons. C'est pourquoi Google a décidé : à partir d'Android 12, vous devez explicitement spécifier android:exported pour tout composant qui a un <intent-filter>.
À quoi ressemble l'erreur en pratique ?
\n\nSupposons que vous ayez un manifeste 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\nSi targetSdkVersion = 31 ou supérieur, vous obtiendrez une erreur lors de la compilation ou de l'exécution. La solution est d'ajouter android:exported :
<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\nPour l'Activity principale, qui est lancée depuis le bureau, exported doit être true — sinon le lanceur ne pourra pas l'ouvrir.
Comment corriger correctement : guide étape par étape
\n\nÉtape 1. Ouvrez AndroidManifest.xml
\nRecherchez tous les <activity>, <service>, <receiver> et <provider> qui ont un <intent-filter>. Pour chacun d'eux, ajoutez android:exported.
Étape 2. Déterminez la valeur de l'attribut
\nVoici une règle simple :
\n- \n
- true — si le composant doit être accessible depuis d'autres applications (par exemple, Activity pour la connexion via Google, BroadcastReceiver pour les événements système, Activity principale avec le filtre LAUNCHER). \n
- false — si le composant est utilisé uniquement à l'intérieur de votre application (par exemple, Activity qui s'ouvre en appuyant sur un bouton dans votre propre code). \n
Étape 3. Exemples pour différents scénarios
\n\nScénario 1 : Activity principale (Launcher)
\n