Cambios en el comportamiento: apps orientadas a Android 15 o versiones posteriores

Al igual que las versiones anteriores, Android 15 incluye cambios de comportamiento que podrían afectar a tu app. Los siguientes cambios se aplican exclusivamente a las apps orientadas a Android 15 o versiones posteriores. Si tu app está orientada a Android 15 o versiones posteriores, debes modificarla para que admita estos comportamientos correctamente, cuando corresponda.

Asegúrate de revisar también la lista de cambios de comportamiento que afectan a todas las apps que se ejecutan en Android 15, independientemente de la targetSdkVersion de tu app.

Funcionalidad principal

Android 15 modifica o expande varias capacidades principales del sistema Android.

Cambios en los servicios en primer plano

我们将对 Android 15 中的前台服务做出以下更改。

新增媒体处理前台服务类型

Android 15 引入了一种新的前台服务类型 mediaProcessing。此服务类型适用于对媒体文件进行转码等操作。例如,媒体应用可能下载音频文件,并且需要将其转换为其他格式才能播放。您可以使用 mediaProcessing 前台服务来确保即使应用在后台运行,转换也会继续进行。

如需详细了解 mediaProcessing 服务类型,请参阅 Android 15 前台服务类型变更

对启动前台服务的 BOOT_COMPLETED 广播接收器的限制

针对启动前台服务的 BOOT_COMPLETED 广播接收器存在新的限制。BOOT_COMPLETED 接收器不能启动以下类型的前台服务:

如果 BOOT_COMPLETED 接收器尝试启动任何此类前台服务,系统会抛出 ForegroundServiceStartNotAllowedException

Cambios en la capacidad de las apps para modificar el estado global del modo No interrumpir

Apps that target Android 15 can no longer change the global state or policy of Do Not Disturb (DND) on a device (either by modifying user settings, or turning off DND mode). Instead, apps must contribute an AutomaticZenRule, which the system combines into a global policy with the existing most-restrictive-policy-wins scheme. Calls to existing APIs that previously affected global state (setInterruptionFilter, setNotificationPolicy) result in the creation or update of an implicit AutomaticZenRule, which is toggled on and off depending on the call-cycle of those API calls.

Note that this change only affects observable behavior if the app is calling setInterruptionFilter(INTERRUPTION_FILTER_ALL) and expects that call to deactivate an AutomaticZenRule that was previously activated by their owners.

Cambios en OpenJDK 17

Android 15 会继续更新 Android 的核心库,以与最新 OpenJDK LTS 版本中的功能保持一致。

对于以 Android 15 为目标平台的应用,以下变更可能会影响应用兼容性:

  • 字符串格式设置 API 的变化:在使用以下 String.format()Formatter.format() API 时,现在对参数索引、标志、宽度和精度的验证更为严格:

    例如,使用参数索引 0 时(格式字符串中的 %0)会抛出以下异常:

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    在这种情况下,可以通过在格式字符串中使用 %1 的参数索引 1 来解决此问题。

  • 语言代码处理方面的变更:使用 Locale API 时,希伯来语、意第绪语和印度尼西亚语的语言代码不再转换为过时的形式(希伯来语:iw、意第绪语:ji 和印度尼西亚语:in)。在为其中一个语言区域指定语言代码时,请改用 ISO 639-1 中的代码:yi、Yid1(希伯来语):yiheid

  • 随机 int 序列变更:在 https://bugs.openjdk.org/browse/JDK-8301574 中做出更改后,以下 Random.ints() 方法现在返回的数字序列现在与 Random.nextInt() 方法不同:

    通常,此变更不会导致应用破坏行为,但您的代码不应期望从 Random.ints() 方法生成的序列与 Random.nextInt() 匹配。

Seguridad

Android 15 incluye cambios que promueven la seguridad del sistema para proteger a los usuarios y las apps de apps maliciosas.

Lanzamientos seguros de actividades en segundo plano

Android 15 protege a los usuarios de apps maliciosas y les brinda más control sobre sus dispositivos, ya que agregan cambios que evitan que las apps maliciosas en segundo plano lleven otras apps al primer plano, elevan sus privilegios y abusen de la interacción con los usuarios. Los inicios de actividades en segundo plano están restringidos desde Android 10 (nivel de API 29).

Bloquear el inicio de actividades en las apps que no coincidan con el UID superior de la pila

Las apps maliciosas pueden iniciar la actividad de otra app dentro de la misma tarea y, luego, superponerse sobre ellas, lo que crea la ilusión de ser esa app. Este ataque de “secuestro de tareas” omite las restricciones actuales de inicio en segundo plano porque todo ocurre dentro de la misma tarea visible. Para mitigar este riesgo, en Android 15, se agrega una marca que bloquea las apps que no coinciden con el UID superior de la pila para que no inicien actividades. Para habilitar todas las actividades de tu app, actualiza el atributo allowCrossUidActivitySwitchFromBelow en el archivo AndroidManifest.xml de la app:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

Otros cambios

Además de la restricción para la coincidencia de UID, también se incluyen estos otros cambios:

  • Cambia los creadores de PendingIntent para que bloqueen inicios de actividades en segundo plano de forma predeterminada. Esto ayuda a evitar que las apps creen accidentalmente un PendingIntent que podría ser abusado por actores maliciosos.
  • No coloques una app en primer plano, a menos que lo permita el remitente del PendingIntent. El objetivo de este cambio es evitar que apps maliciosas abusen de la capacidad de iniciar actividades en segundo plano. De forma predeterminada, las apps no pueden llevar la pila de tareas al primer plano, a menos que el creador permita privilegios de inicio de la actividad en segundo plano o que el remitente tenga privilegios de inicio de actividad en segundo plano.
  • Controla cómo la actividad superior de una pila de tareas puede completar su tarea. Si la actividad principal finaliza una tarea, Android regresará a la tarea que estuvo activa por última vez. Además, si una actividad que no es principal finaliza su tarea, Android regresará a la pantalla principal y no bloqueará el final de esa actividad no principal.
  • Evita iniciar actividades arbitrarias de otras apps en tu propia tarea. Este cambio evita que las apps maliciosas suplanten a los usuarios mediante la creación de actividades que parecen provenir de otras apps.
  • Bloquea las ventanas no visibles a fin de que no se consideren para el inicio de actividades en segundo plano. Esto ayuda a evitar que las apps maliciosas abusen de los inicios de actividades en segundo plano para mostrar contenido malicioso o no deseado a los usuarios.

Intents más seguros

Android 15 introduces new security measures to make intents safer and more robust. These changes are aimed at preventing potential vulnerabilities and misuse of intents that can be exploited by malicious apps. There are two main improvements to the security of intents in Android 15:

  • Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.
  • Intents must have actions: Intents without an action will no longer match any intent-filters. This means that intents used to start activities or services must have a clearly defined action.

Kotlin


fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .build()
    )
}

Java


public void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
            .detectUnsafeIntentLaunch()
            .build());
}

IU del sistema y experiencia del usuario

Android 15 incluye algunos cambios destinados a crear una experiencia del usuario más intuitiva y coherente.

Cambios en la inserción de ventana

En Android 15, habrá dos cambios relacionados con las inserciones de ventana. En la versión Beta 1, se aplicará de borde a borde. También hay próximos cambios de configuración, incluida la configuración predeterminada de las barras del sistema.

全面强制执行

Apps will be edge-to-edge by default on devices running Android 15 if the app is targeting Android 15.

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.


An app that targets Android 15 and is edge-to-edge on an Android 15 device. This app mostly uses Material 3 Compose Components that automatically apply insets. This screen is not negatively impacted by the Android 15 edge-to-edge enforcement.

This is a breaking change that might negatively impact your app's UI. The changes are as follows:

  • Gesture handle navigation bar
    • Transparent by default.
    • Bottom offset is disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor is deprecated and does not affect gesture navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced continues to have no effect on gesture navigation.
  • 3 button navigation
    • Opacity set to 80% by default, with color possibly matching the window background.
    • Bottom offset disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor is set to match the window background by default. The window background must be a color drawable for this default to apply. This API is deprecated but continues to affect three button navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced is true by default, which adds an 80% opaque background across three button navigation.
  • Status bar
    • Transparent by default.
    • The top offset is disabled so content will draw behind the status bar unless insets are applied.
    • setStatusBarColor and R.attr#statusBarColor are deprecated and have no effect on Android 15.
    • setStatusBarContrastEnforced and R.attr#statusBarContrastEnforced are deprecated but still have an effect on Android 15.
  • Display cutout
    • layoutInDisplayCutoutMode of non-floating windows must be LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. In Android 15 Beta 1, apps will crash with an IllegalArgumentException if using SHORT_EDGES, NEVER, or DEFAULT (e.g. LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT). In Android 15 Beta 2, SHORT_EDGES, NEVER and DEFAULT will be interpreted as ALWAYS so that users don't see a Black bar caused by the display cutout and appear edge-to-edge.

The following example shows an app before and after targeting Android 15, and before and after applying insets.

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.
An app that targets Android 15 and is edge-to-edge on an Android 15 device. However, many elements are now occluded by the status bar, 3-button navigation bar, or display cutout due to the Android 15 edge-to-edge enforcements. Occluded UI includes the Material 2 TopAppBar, FAB, and list items.
An app that targets Android 15, is edge to edge on an Android 15 device and applies insets so that UI is not occluded.

If your app:

  • is already edge-to-edge and applies insets, you are mostly unimpacted, except in the following scenarios. However, even if you feel you aren't impacted, we recommend you test your app.
    • You have a non-floating window, such as an Activity that uses SHORT_EDGES, NEVER or DEFAULT instead of LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. If your app crashes on launch, this may be due to your splashscreen. You can either upgrade the core splashscreen dependency to 1.2.0-alpha01 or later, set window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always, or test with Android 15 Beta 2 instead of Beta 1.
    • There may be lower traffic screens with occluded UI. Verify these less visited screens don't have occluded UI. Lower traffic screens include:
      • Onboarding or sign-in screens
      • Settings pages
  • is not edge-to-edge, you are most likely impacted. In addition to the scenarios for apps that are already edge-to-edge, you will need to consider the following:
    • If your app uses Material 3 Components (androidx.compose.material3 in compose, such as TopAppBar, BottomAppBar, and NavigationBar, these components are likely not impacted because they automatically handle insets.
    • If your app is using Material 2 Components (androidx.compose.material in Compose, these components don't automatically handle insets. However, you can get access to the insets and apply them manually. In androidx.compose.material 1.6.0 and later use the windowInsets parameter to apply the insets manually for BottomAppBar, TopAppBar, BottomNavigation, and NavigationRail. Likewise, use the contentWindowInsets parameter for Scaffold.
    • If your app uses Views and Material Components (com.google.android.material, most Views based Material Components such as BottomNavigationView, BottomAppBar, NavigationRailView, or NavigationView, handle insets and require no additional work. However, you will need to add android:fitsSystemWindows="true" if using AppBarLayout.
    • For custom Composables, apply the insets manually as padding. If your content is within a Scaffold, you may consume insets using Scaffold's padding values. Otherwise, apply padding using one of the WindowInsets.
    • If your app is using Views and BottomSheet, SideSheet or custom containers, apply padding using ViewCompat.setOnApplyWindowInsetsListener. For RecyclerView, apply padding using this listener and also add clipToPadding="false".
  • must offer custom background protection to three button navigation or the status bar, you app should place a composable or view behind the system bar using WindowInsets.Type#tappableElement() to get the three button navigation bar height or WindowInsets.Type#statusBars.

See the Edge to Edge Views and Edge to Edge Compose guides for additional considerations on applying insets.

The list of deprecated and disabled APIs are:

  • R.attr#statusBarColor
  • R.attr#navigationBarColor
  • R.attr#navigationBarDividerColor
  • Window#setDecorFitsSystemWindows
  • Window#setStatusBarColor
  • Window#setStatusBarContrastEnforced
  • Window#setNavigationBarColor
  • Window#setNavigationBarDividerColor
  • Window#getStatusBarColor
  • Window#getStatusBarContrastEnforced
  • Window#getNavigationBarColor
  • Window#getNavigationBarDividerColor

稳定配置

If your app targets Android 15 or higher, Configuration no longer excludes the system bars. If you use the screen size in the Configuration class for layout calculation, you should replace it with better alternatives like an appropriate ViewGroup, WindowInsets or WindowMetricsCalculator depending on your need.

Configuration has been available since API 1. It is typically obtained from Activity.onConfigurationChanged. It provides information like window density, orientation, and sizes. One important characteristic about the window sizes returned from Configuration is that it previously excluded the system bars.

The configuration size is typically used for resource selection, such as /res/layout-h500dp, and this is still a valid use case. However, using it for layout calculation has always been discouraged. If you do so, you should move away from it now. You should replace the use of Configuration with something more suitable depending on your use case.

If you use it to calculate the layout, use an appropriate ViewGroup such as CoordinatorLayout or ConstraintLayout. If you use it to determine the height of the system navbar, use WindowInsets. If you want to know the current size of your app window, use computeCurrentWindowMetrics.

The following list describes the fields affected by this change:

El atributo eleganteTextHeight se establece en verdadero de forma predeterminada.

对于以 Android 15 为目标平台的应用,elegantTextHeight TextView 属性默认变为 true,将默认使用的紧凑字体替换为一些具有较大垂直指标的脚本,并且这种字体更易于阅读。紧凑字体的引入是为了防止破坏布局;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing 属性拉伸垂直高度,以防止许多此类破坏。

在 Android 15 中,紧凑字体仍保留在系统中,因此您的应用可以将 elegantTextHeight 设置为 false,以获得与之前相同的行为,但即将在未来版本中提供支持。因此,如果您的应用支持以下文字:阿拉伯语、老挝语、缅甸、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight 设置为 true,以测试应用。

以 Android 14(API 级别 34)及更低版本为目标平台的应用的 elegantTextHeight 行为。
以 Android 15 为目标平台的应用的 elegantTextHeight 行为。

Cambios en el ancho de TextView para formas de letras complejas

En versiones anteriores de Android, algunas fuentes cursivas o idiomas con formas complejas podían dibujar las letras en el área del carácter anterior o siguiente. En algunos casos, esas letras se recortaban en la posición inicial o final. A partir de Android 15, un TextView asigna ancho a fin de generar suficiente espacio para esas letras y permite que las apps soliciten paddings adicionales a la izquierda para evitar el recorte.

Debido a que este cambio afecta la manera en que una TextView decide el ancho, TextView asigna más ancho de forma predeterminada si la app se orienta a Android 15 o versiones posteriores. Para habilitar o inhabilitar este comportamiento, llama a la API de setUseBoundsForWidth en TextView.

Como agregar padding izquierdo puede causar una desalineación para los diseños existentes, el padding no se agrega de forma predeterminada incluso en el caso de las apps orientadas a Android 15 o versiones posteriores. Sin embargo, puedes agregar padding adicional para evitar el recorte llamando a setShiftDrawingOffsetForStartOverhang.

En los siguientes ejemplos, se muestra cómo estos cambios pueden mejorar el diseño del texto de algunos idiomas y fuentes.

Diseño estándar para texto en inglés en fuente cursiva. Algunas de las letras están recortadas. Este es el XML correspondiente:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
Diseño para el mismo texto en inglés con ancho y padding adicionales. Este es el XML correspondiente:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhan="true" />
Diseño estándar para texto tailandés. Algunas de las letras están recortadas. Este es el XML correspondiente:

<TextView
    android:text="คอมพิวเตอร์" />
Diseño para el mismo texto tailandés con ancho y padding adicionales. Este es el XML correspondiente:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhan="true" />

Altura de línea predeterminada en función de la configuración regional para EditText

In previous versions of Android, the text layout stretched the height of the text to meet the line height of the font that matched the current locale. For example, if the content was in Japanese, because the line height of the Japanese font is slightly larger than the one of a Latin font, the height of the text became slightly larger. However, despite these differences in line heights, the EditText element was sized uniformly, regardless of the locale being used, as illustrated in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText is the same, even though these languages have different line heights from each other.

For apps targeting Android 15, a minimum line height is now reserved for EditText to match the reference font for the specified Locale, as shown in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText now includes space to accommodate the default line height for these languages' fonts.

If needed, your app can restore the previous behavior by specifying the useLocalePreferredLineHeightForMinimum attribute to false, and your app can set custom minimum vertical metrics using the setMinimumFontMetrics API in Kotlin and Java.

Cámara y contenido multimedia

En Android 15, se realizan los siguientes cambios en el comportamiento de la cámara y el contenido multimedia para las apps orientadas a Android 15 o versiones posteriores.

Restricciones para solicitar foco de audio

以 Android 15 为目标平台的应用必须是热门应用或运行与音频相关的前台服务,才能请求音频焦点。如果应用在不符合其中任何一项要求时尝试请求焦点,调用会返回 AUDIOFOCUS_REQUEST_FAILED

如果前台服务的类型为 mediaPlaybackcameramicrophonephoneCall,则会被视为与音频相关。

如需详细了解音频焦点,请参阅管理音频焦点

Actualización de restricciones que no pertenecen al SDK

Android 15 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。

如果您的应用并非以 Android 15 为目标平台,其中一些变更可能不会立即对您产生影响。不过,虽然您的应用可以访问某些非 SDK 接口(具体取决于应用的目标 API 级别),但使用任何非 SDK 方法或字段始终存在导致应用出问题的显著风险。

如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用进行确认。如果您的应用依赖于非 SDK 接口,则应开始计划迁移到 SDK 替代方案。不过,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的功能找到无需使用非 SDK 接口的替代方案,则应请求新的公共 API

Para obtener más información sobre los cambios implementados en esta versión de Android, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 15. Para obtener más información sobre interfaces que no pertenecen al SDK en general, consulta Restricciones en interfaces que no pertenecen al SDK.