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é
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 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 thejava.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 theDISALLOW_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 anIllegalArgumentException
during deserialization. To enable or disable this change while testing, toggle theENABLE_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 whetherClass.forName("java.lang.ClassValue")
returns a class or not. If your app was developed against an older version of the runtime without thejava.lang.ClassValue
class available, then these optimizations might remove thecomputeValue
method from classes derived fromjava.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
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 limité aux photos et 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 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, seules les applications qui proposent des fonctionnalités d'appel et d'alarmes peuvent utiliser cette autorisation. 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 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, votre application peut utiliser le nouvel intent ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT
pour afficher la page des paramètres où les utilisateurs peuvent 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 ou 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.
Par exemple, voici 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 ActivityNotFoundException
sera générée :
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"));
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é
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 restreint davantage le moment où les applications sont autorisées à lancer des activités en arrière-plan:
- Lorsqu'une application envoie un
PendingIntent
à l'aide dePendingIntent#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éclencher l'intent en attente. Pour l'activer, l'application doit transmettre un bundleActivityOptions
avecsetPendingIntentBackgroundActivityStartMode(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é d'arrière-plan au service lié. Pour l'activer, l'application doit inclure l'indicateurBIND_ALLOW_ACTIVITY_STARTS
lors de l'appel de la méthodebindService()
.
Ces modifications étendent l'ensemble de restrictions existant afin de protéger les utilisateurs en empêchant les applications malveillantes d'utiliser les API de manière abusive pour démarrer des activités d'interruption 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épertoire ZIP de la manière suivante : ZipFile(String)
et ZipInputStream.getNextEntry()
génèrent un 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()
.
Consentement de l'utilisateur requis pour chaque session de capture MediaProjection
Pour les applications ciblant Android 14 (niveau d'API 34) ou version ultérieure, une exception SecurityException
est générée par MediaProjection#createVirtualDisplay
dans l'un des scénarios suivants:
- Votre application met en cache le
Intent
renvoyé parMediaProjectionManager#createScreenCaptureIntent
et le transmet plusieurs fois àMediaProjectionManager#getMediaProjection
. - Votre application appelle
MediaProjection#createVirtualDisplay
plusieurs fois sur la même instanceMediaProjection
.
Votre application doit demander à l'utilisateur de donner son consentement avant chaque session de capture. Une session de capture unique correspond à une seule invocation 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:
- Appelez
VirtualDisplay#resize
avec la nouvelle largeur et la nouvelle hauteur. - Fournissez un nouvel élément
Surface
avec la nouvelle largeur et la nouvelle hauteur àVirtualDisplay#setSurface
.
Enregistrer un rappel
Votre application doit enregistrer un rappel pour gérer les cas où l'utilisateur ne donne pas son autorisation pour poursuivre une session de capture. Pour ce faire, implémentez Callback#onStop
et demandez à votre application de libérer 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 la section Mises à jour des restrictions d'interface non SDK dans Android 14. Pour en savoir plus sur les interfaces non SDK en général, consultez la section Restrictions concernant les interfaces non SDK.