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 amplía varias funciones principales del sistema Android.
Cambios en los servicios en primer plano
Realizamos 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 en 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 de tiempo de espera del servicio en primer plano de la sincronización de datos
对于以 Android 15(API 级别 35)或更高版本为目标平台的应用,Android 15 为 dataSync
引入了新的超时行为。此行为也适用于新的 mediaProcessing
前台服务类型。
系统允许应用的 dataSync
服务在 24 小时内共运行 6 小时,之后系统会调用正在运行的服务的 Service.onTimeout(int, int)
方法(在 Android 15 中引入)。此时,服务有几秒钟的时间来调用 Service.stopSelf()
。调用 Service.onTimeout()
后,该服务将不再被视为前台服务。如果服务未调用 Service.stopSelf()
,系统会抛出内部异常。系统会在 Logcat 中记录此异常,并显示以下消息:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
为避免此行为变更出现问题,您可以执行以下一项或多项操作:
- 让您的服务实现新的
Service.onTimeout(int, int)
方法。当应用收到回调时,请务必在几秒钟内调用stopSelf()
。(如果您不立即停止应用,系统会生成故障。) - 确保应用的
dataSync
服务在任何 24 小时内总运行时间不超过 6 小时(除非用户与应用互动,重置计时器)。 - 仅在有直接用户互动时启动
dataSync
前台服务;由于服务启动时应用位于前台,因此您的服务在应用进入后台后有完整的 6 小时时间。 - 请使用替代 API,而不是使用
dataSync
前台服务。
如果您的应用的 dataSync
前台服务在过去 24 小时内运行了 6 小时,则您无法启动其他 dataSync
前台服务,除非用户已将您的应用切换到前台(这会重置计时器)。如果您尝试启动其他 dataSync
前台服务,系统会抛出 ForegroundServiceStartNotAllowedException
,并显示类似“前台服务类型 dataSync 的时间限制已用尽”的错误消息。
测试
如需测试应用的行为,即使您的应用并非以 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 data_sync_fgs_timeout_duration duration-in-milliseconds
Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia
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]"
为避免出现此异常,您可以执行以下任一操作:
- 让您的服务实现新的
Service.onTimeout(int, int)
方法。当您的应用收到回调时,请务必在几秒钟内调用stopSelf()
。(如果您未立即停止应用,系统会生成失败情况。) - 确保应用的
mediaProcessing
服务在任何 24 小时内总运行时间不超过 6 小时(除非用户与应用互动,重置计时器)。 - 仅在有直接用户互动时启动
mediaProcessing
前台服务;由于服务启动时应用位于前台,因此您的服务在应用进入后台后有完整的 6 小时时间。 - 请改用 替代 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
Restricciones en los receptores de emisión de BOOT_COMPLETED
que lanzan servicios en primer plano
There are new restrictions on BOOT_COMPLETED
broadcast receivers launching
foreground services. BOOT_COMPLETED
receivers are not allowed to launch the
following types of foreground services:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(this restriction has been in place formicrophone
since Android 14)
If a BOOT_COMPLETED
receiver tries to launch any of those types of foreground
services, the system throws ForegroundServiceStartNotAllowedException
.
Testing
To test your app's behavior, you can enable these new restrictions even if your
app is not targeting Android 15 (as long as the app is running on an Android 15
device). Run the following adb
command:
adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name
To send a BOOT_COMPLETED
broadcast without restarting the device,
run the following adb
command:
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
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
Se modificaron los momentos en que las apps pueden modificar el estado global del modo No interrumpir.
以 Android 15 为目标平台的应用无法再更改设备上的全局状态或勿扰 (DND) 政策(通过修改用户设置或关闭 DND 模式)。相反,应用必须提供一个 AutomaticZenRule
,系统会将后者合并到一个具有现有最严格的政策胜出方案的全局政策中。调用之前影响全局状态的现有 API(setInterruptionFilter
、setNotificationPolicy
)会导致创建或更新隐式 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()
andFormatter.format()
APIs:String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
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 usingArrays.asList(...).toArray()
, the component type of the resulting array is now anObject
—not the type of the underlying array's elements. So the following code throws aClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
For this case, to preserve
String
as the component type in the resulting array, you could useCollection.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 theRandom.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 matchRandom.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()
andMutableList.removeLast()
extension functions inkotlin-stdlib
The
List
type in Java is mapped to theMutableList
type in Kotlin. Because theList.removeFirst()
andList.removeLast()
APIs have been introduced in Android 15 (API level 35), the Kotlin compiler resolves function calls, for examplelist.removeFirst()
, statically to the newList
APIs instead of to the extension functions inkotlin-stdlib
.If an app is re-compiled with
compileSdk
set to35
andminSdk
set to34
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()
andremoveLast()
function calls can be replaced withremoveAt(0)
andremoveAt(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")
andlintOptions { 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
andDeque
. 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, thejavac
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 ListExample 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 errorExample 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 errorTo 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 a las apps y a los usuarios de las apps maliciosas.
Inicios de actividades en segundo plano seguros
Android 15 protects users from malicious apps and gives them more control over their devices by adding changes that prevent malicious background apps from bringing other apps to the foreground, elevating their privileges, and abusing user interaction. Background activity launches have been restricted since Android 10 (API level 29).
Other changes
In addition to the restriction for UID matching, these other changes are also included:
- Change
PendingIntent
creators to block background activity launches by default. This helps prevent apps from accidentally creating aPendingIntent
that could be abused by malicious actors. - Don't bring an app to the foreground unless the
PendingIntent
sender allows it. This change aims to prevent malicious apps from abusing the ability to start activities in the background. By default, apps are not allowed to bring the task stack to the foreground unless the creator allows background activity launch privileges or the sender has background activity launch privileges. - Control how the top activity of a task stack can finish its task. If the top activity finishes a task, Android will go back to whichever task was last active. Moreover, if a non-top activity finishes its task, Android will go back to the home screen; it won't block the finish of this non-top activity.
- Prevent launching arbitrary activities from other apps into your own task. This change prevents malicious apps from phishing users by creating activities that appear to be from other apps.
- Block non-visible windows from being considered for background activity launches. This helps prevent malicious apps from abusing background activity launches to display unwanted or malicious content to users.
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
Android 15 中有两个与窗口边衬区相关的变更:默认强制执行无边框模式;还存在配置变更,例如系统栏的默认配置。
全面实施政策
Las apps son de borde a borde de forma predeterminada en dispositivos que ejecutan Android 15 si se orientan a Android 15 (nivel de API 35).
Este es un cambio rotundo que podría afectar de forma negativa la IU de tu app. Los cambios afectan las siguientes áreas de la IU:
- Barra de navegación con control de gestos
- Es transparente de forma predeterminada.
- El desplazamiento inferior está inhabilitado, por lo que el contenido se dibuja detrás de la barra de navegación del sistema, a menos que se apliquen las inserciones.
setNavigationBarColor
yR.attr#navigationBarColor
dejaron de estar disponibles y no afectan la navegación por gestos.setNavigationBarContrastEnforced
yR.attr#navigationBarContrastEnforced
siguen sin tener efecto en la navegación por gestos.
- Navegación con 3 botones
- La opacidad está configurada en un 80% de forma predeterminada, y el color puede coincidir con el fondo de la ventana.
- Se inhabilitó el desplazamiento inferior para que el contenido se dibuje detrás de la barra de navegación del sistema, a menos que se apliquen inserciones.
setNavigationBarColor
yR.attr#navigationBarColor
se configuran para que coincidan 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 dejó de estar disponible, pero sigue afectando la navegación de 3 botones.setNavigationBarContrastEnforced
yR.attr#navigationBarContrastEnforced
son verdaderos 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 para que el contenido se dibuje detrás de la barra de estado, a menos que se apliquen inserciones.
setStatusBarColor
yR.attr#statusBarColor
dejaron de estar disponibles y no tienen ningún efecto en Android 15.setStatusBarContrastEnforced
yR.attr#statusBarContrastEnforced
dejaron de estar disponibles, pero aún tienen un efecto en Android 15.
- Recorte de la pantalla
layoutInDisplayCutoutMode
de las ventanas no flotantes debe serLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
.SHORT_EDGES
,NEVER
yDEFAULT
se interpretan comoALWAYS
para que los usuarios no vean una barra negra causada por el corte de la pantalla y se muestren de borde a borde.
En el siguiente ejemplo, se muestra una app antes y después de orientarla a Android 15 (nivel de API 35), así como antes y después de aplicar las inserciones.
Qué verificar si tu app ya es de borde a borde
Si tu app ya es de borde a borde y aplica inserciones, tu mayor parte no será afectada, excepto en las siguientes situaciones. Sin embargo, incluso si crees que no te afectará, te recomendamos que pruebes tu app.
- Tienes una ventana no flotante, como una
Activity
que usaSHORT_EDGES
,NEVER
oDEFAULT
en lugar deLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
. Si tu app falla durante el inicio, es posible que se deba a la pantalla de presentación. Puedes actualizar la dependencia de splashscreen principal a 1.2.0-alpha01 o una versión posterior, o bien establecerwindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
. - Puede haber pantallas con menos tráfico y una IU ocluida. Verifica que estas pantallas menos visitadas no tengan una IU ocluida. Entre las pantallas con menos tráfico, se incluyen las siguientes:
- Pantallas de integración o acceso
- Páginas de configuración
Qué verificar si tu app aún no es de borde a borde
Si tu app aún no es de borde a borde, es probable que se vea afectada. Además de las situaciones de las apps que ya son de borde a borde, debes tener en cuenta lo siguiente:
- Si tu app usa componentes de Material 3 (
androidx.compose.material3
) en Compose, comoTopAppBar
,BottomAppBar
yNavigationBar
, es probable que estos componentes no se vean afectados porque controlan automáticamente las inserciones. - Si tu app usa componentes de Material 2 (
androidx.compose.material
) en Compose, estos no controlan las inserciones automáticamente. Sin embargo, puedes obtener acceso a las inserciones y aplicarlas manualmente. En androidx.compose.material 1.6.0 y versiones posteriores, usa el parámetrowindowInsets
para aplicar las inserciones de forma manual paraBottomAppBar
,TopAppBar
,BottomNavigation
yNavigationRail
. De la misma manera, usa el parámetrocontentWindowInsets
paraScaffold
. - Si tu app usa vistas y componentes de Material (
com.google.android.material
), la mayoría de los componentes de Material basados en vistas, comoBottomNavigationView
,BottomAppBar
,NavigationRailView
oNavigationView
, controlan las inserciones y no requieren trabajo adicional. Sin embargo, debes agregarandroid:fitsSystemWindows="true"
si usasAppBarLayout
. - Para los elementos componibles personalizados, aplica las inserciones de forma manual como relleno. Si tu contenido está dentro de un
Scaffold
, puedes consumir inserciones con los valores de paddingScaffold
. De lo contrario, aplica el padding con uno de losWindowInsets
. - Si tu app usa vistas y
BottomSheet
,SideSheet
o contenedores personalizados, aplica relleno conViewCompat.setOnApplyWindowInsetsListener
. ParaRecyclerView
, aplica padding con este objeto de escucha y, además, agregaclipToPadding="false"
.
Qué verifica si tu app debe ofrecer protección personalizada de fondo
Si tu app debe ofrecer una protección personalizada en segundo plano para la navegación con 3 botones o la barra de estado, debería colocar un elemento componible o una vista detrás de la barra del sistema con WindowInsets.Type#tappableElement()
para obtener la altura de la barra de navegación de 3 botones o WindowInsets.Type#statusBars
.
Recursos adicionales de borde a borde
Consulta las guías Views de borde a borde y Compose de borde a borde para obtener más información sobre la aplicación de inserciones.
APIs obsoletas
Las siguientes APIs dejaron de estar disponibles, pero no están inhabilitadas:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
(para la navegación con 3 botones, con un 80% de alfa)Window#isStatusBarContrastEnforced
Window#setNavigationBarColor
(para la navegación con 3 botones, con un 80% de alfa)Window#setStatusBarContrastEnforced
Las siguientes APIs dejaron de estar disponibles y están inhabilitadas:
R.attr#navigationBarColor
(para la navegación por gestos)R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#setDecorFitsSystemWindows
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#setNavigationBarColor
(para la navegación por gestos)Window#setNavigationBarDividerColor
Window#setStatusBarColor
稳定配置
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 que se verán 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 cercanos al cuadrado.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 eleganteTextHeight se establece en verdadero de forma predeterminada
对于以 Android 15 为目标平台的应用,elegantTextHeight
TextView
属性默认变为 true
,将默认使用的紧凑字体替换为一些具有较大垂直指标的脚本,并且这种字体更易于阅读。紧凑字体的引入是为了防止破坏布局;Android 13(API 级别 33)允许文本布局利用 fallbackLineSpacing
属性拉伸垂直高度,以防止许多此类破坏。
在 Android 15 中,紧凑字体仍保留在系统中,因此您的应用可以将 elegantTextHeight
设置为 false
,以获得与之前相同的行为,但即将在未来版本中提供支持。因此,如果您的应用支持以下文字:阿拉伯语、老挝语、缅甸、泰米尔语、古吉拉特语、卡纳达语、马拉雅拉姆语、奥里亚语、泰卢固语或泰语,请将 elegantTextHeight
设置为 true
,以测试应用。
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.
Altura de línea predeterminada 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:
For apps targeting Android 15 (API level 35), a minimum line height is now
reserved for EditText
to match the reference font for the specified Locale, as
shown in the following image:
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
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 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 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.
如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。