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 se aplican exclusivamente a las apps orientadas a Android 15 o versiones posteriores. Si tu app está segmentada para 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 en el comportamiento que afectan a todas las apps que se ejecutan en Android 15, independientemente de 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 presenta un nuevo comportamiento de tiempo de espera para dataSync en el caso de las apps que se orientan a Android 15 (nivel de API 35) o versiones posteriores. Este comportamiento también se aplica al nuevo tipo de servicio en primer plano mediaProcessing.

El sistema permite que los servicios 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 al método Service.onTimeout(int, int) del servicio en ejecución (presentado en Android 15). En este momento, el servicio tiene unos segundos para llamar a Service.stopSelf(). Cuando se llama a Service.onTimeout(), el servicio ya no se considera un servicio en primer plano. Si el servicio no llama a Service.stopSelf(), el sistema arroja una excepción interna. La excepción 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:

  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 unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera una falla).
  2. Asegúrate de que los servicios dataSync de tu app no se ejecuten durante más de un total de 6 horas en cualquier período de 24 horas (a menos que el usuario interactúe con la app y restablezca el temporizador).
  3. Inicia servicios en primer plano de dataSync solo como resultado de la interacción directa del usuario. Como tu app está en primer plano cuando se inicia el servicio, este 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 una API alternativa.

Si los servicios en primer plano dataSync de tu app se ejecutaron durante 6 horas en las últimas 24, no puedes iniciar otro servicio en primer plano dataSync a menos que el usuario haya llevado tu app al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio en primer plano dataSync, el sistema arrojará una ForegroundServiceStartNotAllowedException con un mensaje de error como "El límite de tiempo ya se agotó para el tipo de servicio en primer plano dataSync".

Prueba

Para probar el comportamiento de tu app, puedes habilitar los tiempos de espera de sincronización de datos, incluso si tu app no se orienta a Android 15 (siempre que la app se ejecute en un dispositivo Android 15). 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 facilitar la prueba del comportamiento de tu app cuando se alcanza el límite. Para establecer un nuevo período de tiempo de espera, ejecuta el siguiente comando adb:

adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds

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

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

系统允许应用的 mediaProcessing 服务在 24 小时内总共运行 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. 请改用 替代 API(例如 WorkManager),而不是使用 mediaProcessing 前台服务。

如果您的应用的 mediaProcessing 前台服务在过去 24 小时内运行了 6 小时,则您无法启动其他 mediaProcessing 前台服务,除非用户将您的应用切换到前台(这会重置计时器)。如果您尝试启动另一个 mediaProcessing 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException,并显示类似于“前台服务类型 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 权限时启动前台服务的限制

Anteriormente, si una app tenía el permiso SYSTEM_ALERT_WINDOW, podía iniciar un servicio en primer plano, incluso si la app estaba en segundo plano (como se explica en exenciones de las restricciones de inicio en segundo plano).

Si una app está orientada a Android 15, esta exención ahora es más limitada. Ahora, la app debe tener el permiso SYSTEM_ALERT_WINDOW y también tener una ventana superpuesta visible. Es decir, la app primero debe iniciar una ventana TYPE_APPLICATION_OVERLAY y la ventana debe ser visible antes de iniciar un servicio en primer plano.

Si tu app intenta iniciar un servicio en primer plano desde segundo plano sin cumplir con estos nuevos requisitos (y no tiene otra exención), el sistema arroja ForegroundServiceStartNotAllowedException.

Si tu app declara el permiso SYSTEM_ALERT_WINDOW y, luego, inicia servicios en primer plano desde el segundo plano, es posible que se vea afectada por este cambio. Si tu app obtiene una ForegroundServiceStartNotAllowedException, verifica el orden de operaciones de tu app y asegúrate de que ya tenga una ventana de superposición activa antes de intentar iniciar un servicio en primer plano desde el segundo plano. Puedes verificar si tu ventana de superposición es visible actualmente llamando a View.getWindowVisibility() o puedes anular View.onWindowVisibilityChanged() para recibir notificaciones cada vez que cambie la visibilidad.

Prueba

Para probar el comportamiento de tu app, puedes habilitar estas nuevas restricciones, incluso si tu app no está segmentada para Android 15 (siempre que la app se ejecute en un dispositivo con Android 15). Para habilitar estas nuevas restricciones para iniciar servicios en primer plano desde segundo plano, ejecuta el siguiente comando 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

以 Android 15(API 级别 35)及更高版本为目标平台的应用无法再更改设备上的勿扰 (DND) 功能的全局状态或政策(无论是通过修改用户设置还是关闭勿扰模式)。相反,应用必须提供 AutomaticZenRule,系统会将其与现有的“最严格的政策优先”方案合并为一个全局政策。对之前会影响全局状态的现有 API 的调用(setInterruptionFiltersetNotificationPolicy)会导致创建或更新隐式 AutomaticZenRule,该 AutomaticZenRule 会根据这些 API 调用的调用周期开启和关闭。

请注意,只有当应用调用 setInterruptionFilter(INTERRUPTION_FILTER_ALL) 并希望该调用停用之前由其所有者激活的 AutomaticZenRule 时,此更改才会影响可观察到的行为。

Cambios en la API de OpenJDK

Android 15 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases.

Some of these changes can affect app compatibility for apps targeting Android 15 (API level 35):

  • Changes to string formatting APIs: Validation of argument index, flags, width, and precision are now more strict when using the following String.format() and Formatter.format() APIs:

    For example, the following exception is thrown when an argument index of 0 is used (%0 in the format string):

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    In this case, the issue can be fixed by using an argument index of 1 (%1 in the format string).

  • Changes to component type of Arrays.asList(...).toArray(): When using Arrays.asList(...).toArray(), the component type of the resulting array is now an Object—not the type of the underlying array's elements. So the following code throws a ClassCastException:

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

    For this case, to preserve String as the component type in the resulting array, you could use Collection.toArray(Object[]) instead:

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • Changes to language code handling: When using the Locale API, language codes for Hebrew, Yiddish, and Indonesian are no longer converted to their obsolete forms (Hebrew: iw, Yiddish: ji, and Indonesian: in). When specifying the language code for one of these locales, use the codes from ISO 639-1 instead (Hebrew: he, Yiddish: yi, and Indonesian: id).

  • Changes to random int sequences: Following the changes made in https://bugs.openjdk.org/browse/JDK-8301574, the following Random.ints() methods now return a different sequence of numbers than the Random.nextInt() methods do:

    Generally, this change shouldn't result in app-breaking behavior, but your code shouldn't expect the sequence generated from Random.ints() methods to match Random.nextInt().

The new SequencedCollection API can affect your app's compatibility after you update compileSdk in your app's build configuration to use Android 15 (API level 35):

  • Collision with MutableList.removeFirst() and MutableList.removeLast() extension functions in kotlin-stdlib

    The List type in Java is mapped to the MutableList type in Kotlin. Because the List.removeFirst() and List.removeLast() APIs have been introduced in Android 15 (API level 35), the Kotlin compiler resolves function calls, for example list.removeFirst(), statically to the new List APIs instead of to the extension functions in kotlin-stdlib.

    If an app is re-compiled with compileSdk set to 35 and minSdk set to 34 or lower, and then the app is run on Android 14 and lower, a runtime error is thrown:

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

    The existing NewApi lint option in Android Gradle Plugin can catch these new API usages.

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

    To fix the runtime exception and lint errors, the removeFirst() and removeLast() function calls can be replaced with removeAt(0) and removeAt(list.lastIndex) respectively in Kotlin. If you're using Android Studio Ladybug | 2024.1.3 or higher, it also provides a quick fix option for these errors.

    Consider removing @SuppressLint("NewApi") and lintOptions { disable 'NewApi' } if the lint option has been disabled.

  • Collision with other methods in Java

    New methods have been added into the existing types, for example, List and Deque. These new methods might not be compatible with the methods with the same name and argument types in other interfaces and classes. In the case of a method signature collision with incompatibility, the javac compiler outputs a build-time error. For example:

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

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

    Example 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
    

    To fix these build errors, the class implementing these interfaces should override the method with a compatible return type. For example:

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

Seguridad

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

Versiones de TLS restringidas

Android 15 限制了对 TLS 版本 1.0 和 1.1 的使用。这些版本之前已在 Android 中被弃用,但现在不允许面向 Android 15 的应用使用。

Inicio seguro de actividades en segundo plano

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

Otros cambios

  • Cambia los creadores de PendingIntent para bloquear los inicios de actividad en segundo plano de forma predeterminada. Esto ayuda a evitar que las apps creen accidentalmente un objeto PendingIntent que podría ser utilizado de forma abusiva por agentes maliciosos.
  • No pases una app al primer plano, a menos que el remitente PendingIntent lo permita. El objetivo de este cambio es evitar que las apps maliciosas abusen de la capacidad de iniciar actividades en segundo plano. De forma predeterminada, las apps no pueden llevar la pila de tareas a primer plano, a menos que el creador permita privilegios de inicio de actividad en segundo plano o el remitente tenga privilegios de inicio de actividad en segundo plano.
  • Controla cómo la actividad superior de una pila de tareas puede finalizar su tarea. Si la actividad superior finaliza una tarea, Android volverá a la tarea que estuvo activa por última vez. Además, si una actividad que no está en primer plano finaliza su tarea, Android volverá a la pantalla principal y no bloqueará la finalización de esta actividad que no está en primer plano.
  • Evita iniciar actividades arbitrarias desde otras apps en tu propia tarea. Este cambio evita que las apps maliciosas realicen phishing a los usuarios creando actividades que parecen ser de otras apps.
  • Bloquea las ventanas no visibles para que no se consideren para los inicios de actividad en segundo plano. Esto ayuda a evitar que las apps maliciosas abusen de los inicios de actividad en segundo plano para mostrar contenido no deseado o malicioso a los usuarios.

Intents más seguros

Android 15 针对 intent 引入了 StrictMode

如需查看有关 Intent 使用违规行为的详细日志,请使用以下方法:

Kotlin

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

Java

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

Experiencia del usuario y la IU del sistema

Android 15 incluye algunos cambios que tienen como objetivo crear una experiencia del usuario más coherente e intuitiva.

Cambios en la inserción de ventana

Android 15 中与窗口内边距相关的两项变更:默认强制执行边到边,此外还有配置变更,例如系统栏的默认配置。

全面实施政策

如果应用以 Android 15(API 级别 35)为目标平台,则在搭载 Android 15 的设备上默认以无边框显示。

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


以 Android 15(API 级别 35)为目标平台且在 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_ALWAYSSHORT_EDGESNEVERDEFAULT 会被解读为 ALWAYS,这样用户就不会看到因刘海屏而产生的黑条,并且应用会显示在屏幕的整个边缘。

以下示例展示了应用在以 Android 15(API 级别 35)为目标平台之前和之后,以及在应用边衬区之前和之后的效果。此示例并不全面,在 Android Auto 上可能会显示不同的内容。

以 Android 14 为目标平台且在 Android 15 设备上不是全屏显示的应用。
以 Android 15(API 级别 35)为目标平台且在 Android 15 设备上实现全屏显示的应用。不过,由于 Android 15 的边缘到边缘强制执行,许多元素现在会被状态栏、三按钮导航栏或刘海屏遮挡。隐藏界面包括 Material 2 顶部应用栏、悬浮操作按钮和列表项。
以 Android 15(API 级别 35)为目标平台的应用在 Android 15 设备上是全屏显示,并应用了边衬区,因此界面不会被隐藏。
如果应用已实现全屏显示,需要检查哪些方面

如果您的应用已实现全屏显示并应用边衬区,则基本上不会受到影响,但以下情形除外。不过,即使您认为自己不受影响,我们仍建议您测试应用。

  • 您有一个非浮动窗口,例如使用 SHORT_EDGESNEVERDEFAULT 而不是 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYSActivity。如果您的应用在启动时崩溃,这可能是由启动画面引起的。您可以将核心启动画面依赖项升级到 1.2.0-alpha01 或更高版本,也可以设置 window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
  • 可能存在流量较低且界面被遮挡的屏幕。验证这些访问频率较低的界面是否没有被遮挡的界面。低流量屏幕包括:
    • 初始配置或登录界面
    • “设置”页面
如果您的应用尚未实现全屏显示,需要检查哪些方面

如果您的应用尚未实现全屏显示,则很可能会受到影响。除了已实现全屏显示的边缘到边缘应用的相关场景之外,您还应考虑以下事项:

  • 如果您的应用在 Compose 中使用 Material 3 组件 (androidx.compose.material3),例如 TopAppBarBottomAppBarNavigationBar,这些组件很可能不会受到影响,因为它们会自动处理边衬区。
  • 如果您的应用使用的是 Compose 中的 Material 2 组件 (androidx.compose.material),这些组件不会自动处理边衬区。不过,您可以获得边衬区的访问权限,然后手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,使用 windowInsets 参数可为 BottomAppBarTopAppBarBottomNavigationNavigationRail 手动应用边衬区。 同样,请为 Scaffold 使用 contentWindowInsets 参数。
  • 如果应用使用了视图和 Material 组件 (com.google.android.material),则大多数基于视图的 Material 组件(例如 BottomNavigationViewBottomAppBarNavigationRailViewNavigationView)都会处理边衬区,因此不需要执行额外的操作。不过,如果使用的是 AppBarLayout,则需要添加 android:fitsSystemWindows="true"
  • 对于自定义可组合项,请手动应用边衬区作为内边距。如果您的内容位于 Scaffold 中,则可以使用 Scaffold 内边距值来使用边衬区。否则,请使用 WindowInsets 之一应用内边距。
  • 如果应用使用的是视图和 BottomSheetSideSheet 或自定义容器,请使用 ViewCompat.setOnApplyWindowInsetsListener 应用内边距。对于 RecyclerView,请使用此监听器应用内边距,同时添加 clipToPadding="false"
如果应用必须提供自定义后台保护,您需要检查哪些方面

如果您的应用必须为三按钮导航或状态栏提供自定义背景保护,则应使用 WindowInsets.Type#tappableElement() 获取三按钮导航栏高度或 WindowInsets.Type#statusBars,在系统栏后面放置一个可组合项或视图。

其他全屏显示资源

如需了解有关应用边衬区的其他注意事项,请参阅全屏视图全屏 Compose 指南。

已弃用的 API

以下 API 已弃用,但未停用:

以下 API 已弃用并停用:

稳定配置

Si tu app se segmenta para Android 15 (nivel de API 35) o versiones posteriores, Configuration ya no excluye las barras del sistema. Si usas el tamaño de pantalla en la clase Configuration para el cálculo del diseño, debes reemplazarlo por mejores alternativas, como un ViewGroup, WindowInsets o WindowMetricsCalculator apropiado según tus necesidades.

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

El tamaño de la configuración se suele usar para la selección de recursos, como /res/layout-h500dp, y este sigue siendo un caso de uso válido. Sin embargo, siempre se desaconsejó usarlo para el cálculo del diseño. Si es así, debes alejarte de él ahora. Debes reemplazar el uso de Configuration por algo más adecuado según tu caso de uso.

Si lo usas para calcular el diseño, usa 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 conocer el tamaño actual de la ventana de tu app, usa computeCurrentWindowMetrics.

En la siguiente lista, se describen los campos afectados por este cambio:

El atributo elegantTextHeight tiene el valor predeterminado establecido en verdadero.

对于以 Android 15(API 级别 35)为目标平台的应用,elegantTextHeight TextView 属性默认会变为 true,将默认使用的紧凑字体替换为一些具有较大垂直测量的脚本,使其更易于阅读。紧凑字体旨在防止布局中断;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing 属性拉伸垂直高度,从而防止许多此类中断。

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

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

El ancho de TextView cambia para formas de letras complejas

在以前的 Android 版本中,某些具有复杂形状的手写字体或语言可能会在上一个或下一个字符的区域绘制字母。在某些情况下,此类字母会在开头或结尾处被剪裁。从 Android 15 开始,TextView 会分配宽度,以便为此类字母绘制足够的空间,并允许应用请求向左额外添加内边距以防止剪裁。

由于此更改会影响 TextView 确定宽度的方式,因此如果应用以 Android 15(API 级别 35)或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。

由于添加左内边距可能会导致现有布局未对齐,因此默认情况下不会添加内边距,即使以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 setShiftDrawingOffsetForStartOverhang 添加额外的内边距以防止剪裁。

以下示例展示了这些更改如何改进某些字体和语言的文本布局。

采用手写体字体的英语文本的标准布局。部分字母被截断。对应的 XML 如下:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
相同英语文本的布局,增加了宽度和内边距。以下是相应的 XML:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
泰语文本的标准布局。部分字母被截断。 以下是相应的 XML:

<TextView
    android:text="คอมพิวเตอร์" />
相同泰语文本的布局,增加了宽度和内边距。以下是相应的 XML:

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

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

在较低版本的 Android 中,文本布局会拉伸文本的高度,以满足与当前语言区域匹配的字体的行高。例如,如果内容是日语,由于日语字体的行高略高于拉丁字体,因此文本的高度会略高。不过,尽管行高存在这些差异,但无论使用的是哪种语言区域,EditText 元素的大小都是统一的,如下图所示:

三个框,表示可以包含英语 (en)、日语 (ja) 和缅甸语 (my) 文本的 EditText 元素。EditText 的高度相同,即使这些语言的行高各不相同。

对于以 Android 15(API 级别 35)为目标平台的应用,现在为 EditText 预留了最小行高,以匹配指定语言区域的参考字体,如下图所示:

三个框,表示可以包含英语 (en)、日语 (ja) 和缅甸语 (my) 文本的 EditText 元素。EditText 的高度现在包含足够的空间来容纳这些语言字体的默认行高。

如有需要,您的应用可以将 useLocalePreferredLineHeightForMinimum 属性指定为 false,以恢复之前的行为;您的应用还可以在 Kotlin 和 Java 中使用 setMinimumFontMetrics API 设置自定义最小垂直指标。

Cámara y contenido multimedia

Android 15 realiza los siguientes cambios en el comportamiento de la cámara y los medios para las apps que se segmentan para Android 15 o versiones posteriores.

Restricciones para solicitar el foco de audio

以 Android 15(API 级别 35)为目标平台的应用必须是顶部应用或正在运行前台服务,才能请求音频焦点。如果应用在未满足上述任一要求的情况下尝试请求焦点,调用将返回 AUDIOFOCUS_REQUEST_FAILED

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

Actualización de restricciones que no pertenecen al SDK

Android 15 incluye listas actualizadas de este tipo de interfaces que están basadas en la colaboración con desarrolladores de Android y las pruebas internas más recientes. 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á segmentada para Android 15, es posible que algunos de estos cambios no te afecten de inmediato. Sin embargo, aunque tu app puede acceder a algunas interfaces que no pertenecen al SDK según el nivel de API objetivo de tu app, usar cualquier método o campo que no pertenezca al SDK siempre implica un gran riesgo de error para tu app.

Si no sabes con seguridad si tu app usa este tipo de interfaces, puedes probarla para verificar. Si tu app depende de interfaces que no pertenecen al SDK, deberías planificar una migración hacia otras alternativas SDK. Sin embargo, sabemos que algunas apps tienen casos de uso válidos para usar interfaces que no pertenecen al SDK. Si no encuentras una alternativa al uso de una interfaz que no pertenece al SDK para una función de tu app, deberías solicitar una nueva API pública.

如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制