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
我们将对 Android 15 中的前台服务进行以下更改。
数据同步前台服务超时行为
Android 15 introduces a new timeout behavior to dataSync
for apps targeting
Android 15 (API level 35) or higher. This behavior also applies to the new
mediaProcessing
foreground service type.
The system permits an app's dataSync
services to run for a total of 6 hours
in a 24-hour period, after which the system calls the running service's
Service.onTimeout(int, int)
method (introduced in Android
15). At this time, the service has a few seconds to call
Service.stopSelf()
. When Service.onTimeout()
is called, the
service is no longer considered a foreground service. If the service does not
call Service.stopSelf()
, the system throws an internal exception. The
exception is logged in Logcat with the following message:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
To avoid problems with this behavior change, you can do one or more of the following:
- Have your service implement the new
Service.onTimeout(int, int)
method. When your app receives the callback, make sure to callstopSelf()
within a few seconds. (If you don't stop the app right away, the system generates a failure.) - Make sure your app's
dataSync
services don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer). - Only start
dataSync
foreground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background. - Instead of using a
dataSync
foreground service, use an alternative API.
If your app's dataSync
foreground services have run for 6 hours in the last
24, you cannot start another dataSync
foreground service unless the user
has brought your app to the foreground (which resets the timer). If you try to
start another dataSync
foreground service, the system throws
ForegroundServiceStartNotAllowedException
with an error message like "Time limit already exhausted for foreground service
type dataSync".
Testing
To test your app's behavior, you can enable data sync timeouts even if your app
is not targeting Android 15 (as long as the app is running on an Android 15
device). To enable timeouts, run the following adb
command:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
You can also adjust the timeout period, to make it easier to test how your
app behaves when the limit is reached. To set a new timeout period, run the
following adb
command:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
新的媒体处理前台服务类型
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
对启动前台服务的 BOOT_COMPLETED
广播接收器的限制
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
在应用拥有 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.
Apps that target Android 15 (API level 35) and higher can no longer change the
global state or policy of Do Not Disturb (DND) on a device (either by modifying
user settings, or turning off DND mode). Instead, apps must contribute an
AutomaticZenRule
, which the system combines into a global policy with the
existing most-restrictive-policy-wins scheme. Calls to existing APIs that
previously affected global state (setInterruptionFilter
,
setNotificationPolicy
) result in the creation or update of an implicit
AutomaticZenRule
, which is toggled on and off depending on the call-cycle of
those API calls.
Note that this change only affects observable behavior if the app is calling
setInterruptionFilter(INTERRUPTION_FILTER_ALL)
and expects that call to
deactivate an AutomaticZenRule
that was previously activated by their owners.
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 可保护用户免受恶意应用的侵害,并让用户更好地控制 来防止恶意后台应用 将其他应用置于前台、提升其权限以及滥用 用户互动自以下时间以来,后台活动启动一直受到限制 Android 10(API 级别 29)。
禁止与堆栈中的顶部 UID 不匹配的应用启动 activity
恶意应用可以在同一任务中启动另一个应用的 activity,然后
叠加在上面,营造出像该应用一样的错觉。这个“任务”
劫持"攻击绕过了当前的后台启动限制,
会发生在同一个可见任务中。为了降低这种风险,Android 15 新增了
用于阻止与堆栈中的顶层 UID 不匹配的应用启动的标志
活动。如需选择启用应用的所有活动,请更新
allowCrossUidActivitySwitchFromBelow
属性:AndroidManifest.xml
<application android:allowCrossUidActivitySwitchFromBelow="false" >
如果满足以下所有条件,则启用新的安全措施:
- 执行启动的应用以 Android 15 为目标平台。
- 任务堆栈顶部的应用以 Android 15 为目标平台。
- 所有可见活动都已选择启用新保护措施
如果启用了安全措施,应用可能会返回主屏幕,而不是返回 最后一个可见应用(如果他们自行完成任务)。
其他变更
除了限制 UID 匹配之外,这些其他变更也 包括:
- 更改
PendingIntent
创作者,以阻止后台活动启动,具体方法是: 默认。这有助于防止应用意外创建 可能被恶意操作者滥用的PendingIntent
。 - 请勿将应用调到前台,除非
PendingIntent
发送者 允许它。此变更旨在防止恶意应用滥用 在后台启动 activity 的功能。默认情况下,应用 允许将任务堆栈转到前台,除非创建者允许 后台活动启动权限或发送者有后台活动 启动权限 - 控制任务堆栈的顶层 activity 完成其任务的方式。如果 顶层 activity 完成一项任务后,Android 会返回到之前执行的 上次活动时间。此外,如果非顶层 activity 完成其任务,Android 将 返回主屏幕;因此不会阻碍这个非顶层的 活动。
- 防止将其他应用中的任意 activity 启动到您自己的 activity 任务。这项变更旨在防止恶意应用 看起来像是来自其他应用的活动
- 禁止将不可见窗口视为后台活动 发布。这有助于防止恶意应用滥用后台 activity 来向用户显示不需要或恶意的内容。
Intents más seguros
Android 15 引入了新的可选安全措施,以提高 intent 的安全性和稳健性。这些变更旨在防止潜在的漏洞以及恶意应用可能利用的 intent 滥用行为。Android 15 对 intent 的安全性进行了两项主要改进:
- 与目标 intent 过滤器匹配:定位到特定组件的 intent 必须与目标的 intent 过滤器规范完全匹配。如果您发送 intent 来启动其他应用的 activity,目标 intent 组件需要与接收 activity 声明的 intent 过滤器保持一致。
- intent 必须具有操作:没有操作的 intent 将不再与任何 intent 过滤器匹配。这意味着,用于启动 activity 或服务的 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 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 中与窗口内边距相关的两项变更:默认强制执行边到边,此外还有配置变更,例如系统栏的默认配置。
Edge-to-edge enforcement
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 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
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 se establece en 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 orientarse a Android 15 (nivel de API 35), y antes y después de aplicar inserciones.
Qué verificar si tu app ya es de borde a borde
Si tu app ya es de borde a borde y aplica inserciones, no se verá afectada, excepto en las siguientes situaciones. Sin embargo, incluso si crees que no se verá afectada, 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 relleno con este objeto de escucha y también agregaclipToPadding="false"
.
Qué verificar si tu app debe ofrecer protección en segundo plano personalizada
Si tu app debe ofrecer protección en segundo plano personalizada a la navegación de 3 botones o a la barra de estado, debe 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 alfa del 80%)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
Stable configuration
如果您的应用以 Android 15(API 级别 35)或更高版本为目标平台,Configuration
不再排除系统栏。如果您使用 Configuration
类中的屏幕尺寸进行布局计算,则应根据需要将其替换为更好的替代方案,例如适当的 ViewGroup
、WindowInsets
或 WindowMetricsCalculator
。
Configuration
从 API 1 开始提供。它通常从 Activity.onConfigurationChanged
中获取。它提供窗口密度、屏幕方向和尺寸等信息。从 Configuration
返回的窗口大小的一个重要特征是,它之前会排除系统栏。
配置大小通常用于资源选择(例如 /res/layout-h500dp
),这仍然是一个有效的用例。不过,我们一直不建议将其用于布局计算。如果您正在这样做,请立即停止。您应根据自己的用例,将 Configuration
的使用替换为更合适的用法。
如果您使用它来计算布局,请使用适当的 ViewGroup
,例如 CoordinatorLayout
或 ConstraintLayout
。如果您使用它来确定系统侧边栏的高度,请使用 WindowInsets
。如果您想知道应用窗口的当前大小,请使用 computeCurrentWindowMetrics
。
以下列表介绍了受此变更影响的字段:
Configuration.screenWidthDp
和screenHeightDp
尺寸不再排除系统栏。Configuration.smallestScreenWidthDp
会间接受到对screenWidthDp
和screenHeightDp
的更改的影响。- 在接近方形的设备上,
Configuration.orientation
会间接受到对screenWidthDp
和screenHeightDp
所做的更改的影响。 Display.getSize(Point)
会间接受到Configuration
中的更改影响。从 API 级别 30 开始,此方法已被弃用。- 从 API 级别 33 开始,
Display.getMetrics()
就已经这样运作了。
El atributo elegantTextHeight tiene el valor predeterminado de verdadero.
For apps targeting Android 15 (API level 35), the
elegantTextHeight
TextView
attribute
becomes true
by default, replacing the compact font used by default with some
scripts that have large vertical metrics with one that is much more readable.
The compact font was introduced to prevent breaking layouts; Android 13 (API
level 33) prevents many of these breakages by allowing the text layout to
stretch the vertical height utilizing the fallbackLineSpacing
attribute.
In Android 15, the compact font still remains in the system, so your app can set
elegantTextHeight
to false
to get the same behavior as before, but it is
unlikely to be supported in upcoming releases. So, if your app supports the
following scripts: Arabic, Lao, Myanmar, Tamil, Gujarati, Kannada, Malayalam,
Odia, Telugu or Thai, test your app by setting elegantTextHeight
to 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 que se adapta a la configuración regional para EditText
在较低版本的 Android 中,文本布局会拉伸文本的高度,以满足与当前语言区域匹配的字体的行高。例如,如果内容是日语,由于日语字体的行高略高于拉丁字体,因此文本的高度会略高。不过,尽管行高存在这些差异,但无论使用的是哪种语言区域,EditText
元素的大小都是统一的,如下图所示:
对于以 Android 15(API 级别 35)为目标平台的应用,现在为 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
以 Android 15(API 级别 35)为目标平台的应用必须是顶部应用或正在运行前台服务,才能请求音频焦点。如果应用在未满足上述任一要求的情况下尝试请求焦点,调用将返回 AUDIOFOCUS_REQUEST_FAILED
。
如需详细了解音频焦点,请参阅管理音频焦点。
Actualización de restricciones que no pertenecen al SDK
Android 15 包含更新后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保有可用的公开替代方案。
如果您的应用并非以 Android 15 为目标平台,其中一些变更可能不会立即对您产生影响。不过,虽然您的应用可以访问一些非 SDK 接口(具体取决于应用的目标 API 级别),但如果您使用任何非 SDK 方法或字段,应用无法运行的风险始终会很高。
如果您不确定自己的应用是否使用了非 SDK 接口,则可以测试该应用,进行确认。如果您的应用依赖于非 SDK 接口,您应该开始计划迁移到 SDK 替代方案。不过,我们知道某些应用具有使用非 SDK 接口的有效用例。如果您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,则应请求新的公共 API。
如需详细了解此 Android 版本中的变更,请参阅 Android 15 中有关限制非 SDK 接口的更新。如需全面了解有关非 SDK 接口的详细信息,请参阅对非 SDK 接口的限制。