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á 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 targetSdkVersion
de la app.
Funcionalidad principal
Android 15 modifica o expande varias funciones principales del sistema Android.
Cambios en los servicios en primer plano
Realizaremos los siguientes cambios en los servicios en primer plano con Android 15.
- Comportamiento de tiempo de espera del servicio en primer plano de sincronización de datos
- Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia
- Restricciones para los receptores de emisión
BOOT_COMPLETED
que inician servicios en primer plano - Restricciones para iniciar servicios en primer plano mientras una app tiene el permiso
SYSTEM_ALERT_WINDOW
Comportamiento del tiempo de espera del servicio en primer plano de sincronización de datos
Android 15 introduce un nuevo comportamiento de tiempo de espera en dataSync
para las apps orientadas 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:
- 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 astopSelf()
en unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera una falla). - 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). - Solo inicia los servicios en primer plano de
dataSync
como resultado de la interacción directa del usuario. Dado que tu app está en primer plano cuando se inicia el servicio, el servicio tiene seis horas completas después de que la app pasa a segundo plano. - 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
Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia
Android 15 presenta un nuevo tipo de servicio en primer plano: mediaProcessing
. Este tipo de servicio es adecuado para operaciones como la transcodificación de archivos multimedia. Por ejemplo, una app de música puede descargar un archivo de audio y necesitar convertirlo a un formato diferente antes de reproducirlo. Puedes usar un servicio en primer plano mediaProcessing
para asegurarte de que la conversión continúe incluso mientras la app está en segundo plano.
El sistema permite que los servicios mediaProcessing
de una app se ejecuten durante un total de 6 horas en un período de 24 horas, después del 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()
. 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 mediaProcessing did not stop within its timeout: [component name]"
Para evitar tener la excepción, puedes realizar una de las siguientes acciones:
- 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 astopSelf()
en unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera una falla). - Asegúrate de que los servicios
mediaProcessing
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). - Inicia servicios en primer plano de
mediaProcessing
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. - En lugar de usar un servicio en primer plano de
mediaProcessing
, usa una API alternativa, como WorkManager.
Si los servicios en primer plano de mediaProcessing
de tu app se ejecutaron durante 6 horas durante las últimas 24, no puedes iniciar otro servicio mediaProcessing
en primer plano, a menos que el usuario haya llevado la app al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio en primer plano mediaProcessing
, el sistema arroja ForegroundServiceStartNotAllowedException
con un mensaje de error como "Se agotó el tiempo límite para el tipo de servicio en primer plano mediaProcessing".
Para obtener más información sobre el tipo de servicio mediaProcessing
, consulta Cambios en los tipos de servicios en primer plano para Android 15: Procesamiento de contenido multimedia.
Prueba
Para probar el comportamiento de tu app, puedes habilitar los tiempos de espera de procesamiento de contenido multimedia, incluso si tu app no está orientada a Android 15 (siempre que se ejecute en un dispositivo con 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 tiempo de espera, ejecuta el siguiente comando adb
:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
Restricciones para los receptores de emisión BOOT_COMPLETED
que inician servicios en primer plano
Hay nuevas restricciones para los receptores de emisión de BOOT_COMPLETED
que se lanzan
servicios en primer plano. Los receptores BOOT_COMPLETED
no pueden iniciar los siguientes tipos de servicios en primer plano:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(esta restricción se aplicó pormicrophone
desde el Android 14)
Si un receptor BOOT_COMPLETED
intenta iniciar cualquiera de esos tipos de primer plano.
servicios, el sistema arroja una ForegroundServiceStartNotAllowedException
.
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). Ejecuta el siguiente comando adb
:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
Para enviar una transmisión de BOOT_COMPLETED
sin reiniciar el dispositivo, haz lo siguiente:
Ejecuta el siguiente comando adb
:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name
Restricciones para iniciar servicios en primer plano mientras una app tiene el permiso 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
Se modificaron los momentos en que las apps pueden modificar el estado global del modo No interrumpir.
Las apps que se orientan a Android 15 (nivel de API 35) y versiones posteriores ya no pueden cambiar el estado o la política globales de No interrumpir (ND) en un dispositivo (ya sea modificando la configuración del usuario o desactivando el modo ND). En su lugar, las apps deben contribuir con un AutomaticZenRule
, que el sistema combina en una política global con el esquema existente de política más restrictiva. Las llamadas a las APIs existentes que antes afectaban el estado global (setInterruptionFilter
, setNotificationPolicy
) generan la creación o actualización de un AutomaticZenRule
implícito, que se activa o 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 un AutomaticZenRule
que sus propietarios activaron anteriormente.
Cambios en la API de OpenJDK
Android 15 continúa la tarea de actualizar las bibliotecas principales de Android para alinearlas con las funciones de las versiones más recientes de LTS de OpenJDK.
Algunos de estos cambios pueden afectar la compatibilidad de las apps que se orientan a Android 15 (nivel de API 35):
Cambios en las APIs de formato de cadenas: La validación del índice de argumentos, las marcas, la precisión y el ancho ahora es más estricta cuando se usan las siguientes APIs de
String.format()
yFormatter.format()
:String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
Por ejemplo, se genera la siguiente excepción cuando se usa un índice de argumento de 0 (
%0
en la cadena de formato):IllegalFormatArgumentIndexException: Illegal format argument index = 0
En este caso, el problema se puede solucionar con un índice de argumento de 1 (
%1
en la cadena de formato).Cambios en el tipo de componente de
Arrays.asList(...).toArray()
: Cuando se usaArrays.asList(...).toArray()
, el tipo de componente del array resultante ahora esObject
, no el tipo de los elementos del array subyacente. Por lo tanto, el siguiente código arroja unClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
En este caso, para conservar
String
como el tipo de componente en el array resultante, puedes usarCollection.toArray(Object[])
en su lugar:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
Cambios en el manejo de códigos de idioma: Cuando usas la API de
Locale
, los códigos de idioma para hebreo, yiddish e indonesio ya no se convierten a sus formas obsoletas (hebreo:iw
, yiddish:ji
e indonesio:in
). Cuando especifiques el código de idioma de una de estas configuraciones regionales, usa los códigos de ISO 639-1 (hebreo:he
, yiddish:yi
e indonesio:id
).Cambios en las secuencias de int aleatorias: Después de los cambios realizados en https://bugs.openjdk.org/browse/JDK-8301574, los siguientes métodos
Random.ints()
ahora muestran una secuencia de números diferente a la de los métodosRandom.nextInt()
:Por lo general, este cambio no debería provocar un comportamiento que interrumpa la app, pero tu código no debería esperar que la secuencia generada a partir de los métodos
Random.ints()
coincida conRandom.nextInt()
.
La nueva API de SequencedCollection
puede afectar la compatibilidad de tu app después de que actualices compileSdk
en la configuración de compilación de tu app para usar Android 15 (nivel de API 35):
Colisión con las funciones de extensión
MutableList.removeFirst()
yMutableList.removeLast()
enkotlin-stdlib
El tipo
List
en Java se asigna al tipoMutableList
en Kotlin. Debido a que las APIs deList.removeFirst()
yList.removeLast()
se introdujeron en Android 15 (nivel de API 35), el compilador de Kotlin resuelve las llamadas a función, por ejemplo,list.removeFirst()
, de forma estática a las nuevas APIs deList
en lugar de a las funciones de extensión enkotlin-stdlib
.Si una app se vuelve a compilar con
compileSdk
establecido en35
yminSdk
establecido en34
o una versión anterior, y luego se ejecuta en Android 14 y versiones anteriores, se genera un error de tiempo de ejecución:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
La opción de lint
NewApi
existente en el complemento de Android para Gradle puede detectar estos nuevos usos de la API../gradlew lint
MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()Para corregir la excepción de tiempo de ejecución y los errores de lint, las llamadas a las funciones
removeFirst()
yremoveLast()
se pueden reemplazar porremoveAt(0)
yremoveAt(list.lastIndex)
, respectivamente, en Kotlin. Si usas Android Studio Ladybug | 2024.1.3 o versiones posteriores, también proporciona una opción de solución rápida para estos errores.Considera quitar
@SuppressLint("NewApi")
ylintOptions { disable 'NewApi' }
si se inhabilitó la opción lint.Colisión con otros métodos en Java
Se agregaron métodos nuevos a los tipos existentes, por ejemplo,
List
yDeque
. Es posible que estos métodos nuevos no sean compatibles con los métodos que tienen el mismo nombre y los mismos tipos de argumentos en otras interfaces y clases. En el caso de una colisión de firma de método con incompatibilidad, el compiladorjavac
muestra un error de tiempo de compilación. Por ejemplo:Ejemplo de 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 ListEjemplo de 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 errorEjemplo de 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 errorPara corregir estos errores de compilación, la clase que implementa estas interfaces debe reemplazar el método con un tipo de devolución compatible. Por ejemplo:
@Override public Object getFirst() { return List.super.getFirst(); }
Seguridad
Android 15 incluye cambios que promueven la seguridad del sistema para ayudar a proteger a las apps y a los usuarios de las apps maliciosas.
Versiones de TLS restringidas
Android 15 restringe el uso de las versiones 1.0 y 1.1 de TLS. Estas versiones ya habían dejado de estar disponibles en Android, pero ahora no se permiten para las apps que se orientan a Android 15.
Inicios de actividades en segundo plano seguros
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 accidentalmentePendingIntent
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 presenta nuevas medidas de seguridad opcionales para que los intents sean más seguros y sólidos. El objetivo de estos cambios es evitar posibles vulnerabilidades y el uso inadecuado de intents que pueden aprovechar las apps maliciosas. Hay dos mejoras principales en la seguridad de los intents en Android 15:
- Coincidir con filtros de intents de destino: Los intents que se orientan a componentes específicos deben coincidir de forma precisa con las especificaciones de filtros de intents del destino. Si envías un intent para iniciar la actividad de otra app, el componente de intent de destino debe alinearse con los filtros de intents declarados de la actividad receptora.
- Los intents deben tener acciones: Los intents sin una acción ya no coincidirán con ningún filtro de intents. Esto significa que los intents que se usan para iniciar actividades o servicios deben tener una acción claramente definida.
Para verificar cómo responde tu app a estos cambios, usa StrictMode
en tu app. Para ver registros detallados sobre los incumplimientos de uso de Intent
, agrega el siguiente método:
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
Experiencia del usuario y IU del sistema
Android 15 incluye algunos cambios que tienen como objetivo crear una experiencia del usuario más intuitiva y coerente.
Cambios en la inserción de ventana
Hay dos cambios relacionados con los insertos de ventana en Android 15: el modo de pantalla completa 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
如果应用以 Android 15(API 级别 35)为目标平台,则在搭载 Android 15 的设备上默认以无边框显示。

这是一项重大变更,可能会对应用的界面产生负面影响。这些变更会影响以下界面区域:
- 手势处理程序导航栏
- 默认透明。
- 底部偏移量处于停用状态,因此除非应用边衬区,否则内容会绘制在系统导航栏后面。
setNavigationBarColor
和R.attr#navigationBarColor
已废弃,不会影响手势导航。setNavigationBarContrastEnforced
和R.attr#navigationBarContrastEnforced
对手势导航的影响仍然不变。
- “三按钮”导航
- 默认情况下,不透明度设置为 80%,颜色可能与窗口背景相匹配。
- 底部偏移量处于停用状态,因此除非应用边衬区,否则内容会绘制在系统导航栏后面。
- 默认情况下,
setNavigationBarColor
和R.attr#navigationBarColor
会设置为与窗口背景相匹配。窗口背景必须是彩色可绘制对象,此默认值才能应用。此 API 已废弃,但仍会影响三按钮导航栏。 setNavigationBarContrastEnforced
和R.attr#navigationBarContrastEnforced
默认均为 true,这会在三按钮导航栏中添加 80% 不透明的背景。
- 状态栏
- 默认透明。
- 顶部偏移量处于停用状态,因此除非应用边衬区,否则内容会绘制在状态栏后面。
setStatusBarColor
和R.attr#statusBarColor
已废弃,对 Android 15 没有任何影响。setStatusBarContrastEnforced
和R.attr#statusBarContrastEnforced
已废弃,但对 Android 15 仍有影响。
- 刘海屏
- 非浮动窗口的
layoutInDisplayCutoutMode
必须为LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
。SHORT_EDGES
、NEVER
和DEFAULT
会被解读为ALWAYS
,以便用户不会看到由显示屏缺口导致的黑条,并且显示屏会从边到边显示内容。
- 非浮动窗口的
以下示例展示了应用在以 Android 15(API 级别 35)为目标平台之前和之后,以及应用内边距之前和之后的效果。



如何检查应用是否已采用边到边设计
如果您的应用已经是边到边且应用了内边距,则除以下情况外,您大多不会受到影响。不过,即使您认为自己没有受到影响,我们也建议您测试应用。
- 您有一个非浮动窗口,例如使用
SHORT_EDGES
、NEVER
或DEFAULT
(而非LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
)的Activity
。如果您的应用在启动时崩溃,这可能是因为您的启动画面存在问题。您可以将核心启动画面依赖项升级到 1.2.0-alpha01 或更高版本,也可以设置window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
。 - 有些流量较低的屏幕可能存在遮挡界面的情况。验证这些访问次数较少的屏幕是否存在遮挡的界面。流量较低的屏幕包括:
- 初始配置或登录屏幕
- “设置”页面
如果您的应用尚未采用边到边设计,应检查哪些方面
如果您的应用尚未采用边到边设计,您很可能受到影响。除了已经采用边到边设计的应用的场景之外,您还应考虑以下情况:
- 如果您的应用在 Compose 中使用 Material 3 组件 (
androidx.compose.material3
),例如TopAppBar
、BottomAppBar
和NavigationBar
,这些组件可能不会受到影响,因为它们会自动处理边衬区。 - 如果应用使用的是 Compose 中的 Material 2 组件 (
androidx.compose.material
),这些组件本身并不会自动处理边衬区。不过,您可以获得边衬区的访问权限,然后手动应用边衬区。在 androidx.compose.material 1.6.0 及更高版本中,使用windowInsets
参数可为BottomAppBar
、TopAppBar
、BottomNavigation
和NavigationRail
手动应用边衬区。同样,请为Scaffold
使用contentWindowInsets
参数。 - 如果应用使用了 View 和 Material 组件 (
com.google.android.material
),则大多数基于 View 的 Material 组件(例如BottomNavigationView
、BottomAppBar
、NavigationRailView
或NavigationView
)都会处理边衬区,因此不需要执行额外的操作。不过,如果使用的是AppBarLayout
,则需要添加android:fitsSystemWindows="true"
。 - 对于自定义可组合项,请手动将边衬区应用为内边距。如果您的内容位于
Scaffold
中,您可以使用Scaffold
内边距值使用内边距。否则,请使用WindowInsets
之一应用内边距。 - 如果应用使用的是 View 和
BottomSheet
、SideSheet
或自定义容器,请使用ViewCompat.setOnApplyWindowInsetsListener
应用内边距。对于RecyclerView
,请使用此监听器应用内边距,同时添加clipToPadding="false"
。
如果您的应用必须提供自定义后台保护,应检查哪些方面
如果您的应用必须为三按钮导航栏或状态栏提供自定义背景保护,则应使用 WindowInsets.Type#tappableElement()
在系统栏后面放置可组合项或视图,以获取三按钮导航栏高度或 WindowInsets.Type#statusBars
。
其他端到端资源
如需了解有关应用内边距的其他注意事项,请参阅边到边视图和边到边 Compose 指南。
已弃用的 API
以下 API 已废弃,但并未停用:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
(适用于三按钮导航,透明度为 80%)Window#isStatusBarContrastEnforced
Window#setNavigationBarColor
(适用于三按钮导航,透明度为 80%)Window#setStatusBarContrastEnforced
以下 API 已废弃并停用:
R.attr#navigationBarColor
(适用于手势导航)R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#setDecorFitsSystemWindows
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#setNavigationBarColor
(适用于手势导航)Window#setNavigationBarDividerColor
Window#setStatusBarColor
Configuración estable
Si tu app está orientada a 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
apropiados 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, orientación y tamaño de la ventana. Una característica importante de los tamaños de ventana que se muestran desde Configuration
es que anteriormente excluía las barras del sistema.
El tamaño de configuración suele usarse 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ó su uso para el cálculo del diseño. Si es así, debes alejarte 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:
- Los tamaños
Configuration.screenWidthDp
yscreenHeightDp
ya no excluyen las barras del sistema. Configuration.smallestScreenWidthDp
se ve afectado indirectamente por los cambios enscreenWidthDp
yscreenHeightDp
.Configuration.orientation
se ve afectado indirectamente por los cambios enscreenWidthDp
yscreenHeightDp
en dispositivos casi cuadrados.Display.getSize(Point)
se ve afectado indirectamente por los cambios enConfiguration
. Este elemento dejó de estar disponible a partir del nivel de API 30.Display.getMetrics()
ya funciona de esta manera desde el nivel de API 33.
El atributo elegantTextHeight tiene el valor predeterminado de verdadero.
对于以 Android 15(API 级别 35)为目标平台的应用,elegantTextHeight
TextView
属性默认会变为 true
,将默认使用的紧凑字体替换为一些具有较大垂直测量的脚本,使其更易于阅读。紧凑字体旨在防止布局中断;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing
属性拉伸垂直高度,从而防止许多此类中断。
在 Android 15 中,系统中仍保留了紧凑字体,因此您的应用可以将 elegantTextHeight
设置为 false
以获得与之前相同的行为,但即将发布的版本不太可能支持此字体。因此,如果您的应用支持以下脚本:阿拉伯语、老挝语、缅甸语、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight
设置为 true
以测试您的应用。

elegantTextHeight
行为。
elegantTextHeight
行为。Cambios en el ancho de TextView para formas de letras complejas
En versiones anteriores de Android, algunas fuentes o idiomas en cursiva que tienen formas complejas podrían dibujar las letras en el área del carácter anterior o siguiente.
En algunos casos, esas letras se cortaron al principio o al final.
A partir de Android 15, un TextView
asigna ancho para dibujar suficiente espacio para esas letras y permite que las apps soliciten paddings adicionales a la izquierda para evitar los 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) o versiones posteriores. Para habilitar o inhabilitar este comportamiento, llama a la API de setUseBoundsForWidth
en TextView
.
Como agregar padding izquierdo puede causar un desajuste en 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 de texto para algunas fuentes y algunos idiomas.

<TextView android:fontFamily="cursive" android:text="java" />

<TextView android:fontFamily="cursive" android:text="java" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />

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

<TextView android:text="คอมพิวเตอร์" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
Altura de línea predeterminada que se adapta a la configuración regional para EditText
在较低版本的 Android 中,文本布局会拉伸文本的高度,以满足与当前语言区域匹配的字体的行高。例如,如果内容是日语,由于日语字体的行高略高于拉丁字体,因此文本的高度会略高。不过,尽管行高存在这些差异,但无论使用的是哪种语言区域,EditText
元素的大小都是统一的,如下图所示:

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

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 el contenido multimedia para las apps orientadas a Android 15 o versiones posteriores.
Restricciones para solicitar el foco de audio
Las apps que se orientan a Android 15 (nivel de API 35) deben ser la app principal o ejecutar un servicio en primer plano para solicitar el enfoque de audio. Si una app intenta solicitar el enfoque cuando no cumple con uno de estos requisitos, la llamada muestra AUDIOFOCUS_REQUEST_FAILED
.
Puedes obtener más información sobre el enfoque de audio en Administra el enfoque de audio.
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á orientada a Android 15, es posible que algunos de estos cambios no te afecten de inmediato. Sin embargo, si bien es posible que tu app acceda a algunas interfaces que no pertenecen al SDK según el nivel de API objetivo, 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 verificarlo. 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 usarlas. 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.
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.