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

Comme les versions précédentes, Android 14 inclut des modifications de comportement susceptibles d'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 prendre en charge ces comportements correctement, le cas échéant.

Veillez également à consulter la liste des modifications de comportement qui affectent toutes les applications exécutées sous Android 14, quel que soit le targetSdkVersion de l'application.

Fonctionnalité de base

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

If your app targets Android 14 (API level 34) or higher, it must specify at least one foreground service type for each foreground service within your app. You should choose a foreground service type that represents your app's use case. The system expects foreground services that have a particular type to satisfy a particular use case.

If a use case in your app isn't associated with any of these types, it's strongly recommended that you migrate your logic to use WorkManager or user-initiated data transfer jobs.

Application de l'autorisation BLUETOOTH_CONNECT dans BluetoothAdapter

Android 14 enforces the BLUETOOTH_CONNECT permission when calling the BluetoothAdapter getProfileConnectionState() method for apps targeting Android 14 (API level 34) or higher.

This method already required the BLUETOOTH_CONNECT permission, but it was not enforced. Make sure your app declares BLUETOOTH_CONNECT in your app's AndroidManifest.xml file as shown in the following snippet and check that a user has granted the permission before calling getProfileConnectionState.

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

Mises à jour OpenJDK 17

Android 14 poursuit le travail d'actualisation des principales bibliothèques Android afin de s'adapter aux fonctionnalités des dernières versions d'OpenJDK LTS, y compris les mises à jour de la bibliothèque et la compatibilité avec le langage Java 17 pour les développeurs d'applications et de plates-formes.

Quelques modifications peuvent avoir un impact sur la compatibilité des applications :

  • Modifications apportées aux expressions régulières : les références de groupe non valides sont désormais interdites afin de suivre de manière plus fidèle la sémantique d'OpenJDK. Vous pouvez rencontrer de nouveaux cas où une IllegalArgumentException est générée par la classe java.util.regex.Matcher. Veillez donc à tester votre application pour les éléments qui utilisent des expressions régulières. Pour activer ou désactiver cette modification lors des tests, activez/désactivez l'indicateur DISALLOW_INVALID_GROUP_REFERENCE à l'aide des outils du framework de compatibilité.
  • Gestion de l'UUID : la méthode java.util.UUID.fromString() effectue désormais des contrôles plus stricts lors de la validation de l'argument d'entrée. Vous pouvez donc voir une IllegalArgumentException pendant la désérialisation. Pour activer ou désactiver cette modification lors des tests, activez/désactivez l'indicateur ENABLE_STRICT_VALIDATION à l'aide des outils du framework de compatibilité.
  • Problèmes avec ProGuard : dans certains cas, l'ajout de la classe java.lang.ClassValue cause un problème si vous essayez de réduire, d'obscurcir ou d'optimiser votre application avec ProGuard. Le problème provient d'une bibliothèque Kotlin qui modifie le comportement d'exécution selon que Class.forName("java.lang.ClassValue") renvoie une classe ou non. Si votre application a été développée avec une ancienne version de l'environnement d'exécution sans la classe java.lang.ClassValue disponible, ces optimisations peuvent supprimer la méthode computeValue des classes dérivées de java.lang.ClassValue.

JobScheduler renforce le comportement des rappels et du réseau

Depuis son lancement, JobScheduler s'attend à ce que votre application soit renvoyée de onStartJob ou onStopJob en quelques secondes. Avant Android 14, si une tâche s'exécute trop longtemps, elle s'arrête et échoue en mode silencieux. Si votre application cible Android 14 (niveau d'API 34) ou une version ultérieure et dépasse le délai accordé sur le thread principal, elle déclenche une erreur ANR avec le message d'erreur "Aucune réponse à onStartJob" ou "Aucune réponse à onStopJob". Envisagez de migrer vers WorkManager, qui prend en charge le traitement asynchrone ou la migration des tâches lourdes vers un thread d'arrière-plan.

JobScheduler introduit également une exigence permettant de déclarer l'autorisation ACCESS_NETWORK_STATE si vous utilisez une contrainte 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, elle génère une erreur SecurityException.

Tiles lance l'API

For apps targeting 14 and higher, TileService#startActivityAndCollapse(Intent) is deprecated and now throws an exception when called. If your app launches activities from tiles, use TileService#startActivityAndCollapse(PendingIntent) instead.

Confidentialité

Accès partiel aux photos et aux vidéos

Android 14 introduces Selected Photos Access, which allows users to grant apps access to specific images and videos in their library, rather than granting access to all media of a given type.

This change is only enabled if your app targets Android 14 (API level 34) or higher. If you don't use the photo picker yet, we recommend implementing it in your app to provide a consistent experience for selecting images and videos that also enhances user privacy without having to request any storage permissions.

If you maintain your own gallery picker using storage permissions and need to maintain full control over your implementation, adapt your implementation to use the new READ_MEDIA_VISUAL_USER_SELECTED permission. If your app doesn't use the new permission, the system runs your app in a compatibility mode.

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

Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, Android empêche les applications d'envoyer des intents implicites à des composants d'application internes comme suit:

  • Les intents implicites ne sont transmis qu'aux composants exportés. Les applications doivent utiliser un intent explicite pour transmettre les composants non exportés, ou marquer le composant comme exporté.
  • Si une application crée un intent en attente modifiable avec un intent qui ne spécifie pas de composant ni de package, le système génère une exception.

Ces modifications empêchent les applications malveillantes d'intercepter les intents implicites destinés à être utilisés par les composants internes d'une application.

Voici par exemple un filtre d'intent qui peut être déclaré dans le fichier manifeste de votre application :

<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>

Si votre application a tenté de lancer cette activité à l'aide d'un intent implicite, une exception sera générée :

Kotlin

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

Java

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

Pour lancer l'activité non exportée, votre application doit utiliser un intent explicite :

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

Apps and services that target Android 14 (API level 34) or higher and use context-registered receivers are required to specify a flag to indicate whether or not the receiver should be exported to all other apps on the device: either RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED, respectively. This requirement helps protect apps from security vulnerabilities by leveraging the features for these receivers introduced in Android 13.

Exception for receivers that receive only system broadcasts

If your app is registering a receiver only for system broadcasts through Context#registerReceiver methods, such as Context#registerReceiver(), then it shouldn't specify a flag when registering the receiver.

Chargement de code dynamique plus sécurisé

Si votre application cible Android 14 (niveau d'API 34) ou version ultérieure et utilise le chargement dynamique de code (DCL), tous les fichiers chargés dynamiquement doivent être marqués en lecture seule. Sinon, le système génère une exception. Nous vous recommandons d'éviter le chargement dynamique de code dans la mesure du possible, car cela augmente considérablement le risque qu'une application soit compromise par une injection ou une falsification de code.

Si vous devez charger le code de manière dynamique, utilisez l'approche suivante pour définir le fichier chargé dynamiquement (tel qu'un fichier DEX, JAR ou APK) en lecture seule dès que le fichier est ouvert et avant toute écriture :

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);

Gérer les fichiers chargés dynamiquement préexistants

Pour éviter de générer des exceptions pour les fichiers existants chargés dynamiquement, nous vous recommandons de supprimer et de recréer les fichiers avant de réessayer de les charger dynamiquement dans votre application. Lorsque vous recréez les fichiers, suivez les instructions précédentes pour les marquer en lecture seule au moment de l'écriture. Vous pouvez également libeller à nouveau les fichiers existants en lecture seule, mais dans ce cas, nous vous recommandons vivement de vérifier d'abord l'intégrité des fichiers (par exemple, en vérifiant la signature du fichier correspond à une valeur de confiance), pour protéger votre application des actions malveillantes.

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

For apps targeting Android 14 (API level 34) or higher, Android prevents the Zip Path Traversal Vulnerability in the following way: ZipFile(String) and ZipInputStream.getNextEntry() throws a ZipException if zip file entry names contain ".." or start with "/".

Apps can opt-out from this validation by calling 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 includes updated lists of restricted non-SDK interfaces based on collaboration with Android developers and the latest internal testing. Whenever possible, we make sure that public alternatives are available before we restrict non-SDK interfaces.

If your app does not target Android 14, some of these changes might not immediately affect you. However, while you can currently use some non-SDK interfaces (depending on your app's target API level), using any non-SDK method or field always carries a high risk of breaking your app.

If you are unsure if your app uses non-SDK interfaces, you can test your app to find out. If your app relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives. Nevertheless, we understand that some apps have valid use cases for using non-SDK interfaces. If you cannot find an alternative to using a non-SDK interface for a feature in your app, you should request a new public API.

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.