Modifications de comportement : applications ciblant Android 14 ou version ultérieure

Comme les versions précédentes, Android 14 apporte des modifications de comportement pouvant affecter votre application. Les modifications de comportement suivantes s'appliquent exclusivement aux applications qui ciblent Android 14 (niveau d'API 34) ou version ultérieure. Si votre application cible Android 14 ou une version ultérieure, vous devez la modifier pour qu'elle prenne en charge ces comportements, le cas échéant.

Veillez également à consulter la liste des modifications de comportement qui affectent toutes les applications exécutées sur Android 14, peu importe la targetSdkVersion de l'application.

Fonctionnalité de base

Le type de service au premier plan doit être indiqué

Si votre application cible Android 14 (niveau d'API 34) ou une version ultérieure, elle doit spécifier au moins un type de service de premier plan pour chaque service de premier plan. Vous devez choisir un type de service de premier plan qui représente le cas d'utilisation de votre application. Le système s'attend à ce que des services de premier plan ayant un type particulier répondent à un cas d'utilisation particulier.

Si un cas d'utilisation dans votre application n'est associé à aucun de ces types, il est fortement recommandé de migrer votre logique pour utiliser WorkManager ou les tâches de transfert de données déclenchées par l'utilisateur.

Application de l'autorisation BLUETOOTH_CONNECT dans BluetoothAdapter

Android 14 applique l'autorisation BLUETOOTH_CONNECT lors de l'appel de la méthode BluetoothAdapter getProfileConnectionState() pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure.

Cette méthode nécessitait déjà l'autorisation BLUETOOTH_CONNECT, mais elle n'était pas appliquée. Assurez-vous que votre application déclare BLUETOOTH_CONNECT dans le fichier AndroidManifest.xml de votre application, comme indiqué dans l'extrait de code suivant, et vérifiez qu'un utilisateur a accordé l'autorisation avant d'appeler getProfileConnectionState.

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

Mises à jour OpenJDK 17

Android 14 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases, including both library updates and Java 17 language support for app and platform developers.

A few of these changes can affect app compatibility:

  • Changes to regular expressions: Invalid group references are now disallowed to more closely follow the semantics of OpenJDK. You might see new cases where an IllegalArgumentException is thrown by the java.util.regex.Matcher class, so make sure to test your app for areas that use regular expressions. To enable or disable this change while testing, toggle the DISALLOW_INVALID_GROUP_REFERENCE flag using the compatibility framework tools.
  • UUID handling: The java.util.UUID.fromString() method now does more strict checks when validating the input argument, so you might see an IllegalArgumentException during deserialization. To enable or disable this change while testing, toggle the ENABLE_STRICT_VALIDATION flag using the compatibility framework tools.
  • ProGuard issues: In some cases, the addition of the java.lang.ClassValue class causes an issue if you try to shrink, obfuscate, and optimize your app using ProGuard. The problem originates with a Kotlin library that changes runtime behaviour based on whether Class.forName("java.lang.ClassValue") returns a class or not. If your app was developed against an older version of the runtime without the java.lang.ClassValue class available, then these optimizations might remove the computeValue method from classes derived from java.lang.ClassValue.

JobScheduler renforce le comportement des rappels et du réseau

Depuis son lancement, JobScheduler s'attend à ce que votre application renvoie une valeur de onStartJob ou onStopJob dans les quelques secondes qui suivent. Avant Android 14, Si une tâche s'exécute trop longtemps, elle est arrêtée et échoue en mode silencieux. Si votre application cible Android 14 (niveau d'API 34) ou une version ultérieure et que dépasse le temps accordé sur le thread principal, l'application déclenche une erreur ANR avec le message d'erreur "Aucune réponse à onStartJob" ou "Aucune réponse à onStopJob."

Cette erreur ANR peut être due à deux scénarios: 1. Des tâches bloquent le thread principal, empêchant les rappels onStartJob ou onStopJob de s'exécuter et de se terminer dans le délai prévu. 2. Le développeur exécute une tâche bloquante dans le rappel JobScheduler onStartJob ou onStopJob, ce qui empêche le rappel de se terminer dans le délai prévu.

Pour résoudre le problème n° 1, vous devez déboguer davantage ce qui bloque le thread principal lorsque l'erreur ANR se produit, vous pouvez le faire ApplicationExitInfo#getTraceInputStream() pour obtenir la pierre tombale trace lorsque l'erreur ANR se produit. Si vous parvenez à reproduire manuellement l'ANR, vous pouvez enregistrer une trace système et l'inspecter à l'aide de l'une des méthodes Android Studio ou Perfetto pour mieux comprendre ce qui fonctionne le thread principal lorsque l'erreur ANR se produit. Notez que cela peut se produire lorsque vous utilisez directement l'API JobScheduler. ou en utilisant WorkManager de la bibliothèque Androidx.

Pour résoudre le problème 2, envisagez de migrer vers WorkManager, qui permet d'encapsuler tout traitement dans onStartJob ou onStopJob dans un thread asynchrone.

JobScheduler introduit également une exigence pour déclarer le Autorisation ACCESS_NETWORK_STATE si vous utilisez setRequiredNetworkType ou setRequiredNetwork. Si votre application ne déclare pas l'autorisation ACCESS_NETWORK_STATE lors de la planification de la tâche et qu'elle cible Android 14 ou version ultérieure, une erreur SecurityException s'affiche.

API de lancement des cartes

Pour les applications ciblant l'âge de 14 ans ou plus, TileService#startActivityAndCollapse(Intent) est obsolète et génère désormais une exception lorsqu'elle est appelée. Si votre application lance des activités à partir de cartes, utilisez plutôt TileService#startActivityAndCollapse(PendingIntent).

Confidentialité

Accès partiel aux photos et vidéos

Android 14 introduit l'accès aux photos sélectionnées, qui permet aux utilisateurs d'autoriser des applications à accéder à des images et des vidéos spécifiques de leur bibliothèque, plutôt que d'accorder l'accès à tous les contenus multimédias d'un type donné.

Cette modification n'est activée que si votre application cible Android 14 (niveau d'API 34) ou version ultérieure. Si vous n'utilisez pas encore le sélecteur de photos, nous vous recommandons de le mettre en œuvre dans votre application pour offrir une expérience cohérente de sélection d'images et de vidéos, tout en améliorant la confidentialité des utilisateurs sans avoir à demander d'autorisations de stockage.

Si vous gérez votre propre sélecteur de galerie à l'aide d'autorisations de stockage et que vous devez garder un contrôle total sur votre implémentation, adaptez votre implémentation pour utiliser la nouvelle autorisation READ_MEDIA_VISUAL_USER_SELECTED. Si votre application n'utilise pas la nouvelle autorisation, le système l'exécute en mode de compatibilité.

Expérience utilisateur

Notifications d'intent plein écran sécurisées

Avec Android 11 (niveau d'API 30), toutes les applications pouvaient utiliser Notification.Builder.setFullScreenIntent pour envoyer des intents en plein écran lorsque le téléphone était verrouillé. Vous pouvez l'accorder automatiquement lors de l'installation de l'application en déclarant l'autorisation USE_FULL_SCREEN_INTENT dans le fichier AndroidManifest.

Les notifications d'intent plein écran sont conçues pour les notifications à priorité très élevée nécessitant l'attention immédiate de l'utilisateur, comme les appels entrants ou les paramètres d'alarme configurés par l'utilisateur. Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, les applications autorisées à utiliser cette autorisation sont limitées à celles qui proposent uniquement des appels et des alarmes. Le Google Play Store révoque les autorisations USE_FULL_SCREEN_INTENT par défaut pour toutes les applications qui ne correspondent pas à ce profil. La date limite pour appliquer ces modifications de stratégie est le 31 mai 2024.

Cette autorisation reste activée pour les applications installées sur le téléphone avant que l'utilisateur passe à Android 14. Les utilisateurs peuvent activer et désactiver cette autorisation.

Vous pouvez utiliser la nouvelle API NotificationManager.canUseFullScreenIntent pour vérifier si votre application dispose de l'autorisation. Sinon, elle peut utiliser le nouvel intent ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT pour ouvrir la page des paramètres permettant aux utilisateurs d'accorder l'autorisation.

Sécurité

Restrictions concernant les intents implicites et en attente

For apps targeting Android 14 (API level 34) or higher, Android restricts apps from sending implicit intents to internal app components in the following ways:

  • Implicit intents are only delivered to exported components. Apps must either use an explicit intent to deliver to unexported components, or mark the component as exported.
  • If an app creates a mutable pending intent with an intent that doesn't specify a component or package, the system throws an exception.

These changes prevent malicious apps from intercepting implicit intents that are intended for use by an app's internal components.

For example, here is an intent filter that could be declared in your app's manifest file:

<activity
    android:name=".AppActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

If your app tried to launch this activity using an implicit intent, an ActivityNotFoundException exception would be thrown:

Kotlin

// Throws an ActivityNotFoundException exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))

Java

// Throws an ActivityNotFoundException exception when targeting Android 14.
context.startActivity(new Intent("com.example.action.APP_ACTION"));

To launch the non-exported activity, your app should use an explicit intent instead:

Kotlin

// This makes the intent explicit.
val explicitIntent =
        Intent("com.example.action.APP_ACTION")
explicitIntent.apply {
    package = context.packageName
}
context.startActivity(explicitIntent)

Java

// This makes the intent explicit.
Intent explicitIntent =
        new Intent("com.example.action.APP_ACTION")
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);

Les broadcasts receivers enregistrés lors de l'exécution doivent spécifier le comportement d'exportation

Les applications et les services qui ciblent Android 14 (niveau d'API 34) ou version ultérieure et utilisent des récepteurs enregistrés en contexte doivent spécifier un indicateur pour indiquer si le récepteur doit être exporté ou non vers toutes les autres applications de l'appareil: RECEIVER_EXPORTED ou RECEIVER_NOT_EXPORTED, respectivement. Cette exigence permet de protéger les applications contre les failles de sécurité en exploitant les fonctionnalités pour ces récepteurs introduites dans Android 13.

Exception pour les récepteurs qui ne reçoivent que des annonces du système

Si votre application n'enregistre un récepteur que pour les annonces du système via des méthodes Context#registerReceiver, telles que Context#registerReceiver(), elle ne doit pas spécifier d'indicateur lors de l'enregistrement du récepteur.

Chargement de code dynamique plus sécurisé

If your app targets Android 14 (API level 34) or higher and uses Dynamic Code Loading (DCL), all dynamically-loaded files must be marked as read-only. Otherwise, the system throws an exception. We recommend that apps avoid dynamically loading code whenever possible, as doing so greatly increases the risk that an app can be compromised by code injection or code tampering.

If you must dynamically load code, use the following approach to set the dynamically-loaded file (such as a DEX, JAR, or APK file) as read-only as soon as the file is opened and before any content is written:

Kotlin

val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly()
    // Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)

Java

File jar = new File("DYNAMICALLY_LOADED_FILE.jar");
try (FileOutputStream os = new FileOutputStream(jar)) {
    // Set the file to read-only first to prevent race conditions
    jar.setReadOnly();
    // Then write the actual file content
} catch (IOException e) { ... }
PathClassLoader cl = new PathClassLoader(jar, parentClassLoader);

Handle dynamically-loaded files that already exist

To prevent exceptions from being thrown for existing dynamically-loaded files, we recommend deleting and recreating the files before you try to dynamically load them again in your app. As you recreate the files, follow the preceding guidance for marking the files read-only at write time. Alternatively, you can re-label the existing files as read-only, but in this case, we strongly recommend that you verify the integrity of the files first (for example, by checking the file's signature against a trusted value), to help protect your app from malicious actions.

Restrictions supplémentaires concernant le démarrage d'activités en arrière-plan

Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, le système limite davantage le moment où les applications sont autorisées à démarrer des activités en arrière-plan:

  • Lorsqu'une application envoie un PendingIntent à l'aide de PendingIntent#send() ou de méthodes similaires, elle doit l'activer si elle souhaite accorder ses propres privilèges de lancement d'activité en arrière-plan pour démarrer l'intent en attente. Pour l'activer, l'application doit transmettre un bundle ActivityOptions avec setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED).
  • Lorsqu'une application visible associe un service à une autre application en arrière-plan à l'aide de la méthode bindService(), elle doit désormais l'activer si elle souhaite accorder ses propres privilèges de lancement d'activité en arrière-plan au service lié. Pour l'activer, l'application doit inclure l'indicateur BIND_ALLOW_ACTIVITY_STARTS lors de l'appel de la méthode bindService().

Ces modifications étendent l'ensemble de restrictions existant pour protéger les utilisateurs en empêchant les applications malveillantes d'utiliser les API de manière abusive pour lancer des activités perturbatrices en arrière-plan.

Traversée de répertoire ZIP

Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, Android empêche la faille de traversée de répertoires ZIP de la manière suivante : ZipFile(String) et ZipInputStream.getNextEntry() génèrent une erreur ZipException si les noms des entrées de fichiers ZIP contiennent ".." ou commencent par "/".

Les applications peuvent désactiver cette validation en appelant dalvik.system.ZipPathValidator.clearCallback().

Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, une SecurityException est générée par MediaProjection#createVirtualDisplay dans l'un des scénarios suivants:

Votre application doit demander à l'utilisateur de donner son consentement avant chaque session de capture. Une session de capture unique correspond à un appel unique sur MediaProjection#createVirtualDisplay, et chaque instance MediaProjection ne doit être utilisée qu'une seule fois.

Gérer les modifications de configuration

Si votre application doit appeler MediaProjection#createVirtualDisplay pour gérer les modifications de configuration (telles que l'orientation ou la taille de l'écran), vous pouvez suivre ces étapes pour mettre à jour VirtualDisplay pour l'instance MediaProjection existante:

  1. Appelez VirtualDisplay#resize avec les nouvelles largeurs et hauteurs.
  2. Fournissez un nouveau Surface avec de nouvelles largeurs et hauteurs définies pour VirtualDisplay#setSurface.

Enregistrer un rappel

Votre application doit enregistrer un rappel pour gérer les cas où l'utilisateur ne donne pas son consentement pour poursuivre une session de capture. Pour ce faire, implémentez Callback#onStop et demandez à votre application de publier toutes les ressources associées (telles que VirtualDisplay et Surface).

Si votre application n'enregistre pas ce rappel, MediaProjection#createVirtualDisplay génère une exception IllegalStateException lorsque votre application l'appelle.

Mise à jour des restrictions non SDK

Android 14 inclut des listes à jour d'interfaces non SDK limitées grâce à la collaboration avec les développeurs Android et aux derniers tests internes. Dans la mesure du possible, nous nous assurons que des alternatives publiques sont disponibles avant de limiter les interfaces non SDK.

Si votre application ne cible pas Android 14, certaines de ces modifications ne vous affecteront peut-être pas immédiatement. Cependant, bien que vous puissiez actuellement utiliser certaines interfaces non SDK (en fonction du niveau d'API cible de votre application), l'utilisation d'un champ ou d'une méthode non SDK présente toujours un risque élevé d'endommager votre application.

Si vous n'êtes pas sûr que votre application utilise des interfaces non SDK, vous pouvez tester votre application pour le savoir. Si votre application repose sur des interfaces non SDK, vous devriez commencer à planifier une migration vers des alternatives SDK. Nous comprenons néanmoins que certaines applications ont des cas d'utilisation valides pour utiliser des interfaces non SDK. Si vous ne trouvez pas d'alternative à l'utilisation d'une interface non SDK pour une fonctionnalité de votre application, vous devriez demander une nouvelle API publique.

Pour en savoir plus sur les modifications apportées à cette version d'Android, consultez Mises à jour des restrictions des interfaces non SDK dans Android 14. Pour en savoir plus sur les interfaces non SDK de manière générale, consultez la section Restrictions concernant les interfaces non SDK.