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 tu app. Los siguientes cambios de comportamiento se aplican exclusivamente a las apps que son que se orienten a Android 15 o versiones posteriores. Si tu app está orientada a Android 15 o versiones posteriores, debes modificar tu app para que admita correctamente estos comportamientos, que corresponda.

Asegúrate de revisar también la lista de cambios de comportamiento que afectan a todas las apps que se ejecuten 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 introduce un nuevo comportamiento de tiempo de espera en dataSync para la segmentación de apps Android 15 (nivel de API 35) o una versión posterior Este comportamiento también se aplica a la nueva Tipo de servicio en primer plano mediaProcessing.

El sistema permite que los servicios de dataSync de una app se ejecuten durante un total de 6 horas en un período de 24 horas, después de lo cual el sistema llama a la red del Método Service.onTimeout(int, int) (presentado en Android) 15). En este momento, el servicio tiene unos segundos para llamar Service.stopSelf() Cuando se llama a Service.onTimeout(), el elemento servicio ya no se considera un servicio en primer plano. Si el servicio no llama a Service.stopSelf(), el sistema arrojará una excepción interna. El se registra en Logcat con el siguiente mensaje:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"

Para evitar problemas con este cambio de comportamiento, puedes realizar una o más de las siguientes acciones: lo siguiente:

  1. Haz que tu servicio implemente el nuevo método Service.onTimeout(int, int). Cuando tu app reciba la devolución de llamada, asegúrate de llamar a stopSelf() en una unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera falla).
  2. Asegúrate de que los servicios de dataSync de tu app no se ejecuten durante un total de 6 horas en cualquier período de 24 horas (salvo que el usuario interactúe con la app) restableciendo el temporizador).
  3. Solo iniciar dataSync servicios en primer plano como resultado de la acción de un usuario directo interacción dado que tu app está en primer plano cuando se inicia el servicio el servicio tiene las seis horas completas después de que la app pasa a segundo plano.
  4. En lugar de usar un servicio en primer plano de dataSync, usa un alternativa.

Si los servicios en primer plano de dataSync de tu app se ejecutaron durante 6 horas durante el último período 24, no puedes iniciar otro servicio en primer plano de dataSync, a menos que el usuario Tu aplicación se puso en primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio dataSync en primer plano, el sistema arrojará ForegroundServiceStartNotAllowedException con un mensaje de error como “Ya se agotó el tiempo para el servicio en primer plano escribe dataSync".

Prueba

Para probar el comportamiento de tu app, habilita los tiempos de espera de la sincronización de datos incluso si la app No está orientada a Android 15 (siempre y cuando la app se ejecute en un dispositivo Android 15). dispositivo). Para habilitar los tiempos de espera, ejecuta el siguiente comando adb:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

También puedes ajustar el tiempo de espera para probar cómo tus se comporta cuando se alcanza el límite. Para establecer un nuevo tiempo de espera, ejecuta siguiente comando adb:

adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds

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

Android 15 引入了一种新的前台服务类型,即 mediaProcessing。本次 服务类型适用于对媒体文件进行转码等操作。对于 例如,媒体应用可能会下载音频文件并需要将其转换为 然后再播放之前的视频您可以使用 mediaProcessing 前台 以确保即使应用处于打开或关闭状态,转化仍会继续进行 背景。

系统允许应用的 mediaProcessing 服务共运行 6 次 之后,系统会调用正在运行的服务的 Service.onTimeout(int, int) 方法(在 Android 中引入) 15)。此时,服务有几秒钟的时间来调用 Service.stopSelf()。如果该服务没有 调用 Service.stopSelf() 时,系统会抛出内部异常。通过 Logcat 中会记录以下异常:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"

为避免出现异常,您可以执行以下操作之一:

  1. 让您的服务实现新的 Service.onTimeout(int, int) 方法。 当您的应用收到回调时,请务必在stopSelf() 几秒。(如果您不立即停止应用,则系统会生成 失败。)
  2. 确保应用的 mediaProcessing 服务的运行时间不超过 总计 在任何 24 小时内为 6 小时(除非用户与应用互动; 重置计时器)。
  3. 仅在用户执行直接操作后启动 mediaProcessing 项前台服务 互动;由于服务启动时您的应用位于前台 您的服务在应用转入后台后的完整运行 6 小时。
  4. 不使用 mediaProcessing 前台服务,而是使用替代方法 API,例如 WorkManager。

如果您的应用的 mediaProcessing 前台服务已在 不能启动其他 mediaProcessing 前台服务,除非 用户将您的应用转至前台(这会重置计时器)。如果您 尝试启动另一个 mediaProcessing 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException 并显示类似“前台服务的时限已用尽”的错误消息 type mediaProcessing”。

要详细了解 mediaProcessing 服务类型,请参阅对 前台服务类型:媒体处理

测试

如需测试应用的行为,您可以启用媒体处理超时,即使 您的应用并非以 Android 15 为目标平台(只要该应用在 Android 15 上运行) Android 15 设备)。如需启用超时功能,请运行以下 adb 命令:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

您还可以调整超时期限,以便更轻松地测试 在达到该限制时,应用的行为。要设置新的超时期限,请运行 以下 adb 命令:

adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds

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

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

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

测试

如需测试应用的行为,您可以启用这些新限制,即使您的应用并未以 Android 15 为目标平台(只要应用在 Android 15 设备上运行)也是如此。运行以下 adb 命令:

adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name

如需在不重启设备的情况下发送 BOOT_COMPLETED 广播,请运行以下 adb 命令:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name

限制在应用拥有 SYSTEM_ALERT_WINDOW 权限时启动前台服务

以前,如果应用拥有 SYSTEM_ALERT_WINDOW 权限,则可以启动 前台服务,即使应用当前在后台运行(如 请参阅后台启动限制的豁免部分)。

如果应用以 Android 15 为目标平台,则此豁免的范围现在更窄。现在,该应用需要 具有 SYSTEM_ALERT_WINDOW 权限,并且还应显示一个可见叠加层 窗口。也就是说,应用需要先启动一个 TYPE_APPLICATION_OVERLAY 窗口窗口 在您启动前台服务之前必须处于可见状态。

如果您的应用试图在后台启动前台服务,却没有启动 符合这些新要求(并且不具有某些其他豁免情况), 系统会抛出 ForegroundServiceStartNotAllowedException

如果您的应用声明了 SYSTEM_ALERT_WINDOW 权限 并在后台启动前台服务时,可能会受此影响 更改。如果您的应用收到 ForegroundServiceStartNotAllowedException,请检查 应用的操作顺序,并确保应用已有 叠加层窗口,然后再尝试从 背景。您可以检查叠加窗口当前是否可见 致电 View.getWindowVisibility(),或者 可以替换 View.onWindowVisibilityChanged() 以便在公开范围发生变化时收到通知。

测试

如需测试应用的行为,即使您的 应用并非以 Android 15 为目标平台(只要该应用在 Android 15 上运行即可) 设备)。为了在启动前台服务时启用这些新限制 在后台运行以下 adb 命令:

adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name

Cambios en el momento en que las apps pueden modificar el estado global del modo No interrumpir

Las apps orientadas a Android 15 ya no pueden cambiar el estado global ni la política de No interrumpir (No interrumpir) en un dispositivo (ya sea modificando la configuración del usuario o desactivando el modo No interrumpir). En cambio, las apps deben aportar un AutomaticZenRule, que el sistema combina en una política global con el esquema existente más restrictivo de la política. Las llamadas a las APIs existentes que anteriormente afectaron el estado global (setInterruptionFilter, setNotificationPolicy) generan la creación o actualización de un AutomaticZenRule implícito, que se activa y desactiva según el ciclo de llamadas de esas llamadas a la API.

Ten en cuenta que este cambio solo afecta el comportamiento observable si la app llama a setInterruptionFilter(INTERRUPTION_FILTER_ALL) y espera que esa llamada desactive una AutomaticZenRule que sus propietarios hayan activado.

Cambios en la API de OpenJDK

Android 15 将继续更新 Android 的核心库, 最新 OpenJDK LTS 版本中的功能。

其中一些变更可能会影响应用定位的应用兼容性 Android 15(API 级别 35):

  • 字符串格式设置 API 变更:验证参数索引、标志、 现在,使用 String.format()Formatter.format() API:

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

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    在这种情况下,可以使用参数索引为 1 (%1 )。

  • Arrays.asList(...).toArray() 组件类型的更改:使用 Arrays.asList(...).toArray(),则所得数组的组件类型为 现在是 Object,而不是底层数组元素的类型。因此, 以下代码会抛出 ClassCastException

    String[] elements = (String[]) Arrays.asList("one", "two").toArray();
    

    在本例中,在结果中将 String 保留为组件类型 数组,您可以改用 Collection.toArray(Object[])

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • 语言代码处理方式变更:使用 Locale API 时, 不再转换希伯来语、意第绪语和印度尼西亚语的语言代码 对应的过时形式(希伯来语:iw、意第绪语:ji 和印度尼西亚语:in)。 在为其中某个语言区域指定语言代码时,请使用代码 改为 ISO 639-1(希伯来语:he,意第绪语:yi,印度尼西亚语:id)。

  • 对随机整数序列的更改https://bugs.openjdk.org/browse/JDK-8301574,下面 Random.ints() 方法现在返回的数值序列与 Random.nextInt() 方法的用途如下:

    一般来说,此变更不会导致应用中断行为,但您的 代码不应期望 Random.ints() 方法生成的序列 匹配Random.nextInt()

新的 SequencedCollection API 可能会影响应用的兼容性 当您在应用的 build 配置中更新 compileSdk 以使用 Android 15(API 级别 35)

  • MutableList.removeFirst()kotlin-stdlib 中的 MutableList.removeLast() 扩展函数

    Java 中的 List 类型会映射到 Kotlin 中的 MutableList 类型。 由于使用 List.removeFirst()List.removeLast() API 已在 Android 15(API 级别 35)中引入,Kotlin 编译器 将函数调用(例如 list.removeFirst())静态解析为 新的 List API,而不是对 API 中的扩展函数 kotlin-stdlib

    重新编译应用时,如果 compileSdk 设为 35,并且 minSdk 设为 34 或更低版本,那么应用会在 Android 14 及更低版本(运行时)上运行 错误:

    java.lang.NoSuchMethodError: No virtual method
    removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
    

    Android Gradle 插件中的现有 NewApi lint 选项可以捕获这些 新的 API 用法。

    ./gradlew lint
    
    MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi]
          list.removeFirst()
    

    如需修复运行时异常和 lint 错误,removeFirst()removeLast() 函数调用可替换为 removeAt(0)removeAt(list.lastIndex)(在 Kotlin 中分别对应)。如果您使用的是 Android Studio Ladybug |2024.1.3 或更高版本,也提供快速修复 处理这些错误的选项

    如果 lint 选项已停用,请考虑移除 @SuppressLint("NewApi")lintOptions { disable 'NewApi' }

  • 与 Java 中的其他方法冲突

    向现有类型中添加了新方法,例如, ListDeque。这些新方法 其他接口中使用相同名称和参数类型的方法 和类。如果与 不兼容,javac 编译器会输出构建时错误。例如:

    错误 1 示例:

    javac MyList.java
    
    MyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List
      public void removeLast() {
                  ^
      return type void is not compatible with Object
      where E is a type-variable:
        E extends Object declared in interface List
    

    错误 2 示例:

    javac MyList.java
    
    MyList.java:7: error: types Deque<Object> and List<Object> are incompatible;
    public class MyList implements  List<Object>, Deque<Object> {
      both define reversed(), but with unrelated return types
    1 error
    

    错误 3 示例:

    javac MyList.java
    
    MyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible;
    public static class MyList implements List<Object>, MyInterface<Object> {
      class MyList inherits unrelated defaults for getFirst() from types List and MyInterface
      where E#1,E#2 are type-variables:
        E#1 extends Object declared in interface List
        E#2 extends Object declared in interface MyInterface
    1 error
    

    要修复这些构建错误,实现这些接口的类应 使用兼容的返回值类型替换该方法。例如:

    @Override
    public Object getFirst() {
        return List.super.getLast();
    }
    

Seguridad

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

Lanzamientos seguros de actividades en segundo plano

Android 15 protege a los usuarios de apps maliciosas y les da más control sobre sus dispositivos agregando cambios que eviten que las apps llevar otras apps al primer plano, elevar sus privilegios y fomentar el abuso la interacción del usuario. Se restringieron los inicios de actividades en segundo plano desde Android 10 (nivel de API 29)

Impedir que se inicien actividades 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, se superponen para crear la ilusión de ser esa aplicación. Esta "tarea usurpación" este ataque elude las restricciones actuales de inicio en segundo plano ocurre dentro de la misma tarea visible. Para mitigar este riesgo, Android 15 agrega un marca que impide que se inicien las apps que no coinciden con el UID superior de la pila de datos. Para aceptar todas las actividades de tu app, actualiza la allowCrossUidActivitySwitchFromBelow en el archivo AndroidManifest.xml de tu app:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

Las nuevas medidas de seguridad estarán activas si se cumplen todas las condiciones que figuran a continuación:

  • La app que realiza el lanzamiento está orientada a Android 15.
  • La app que está sobre la pila de tareas se orienta a Android 15.
  • Toda actividad visible se haya habilitado para las nuevas protecciones

Si las medidas de seguridad están habilitadas, las apps podrían regresar a la página principal, en lugar de la última app visible, si terminan sus propias tareas.

Otros cambios

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

  • Cambia a PendingIntent creadores para que bloqueen los lanzamientos de actividades en segundo plano de la siguiente manera: predeterminada. Esto ayuda a evitar que las apps creen accidentalmente PendingIntent que podrían ser abusadas por agentes maliciosos.
  • No lleves una app al primer plano, a menos que sea el remitente de PendingIntent. lo permite. El objetivo de este cambio es evitar que apps maliciosas abusen de los capacidad para iniciar actividades en segundo plano. De forma predeterminada, las apps no llevar la pila de tareas al primer plano, a menos que el creador permita privilegios de inicio de la actividad en segundo plano o si el remitente tiene actividad en segundo plano iniciar privilegios.
  • Controla cómo la actividad principal de una pila de tareas puede finalizar su tarea. Si el botón una actividad principal finaliza una tarea, Android regresará a la tarea que se haya la última vez que estuvo activo. Además, si una actividad que no es principal finaliza su tarea, Android vuelve a la pantalla de inicio, no bloqueará el acabado de este no superior actividad.
  • Evita iniciar actividades arbitrarias de otras apps en la tuya tarea. Este cambio evita que las apps maliciosas creen ataques de phishing a través de la creación actividades que parecen ser de otras aplicaciones.
  • Bloquear ventanas no visibles para que no se consideren para la actividad en segundo plano inicio de sesión. Esto ayuda a evitar que apps maliciosas abusen de los recursos en segundo plano se inicia actividad para mostrar contenido malicioso o no deseado a los usuarios.

Intents más seguros

Android 15 引入了新的安全措施,可让 intent 更加安全且更安全 稳健。这些变更旨在防范潜在的漏洞和 可能会被恶意应用利用的 intent 滥用。有两个主要的 Android 15 中对 intent 安全性的改进:

  • 匹配目标 intent 过滤器:针对特定组件的 intent 准确匹配目标的 intent 过滤器规范。如果您发送 intent 来启动另一个应用的 activity,则目标 intent 组件需要 与接收 activity 声明的 intent 过滤器保持一致。
  • intent 必须具有操作:没有操作的 intent 将不再匹配 任何 intent 过滤器。也就是说,用于启动 activity 或 服务都必须有明确定义的操作。
  • 待处理 intent:待处理 intent 的创建者被视为封装 intent 的发送者,而非待处理 intent 的发送者 意图

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 un entorno una experiencia del usuario intuitiva.

Cambios en la inserción de ventana

Hay dos cambios relacionados con las inserciones de ventana en Android 15: de borde a borde se aplica de forma predeterminada, y también hay cambios de configuración, como la configuración predeterminada de las barras del sistema.

Aplicación de borde a borde

Las apps son de borde a borde de forma predeterminada en dispositivos que ejecutan Android 15 si se usan orientadas a Android 15 (nivel de API 35).

Una app orientada a Android 14 y no de borde a borde Dispositivo con Android 15.


Una app orientada a Android 15 (nivel de API 35) y de borde a borde en un dispositivo con Android 15. Esta app usa principalmente componentes de Compose de Material 3 que aplican automáticamente las inserciones. Esta pantalla no se ve afectada negativamente por el Aplicación de borde a borde de Android 15

Este es un cambio rotundo que podría afectar negativamente la IU de tu app. El afectan las siguientes áreas de la IU:

  • Barra de navegación del controlador por gestos
    • Es transparente de forma predeterminada.
    • El desplazamiento inferior está inhabilitado, por lo que el contenido se dibuja detrás de la navegación del sistema. a menos que se apliquen inserciones.
    • setNavigationBarColor y R.attr#navigationBarColor son y no afectan la navegación por gestos.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced siguen sin tener efecto en navegación por gestos.
  • Navegación con 3 botones
    • Opacidad establecida en 80% de forma predeterminada, con color posiblemente coincidente con la ventana en segundo plano.
    • Se inhabilitó el desplazamiento inferior, por lo que el contenido se dibuja detrás de la barra de navegación del sistema a menos que se apliquen inserciones.
    • setNavigationBarColor y R.attr#navigationBarColor son se configura para que coincida con el fondo de la ventana de forma predeterminada. El fondo de la ventana debe ser un elemento de diseño de color para que se aplique este valor predeterminado. Esta API es obsoleta, pero continúa afectando la navegación con 3 botones.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced es verdadero de forma predeterminada, lo que agrega un Fondo opaco del 80% en la navegación con 3 botones.
  • Barra de estado
    • Es transparente de forma predeterminada.
    • El desplazamiento superior está inhabilitado, por lo que el contenido se dibuja detrás de la barra de estado, a menos que se aplican las inserciones.
    • setStatusBarColor y R.attr#statusBarColor son obsoleto y no afectan a Android 15.
    • setStatusBarContrastEnforced y R.attr#statusBarContrastEnforced dejaron de estar disponibles, pero aún tienen un el efecto en Android 15.
  • Recorte de pantalla
    • El layoutInDisplayCutoutMode de las ventanas no flotantes deben tener LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS SHORT_EDGES, NEVER y DEFAULT se interpretan como ALWAYS, de modo que los usuarios no ven un negro causada por el corte de la pantalla y aparece de borde a borde.

En el siguiente ejemplo, se muestra una app antes y después de la segmentación Android 15 (nivel de API 35), y antes y después de aplicar inserciones.

Una app orientada a Android 14 y no de borde a borde Dispositivo con Android 15.
Una app orientada a Android 15 (nivel de API 35) y de borde a borde en un dispositivo con Android 15. Sin embargo, muchos elementos ahora están ocultos por el estado barra de navegación con 3 botones o un corte de pantalla debido a la aplicaciones de borde a borde. La IU oculta incluye Material 2 la barra superior de la app, los botones de acción flotantes y los elementos de lista.
Una app que se orienta a Android 15 (nivel de API 35) está de borde a borde un dispositivo con Android 15 y aplica inserciones para que la IU no sea ocultan.
Qué debes verificar si tu app ya está de borde a borde

Si tu aplicación ya es de borde a borde y aplica inserciones, puedes hacer lo siguiente: en su mayoría no se verán afectados, excepto en los siguientes escenarios. Sin embargo, incluso si piensas no te afectará, te recomendamos que pruebes tu app.

  • Tienes una ventana no flotante, como una Activity que usa SHORT_EDGES, NEVER o DEFAULT en lugar de LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS Si tu app falla durante el inicio, esto podría deberse a la pantalla de presentación. Se pueden actualizar los principales Dependencia de splashscreen a 1.2.0-alpha01 o posterior, o configura window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • Es posible que haya pantallas con poco tráfico con una IU oculta. Verificar estas opciones las pantallas menos visitadas no tienen una IU oculta. Las pantallas con poco tráfico incluyen:
    • Pantallas de incorporación o acceso
    • Páginas de configuración
Qué debes verificar si tu app aún no está de borde a borde

Si tu app aún no está de borde a borde, lo más probable es que te veas afectado. En además de los casos de apps que ya están de borde a borde, considera lo siguiente:

  • Si tu app usa componentes de Material 3 ( androidx.compose.material3) en Compose, como TopAppBar, BottomAppBar y NavigationBar, es probable que estos componentes no porque manejan automáticamente las inserciones.
  • Si tu app usa componentes de Material 2 ( androidx.compose.material) en Compose, estos componentes no controlan automáticamente las inserciones. Sin embargo, puedes acceder a las inserciones y aplicarlos manualmente. En androidx.compose.material 1.6.0 y, luego, usa el parámetro windowInsets para aplicar las inserciones de forma manual BottomAppBar, TopAppBar BottomNavigation y NavigationRail. Del mismo modo, usa el parámetro contentWindowInsets para Scaffold
  • Si tu app usa vistas y componentes de Material (com.google.android.material), la mayoría de las vistas de Material basadas en vistas Componentes como BottomNavigationView, BottomAppBar, NavigationRailView o NavigationView controlan las inserciones y no requieren trabajo adicional. Sin embargo, debes agregar android:fitsSystemWindows="true" si usas AppBarLayout.
  • En el caso de los elementos componibles personalizados, aplica las inserciones de forma manual como padding. Si el contenido dentro de un Scaffold, puedes consumir inserciones con el Scaffold valores de padding. De lo contrario, aplica el padding con uno de los WindowInsets
  • Si tu app usa vistas y BottomSheet, SideSheet o personalizados contenedores, aplica el relleno con ViewCompat.setOnApplyWindowInsetsListener Para RecyclerView, aplica padding con este objeto de escucha y agrega clipToPadding="false"
Qué verifica si tu app debe ofrecer protección personalizada de fondo

Si tu app debe ofrecer protección personalizada en segundo plano para la navegación con 3 botones o la barra de estado, tu app debe colocar un elemento componible o una vista detrás de la barra del sistema usando WindowInsets.Type#tappableElement() para obtener el botón de 3 altura de la barra de navegación o WindowInsets.Type#statusBars

Recursos adicionales de borde a borde

Consulta Vistas de borde a borde y Redacción de borde a borde. para obtener información adicional sobre la aplicación de inserciones.

APIs obsoletas

Las siguientes APIs dejaron de estar disponibles:

Configuración estable

Si tu app se orienta a Android 15 (nivel de API 35) o versiones posteriores, Configuration no excluye las barras del sistema. Si utilizas el tamaño de la pantalla Configuration para el cálculo de diseño, debes reemplazarla por una alternativas como un ViewGroup, WindowInsets o WindowMetricsCalculator según tus necesidades.

Configuration está disponible desde la API 1. Por lo general, se obtienen de Activity.onConfigurationChanged Proporciona información como la densidad de la ventana, la orientación y los tamaños. Una característica importante de los tamaños de ventana que muestra Configuration es que antes excluía las barras del sistema.

Por lo general, el tamaño de la configuración se usa para seleccionar recursos, como /res/layout-h500dp, y este sigue siendo un caso de uso válido. Sin embargo, usarlo para el cálculo de diseño siempre se desaconsejó. Si lo haces, deberías ahora. Debes reemplazar el uso de Configuration por algo. sean más adecuados según tu caso de uso.

Si lo usas para calcular el diseño, utiliza un ViewGroup adecuado, como CoordinatorLayout o ConstraintLayout. Si lo usas para determinar la altura de la barra de navegación del sistema, usa WindowInsets. Si quieres saber el tamaño actual de la ventana de tu app, usa computeCurrentWindowMetrics.

En la siguiente lista, se describen los campos que se verán afectados por este cambio:

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 de ancho de TextView para formas de letras complejas

En versiones anteriores de Android, algunos idiomas o fuentes cursivas con las formas complejas podrí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 para dibujar suficiente espacio para estas letras y permite que las apps soliciten rellenos adicionales a la izquierda para evitar recortes.

Como este cambio afecta la forma en que un TextView decide el ancho, TextView asigna más ancho de forma predeterminada si la app se orienta a Android 15 (nivel de API 35). mayores. Para habilitar o inhabilitar este comportamiento, llama al La API de setUseBoundsForWidth en TextView

Como agregar padding izquierdo puede causar un desajuste en los diseños existentes, el El padding no se agrega de forma predeterminada, incluso en las apps orientadas a Android 15 o versiones posteriores. Sin embargo, puedes agregar relleno para evitar el recorte llamando setShiftDrawingOffsetForStartOverhang

Los siguientes ejemplos muestran cómo estos cambios pueden mejorar el diseño del texto para algunas fuentes e idiomas.

Diseño estándar para texto en inglés en fuente cursiva. Algunos de los 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 adicional y con padding. Este es el XML correspondiente:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
Diseño estándar para el texto en 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 adicional y con padding. Este es el XML correspondiente:

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

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

En las versiones anteriores de Android, el diseño de texto estiraba la altura del texto para cumplir con la altura de la línea de la fuente que coincidía con la configuración regional actual. Por ejemplo, si el contenido estaba en japonés, debido a que la altura de la línea de la fuente japonesa es ligeramente mayor que la de una fuente latina, la altura del texto se agrandó un poco más grande. Sin embargo, a pesar de estas diferencias en las alturas de las líneas, el tamaño del elemento EditText se dimensionó de manera uniforme, independientemente de la configuración regional que se usara, como se ilustra en la siguiente imagen:

Tres cuadros que representan elementos EditText que pueden contener texto de inglés (en), japonés (ja) y birmano (my). La altura de EditText es la misma, aunque estos idiomas tienen alturas de línea diferentes.

En el caso de las apps orientadas a Android 15, ahora se reserva una altura de línea mínima para que EditText coincida con la fuente de referencia de la configuración regional especificada, como se muestra en la siguiente imagen:

Tres cuadros que representan elementos EditText que pueden contener texto de inglés (en), japonés (ja) y birmano (my). La altura de EditText ahora incluye espacio para adaptarse a la altura de línea predeterminada de las fuentes de estos idiomas.

Si es necesario, tu app puede restablecer el comportamiento anterior especificando el atributo useLocalePreferredLineHeightForMinimum en false, y tu app puede establecer métricas verticales mínimas personalizadas con la API de setMinimumFontMetrics en Kotlin y Java.

Cámara y contenido multimedia

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

Restricciones para solicitar foco de audio

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

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 incluye listas actualizadas de usuarios restringidos que no pertenecen al SDK basadas en la colaboración con desarrolladores de Android y la las pruebas internas. Siempre que sea posible, nos aseguramos de que las alternativas públicas estén disponibles antes de restringir las interfaces que no pertenecen al SDK.

Si tu app no está orientada a Android 15, se implementarán algunos de estos cambios. podría no afectarte de inmediato. Sin embargo, si bien es posible que tu app acceder a algunas interfaces que no pertenecen al SDK según el nivel de API objetivo de tu app, con cualquier método o campo siempre conlleva un alto riesgo de error para tu app.

Si no sabes con certeza si tu app usa interfaces que no pertenecen al SDK, puedes prueba tu app para averiguarlo. Si tu app depende del SDK interfaces, deberías comenzar a planificar la migración hacia alternativas de SDK. Sin embargo, sabemos que algunas apps tienen casos de uso válidos para usarlas. Si no encuentras una alternativa al uso de un SDK interfaz de una función de tu app, deberías solicitar una nueva API pública

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.