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

Realizaremos los siguientes cambios en los servicios en primer plano con Android 15.

Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia

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

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

Restricciones en los receptores de emisión de BOOT_COMPLETED que inician servicios en primer plano

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

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

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

以 Android 15 为目标平台的应用无法再更改设备上的全局状态或勿扰 (DND) 政策(通过修改用户设置或关闭 DND 模式)。相反,应用必须提供一个 AutomaticZenRule,系统会将后者合并到一个具有现有最严格的政策胜出方案的全局政策中。调用之前影响全局状态的现有 API(setInterruptionFiltersetNotificationPolicy)会导致创建或更新隐式 AutomaticZenRule,该 AutomaticZenRule 根据这些 API 调用的调用周期而开启或关闭。

请注意,只有在应用调用 setInterruptionFilter(INTERRUPTION_FILTER_ALL) 且预期调用会停用之前由其所有者激活的 AutomaticZenRule 时,此变更才会影响可观察的行为。

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 通过添加变更来防止恶意后台应用将其他应用带到前台、提升其权限和滥用用户互动,从而保护用户免受恶意应用的侵害,并使用户能够更好地控制其设备。从 Android 10(API 级别 29)开始,后台 activity 启动已受到限制。

阻止与堆栈中顶部 UID 不匹配的应用启动 activity

恶意应用可以在同一任务内启动另一个应用的 activity,然后叠加在上面,制造出作为该应用的错觉。这种“任务劫持”攻击绕过了当前的后台启动限制,因为它都发生在同一可见任务内。为了降低这种风险,Android 15 添加了一个标志,用于阻止与堆栈上的顶级 UID 不匹配的应用启动 activity。如需选择启用应用的所有 activity,请更新应用的 AndroidManifest.xml 文件中的 allowCrossUidActivitySwitchFromBelow 属性:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

其他变更

除了 UID 匹配的限制之外,还包含以下其他更改:

  • PendingIntent 创建者更改为默认阻止后台 activity 启动。这有助于防止应用意外创建可能会被恶意操作者滥用的 PendingIntent
  • 请勿将应用置于前台,除非 PendingIntent 发送者允许该应用。此变更旨在防止恶意应用滥用在后台启动 activity 的功能。默认情况下,不允许应用将任务堆栈置于前台,除非创建者允许后台 activity 启动特权或发送者具有后台 activity 启动特权。
  • 控制任务堆栈的顶层 activity 完成其任务的方式。如果顶层 activity 完成某项任务,Android 会返回到上次处于活动状态的任务。此外,如果非顶层 activity 完成其任务,Android 将返回主屏幕;它不会阻止此非顶部 activity 的完成。
  • 防止将其他应用中的任意 activity 启动到您自己的任务中。这项变更会通过创建看似来自其他应用的活动,防止恶意应用向用户进行钓鱼式攻击。
  • 阻止系统考虑将不可见窗口用于后台 activity 启动。这有助于防止恶意应用滥用后台 activity 启动来向用户显示不受欢迎或恶意内容。

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.

Aplicación de borde a borde

默认情况下,如果应用以 Android 15 为目标平台,则在搭载 Android 15 的设备上会无边框。

应用以 Android 14 为目标平台且在 Android 15 设备上并非全屏显示的应用。


一个以 Android 15 为目标平台且在 Android 15 设备上实现无边框的应用。此应用主要使用可自动应用边衬区的 Material 3 Compose 组件。此屏幕不会受到 Android 15 无边框强制执行的影响。

这是一项重大变更,可能会对应用的界面产生负面影响。变更如下:

  • 手势手柄导航栏
    • 默认为透明。
    • 由于底部偏移已停用,因此内容绘制在系统导航栏后面,除非应用边衬区。
    • setNavigationBarColorR.attr#navigationBarColor 已废弃,不会影响手势导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 仍然对手势导航没有影响。
  • “三按钮”导航
    • 不透明度默认设置为 80%,颜色可能与窗口背景匹配。
    • 已停用底部偏移,因此内容绘制在系统导航栏后面,除非应用边衬区。
    • 默认情况下,setNavigationBarColorR.attr#navigationBarColor 设置为与窗口背景匹配。窗口背景必须是彩色可绘制对象,才能应用此默认设置。此 API 已废弃,但会继续影响三按钮导航。
    • setNavigationBarContrastEnforcedR.attr#navigationBarContrastEnforced 默认情况下为 true,这会在“三按钮”导航中添加 80% 的不透明背景。
  • 状态栏
    • 默认为透明。
    • 顶部偏移量已停用,因此,除非应用边衬区,否则内容将绘制在状态栏后面。
    • setStatusBarColorR.attr#statusBarColor 已废弃,对 Android 15 没有任何影响。
    • setStatusBarContrastEnforcedR.attr#statusBarContrastEnforced 已废弃,但在 Android 15 上仍产生影响。
  • 刘海屏
    • 非浮动窗口的 layoutInDisplayCutoutMode 必须为 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS。在 Android 15 Beta 1 中,如果使用 SHORT_EDGESNEVERDEFAULT(例如 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT),应用将会崩溃并出现 IllegalArgumentException。在 Android 15 Beta 版 2 中,SHORT_EDGESNEVERDEFAULT 将被解释为 ALWAYS,这样用户就不会看到由刘海屏导致的黑色条形,而无边框。

以下示例展示了以 Android 15 为目标平台之前和之后以及应用边衬区前后的应用。

应用以 Android 14 为目标平台且在 Android 15 设备上并非全屏显示的应用。
一个以 Android 15 为目标平台且在 Android 15 设备上实现无边框的应用。不过,由于 Android 15 的无边框强制措施,许多元素现在被状态栏、“三按钮”导航栏或刘海屏遮挡。被遮盖的界面包括 Material 2 TopAppBar、FAB 和列表项。
如果应用以 Android 15 为目标平台,则可以在 Android 15 设备上全屏显示,并会应用边衬区来避免界面被遮挡。

如果您的应用:

  • 无边框并应用了边衬区,那么除了以下几种场景外,您基本上不受影响。不过,即使您认为自己不受影响,我们也建议您测试自己的应用。
    • 您有一个非浮动窗口,例如使用 SHORT_EDGES, NEVERDEFAULT(而非 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)的 Activity。如果您的应用在启动时崩溃,这可能是由于启动画面所致。您可以将 core splashscreen 依赖项升级到 1.2.0-alpha01 或更高版本,设置 window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always,或使用 Android 15 Beta 版 2(而不是 Beta 版 1)进行测试。
    • 在流量较低的屏幕上,可能会出现界面被遮挡的屏幕。验证这些访问较少的屏幕没有被遮挡的界面。流量较低的屏幕包括:
      • 初始配置或登录屏幕
      • “设置”页面
  • 非无边际,那么您很有可能受到影响。除了无边框应用出现的情况之外,您还需要考虑以下因素:
    • 如果您的应用使用 Material 3 组件(Compose 中的 androidx.compose.material3,例如 TopAppBar, BottomAppBarNavigationBar),这些组件可能不受影响,因为它们会自动处理边衬区。
    • 如果您的应用使用的是 Material 2 组件(Compose 中的 androidx.compose.material),则这些组件不会自动处理边衬区。不过,您可以访问边衬区并手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,请使用 windowInsets 参数,为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。同样,对 Scaffold 使用 contentWindowInsets 参数。
    • 如果您的应用使用 View 和 Material 组件 (com.google.android.material),则大多数基于 View 的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)会处理边衬区,无需执行额外的操作。不过,如果使用 AppBarLayout,则需要添加 android:fitsSystemWindows="true"
    • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的内容位于 Scaffold 内,您可以使用 Scaffold 的内边距值使用边衬区。否则,请使用 WindowInsets 之一应用内边距。
    • 如果您的应用使用的是 View 和 BottomSheet、SideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,并添加 clipToPadding="false"
  • 必须为三按钮导航或状态栏提供自定义背景保护,那么您的应用应使用 WindowInsets.Type#tappableElement() 获取三按钮导航栏高度或 WindowInsets.Type#statusBars,将可组合项或视图放置在系统栏后面。

如需了解应用边衬区的其他注意事项,请参阅边缘视图Edge to Edge Compose 指南。

已废弃和已停用的 API 列表如下:

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

Configuración estable

此变更无法在 Beta 1 中进行测试,但很快就会推出。

如果您的应用以 Android 15 或更高版本为目标平台,Configuration 将不再排除系统栏。如果您在 Configuration 类中使用屏幕尺寸计算布局,则应根据需要将其替换为合适的 ViewGroupWindowInsetsWindowMetricsCalculator 等更好的替代方案。

从 API 1 开始,Configuration 一直可用。它通常从 Activity.onConfigurationChanged 获取。它可提供窗口密度、方向和大小等信息。从 Configuration 返回的窗口大小的一个重要特征是它之前排除了系统栏。

配置大小通常用于资源选择(如 /res/layout-h500dp),这仍然是一个有效的用例。不过,我们一直不建议将其用于布局计算。如果这样做,您应该立即离开。您应该根据自己的使用场景,将 Configuration 替换为更合适的代码。

如果您使用它来计算布局,请使用适当的 ViewGroup,例如 CoordinatorLayoutConstraintLayout。如果您使用它来确定系统导航栏的高度,请使用 WindowInsets。如果您想知道应用窗口的当前大小,请使用 computeCurrentWindowMetrics

以下列表介绍了受此更改影响的字段:

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

Las apps orientadas a Android 15 deben ser la app principal o ejecutar un servicio en primer plano relacionado con el audio para solicitar el foco de audio. Si una app intenta solicitar el foco cuando no cumple con uno de estos requisitos, la llamada mostrará AUDIOFOCUS_REQUEST_FAILED.

Un servicio en primer plano se considera relacionado con el audio si su tipo es mediaPlayback, camera, microphone o phoneCall.

Puedes obtener más información sobre el foco de audio en Cómo administrar el foco de audio.

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.