Al igual que las versiones anteriores, Android 17 incluye cambios de comportamiento que podrían afectar tu app. Los siguientes cambios se aplican exclusivamente a las apps que tienen como objetivo Android 17 o versiones posteriores. Si tu app está orientada a Android 17 o versiones posteriores, debes modificarla para que admita estos comportamientos, 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 17, independientemente de targetSdkVersion de la app.
Experiencia del usuario y la IU del sistema
Android 17 incluye los siguientes cambios que tienen como objetivo crear una experiencia del usuario más coherente e intuitiva.
Widget de límite de memoria
A partir de Android 17, el sistema aplica un límite de memoria estricto en las actualizaciones de RemoteViews para las apps que se orientan a Android 17 (nivel de API 37) o versiones posteriores. Cuando una app pasa un objeto RemoteViews a AppWidgetManager.updateAppWidget, system_server calcula el espacio en memoria total de todos los datos de imagen en cada bucket de orientación y tamaño de la carga útil. Si la memoria total supera
el límite del sistema (mMaxWidgetBitmapMemory), el sistema rechaza la actualización y
arroja un IllegalArgumentException:
java.lang.IllegalArgumentException: RemoteViews for widget update exceeds maximum bitmap memory usage (used: XXXXX, max: YYYYY)
En el caso de las apps que se orientan al nivel de API 36 o versiones anteriores, el sistema registra esta infracción de memoria como una advertencia (Slog.w) sin arrojar una excepción.
Habilidades de Android
Ver en GitHubAdministra las actualizaciones de AppWidget y la memoria de mapas de bits
android skills add glance-appwidget-updates-and-memoryCómo calcula el sistema el límite de memoria
El sistema establece el presupuesto de memoria del mapa de bits del widget en 6 * width * height bytes (1.5 * 4 * width * height, equivalente a 1.5 veces el tamaño de un búfer ARGB_8888 de pantalla completa) para la configuración de pantalla activa. En el nivel de API 37 y versiones posteriores, este cálculo incluye lo siguiente:
- Objetos
Bitmapen memoria yIconrespaldados por mapas de bits (Icon.TYPE_BITMAPyIcon.TYPE_ADAPTIVE_BITMAP) almacenados enRemoteViews.mBitmapCache(como llamadas asetImageViewBitmap,Icon.createWithBitmap,Icon.createWithAdaptiveBitmapo Jetpack GlanceImageProvider(bitmap)). Cada instancia única deBitmapoIconrespaldada por mapas de bits enmBitmapCachese cuenta una vez por jerarquía deRemoteViews. - Las imágenes respaldadas por URI (
Icon.createWithContentUri,setImageViewUrioImageProvider(uri)de Glance) no se tienen en cuenta para el límite de bytes de IPC deRemoteViewsensystem_server, pero el proceso del host del widget decodifica el archivocontent://al que se hace referencia en resolución completa en su propio montón. Siempre escribe una imagen con reducción de muestreo encontext.cacheDirantes de exponerla a través de un URI deFileProvider.
Pasos de mitigación
Para mantener las actualizaciones de tus widgets dentro del límite de memoria en teléfonos, tablets y dispositivos plegables, haz lo siguiente:
Calcula tu presupuesto de memoria de tiempo de ejecución desde
WindowMetrics: En el nivel de API 30 y versiones posteriores, lee los límites de la ventana activa desdeWindowManager.currentWindowMetrics.boundsen lugar deresources.displayMetrics. En dispositivos con varias resoluciones y plegables,displayMetricspuede informar dimensiones de pantalla inactivas. Calcula el presupuesto total de imágenes del widget en6L * bounds.width() * bounds.height(), como se muestra en el siguiente ejemplo:private const val FALLBACK_MAX_BYTES = 15_000_000L fun calculateWidgetMemoryCapBytes(context: Context): Long { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val wm = context.getSystemService(WindowManager::class.java) ?: return FALLBACK_MAX_BYTES val bounds = wm.currentWindowMetrics.bounds return 6L * bounds.width().toLong() * bounds.height().toLong() } val dm = context.resources.displayMetrics return 6L * dm.widthPixels.toLong() * dm.heightPixels.toLong() }Reduce el muestreo de las imágenes a las dimensiones visibles del widget y usa
RGB_565: Decodifica mapas de bits con valoresBitmapFactory.Options.inSampleSizede potencia de dos con un tamaño que se ajuste a las dimensiones máximas de visualización del widget (maxWidthDppormaxHeightDp) y usaBitmap.Config.RGB_565(2bytes por píxel) en lugar deARGB_8888(4bytes por píxel) para fotos y miniaturas opacas.Eleva la decodificación de mapas de bits fuera de
provideContenten Jetpack Glance: Cuando usasSizeMode.ResponsiveoSizeMode.Exact, Glance invoca tu lambdaprovideContentuna vez por bucket de tamaño. Decodifica cadaBitmapcompartido una vez dentro deprovideGlanceantes de llamar aprovideContentpara que todos los buckets de tamaño hagan referencia a la misma instancia deBitmapenRemoteViews.mBitmapCache.Usa llamadas completas de
updateAppWidgetcuando reemplaces imágenes: En las implementaciones clásicas deAppWidgetProvider, evita llamar aAppWidgetManager.partiallyUpdateAppWidgetpara intercambiar vistas deBitmapoIcon. Las actualizaciones parciales combinan acciones nuevas en el árbolRemoteViewsexistente ensystem_serversin expulsar las acciones de imagen almacenadas en caché anteriormente. En su lugar, compila un diseño deRemoteViewscompleto y llama aupdateAppWidget.Proporciona un diseño de resguardo de errores: En Jetpack Glance, anula
onCompositionErrorpara renderizar un resguardo deRemoteViewssin mapa de bits si falla una actualización.
Puedes inspeccionar el uso de memoria de mapa de bits serializada actual de tu widget en un dispositivo conectado ejecutando lo siguiente:
adb shell dumpsys appwidget
Funcionalidad principal
Android 17 incluye los siguientes cambios que modifican o expanden varias funciones principales del sistema Android.
Nueva implementación sin bloqueos de MessageQueue
A partir de Android 17, las apps orientadas a Android 17 (nivel de API 37) o versiones posteriores reciben una nueva implementación sin bloqueos de android.os.MessageQueue. La nueva implementación mejora el rendimiento y reduce los fotogramas perdidos, pero puede interrumpir los clientes que reflejan los campos y métodos privados de MessageQueue.
Para obtener más información, incluidas las estrategias de mitigación, consulta la guía de cambio de comportamiento de MessageQueue.
Los campos finales estáticos ahora no se pueden modificar
Las apps que se ejecutan en Android 17 o versiones posteriores y que se orientan a Android 17 (nivel de API 37) o versiones posteriores no pueden cambiar los campos static final. Si una app intenta cambiar un campo static final con la reflexión, se producirá una IllegalAccessException. Si intentas modificar uno de estos campos a través de las APIs de JNI (como SetStaticLongField()), la app fallará.
Accesibilidad
Android 17 incluye los siguientes cambios para mejorar la accesibilidad.
Compatibilidad de accesibilidad con la escritura compleja con teclado físico del IME
Esta función presenta las nuevas APIs de AccessibilityEvent y TextAttribute para mejorar las descripciones por voz del lector de pantalla para la entrada de idiomas CJKV. Las apps de IME de CJKV ahora pueden indicar si se seleccionó un candidato de conversión de texto durante la composición de texto. Las apps con campos de edición pueden especificar tipos de cambios de texto cuando envían eventos de accesibilidad de texto modificado.
Por ejemplo, las apps pueden especificar que se produjo un cambio de texto durante la composición de texto o que un cambio de texto se produjo a partir de una confirmación.
Esto permite que los servicios de accesibilidad, como los lectores de pantalla, proporcionen comentarios más precisos según la naturaleza de la modificación del texto.
Adopción de apps
Apps de IME: Cuando se configura el texto de redacción en los campos de edición, los IME pueden usar
TextAttribute.Builder.setTextSuggestionSelected()para indicar si se seleccionó un candidato de conversión específico.Apps con campos de edición: Las apps que mantienen un
InputConnectionpersonalizado pueden recuperar datos de selección de candidatos llamando aTextAttribute.isTextSuggestionSelected(). Estas apps deben llamar aAccessibilityEvent.setTextChangeTypes()cuando se envían eventosTYPE_VIEW_TEXT_CHANGED. Las apps orientadas a Android 17 (nivel de API 37) que usen elTextViewestándar tendrán esta función habilitada de forma predeterminada. (Es decir,TextViewse encargará de recuperar datos del IME y establecer tipos de cambios de texto cuando se envíen eventos a los servicios de accesibilidad).Servicios de accesibilidad: Los servicios de accesibilidad que procesan eventos
TYPE_VIEW_TEXT_CHANGEDpueden llamar aAccessibilityEvent.getTextChangeTypes()para identificar la naturaleza de la modificación y ajustar sus estrategias de comentarios según corresponda.
Privacidad
Android 17 incluye los siguientes cambios para mejorar la privacidad del usuario.
ECH (Encrypted Client Hello) habilitado
Android 17 引入了对加密客户端问候 (ECH) 的平台支持,这是一种 TLS 扩展,可通过在 TLS 握手中加密服务器名称指示 (SNI) 来增强用户隐私。这种加密有助于防止网络观察者轻易识别出应用连接到的特定网域。
对于以 Android 17(API 级别 37)或更高版本为目标平台的应用,ECH 用于 TLS 连接。只有在应用使用的网络库(例如 HttpEngine、WebView 或 OkHttp)集成了 ECH 支持,并且远程服务器也支持 ECH 协议时,ECH 才会处于活跃状态。如果无法协商 ECH,客户端会发送包含随机内容的 ECH 扩展程序(一种称为 ECH GREASE 的机制)。如需详细了解 ECH GREASE 的运作方式,请参阅 RFC 9849。
为了允许应用自定义此行为,Android 17 向网络安全配置文件添加了新的 <domainEncryption> 元素。开发者可以在 <base-config> 或 <domain-config> 标记中使用 <domainEncryption>,以全局或按网域选择 ECH 模式(例如 "enabled" 或 "disabled")。
如需了解详情,请参阅加密客户端问候文档。
Se requiere el permiso de red local para las apps que se orientan a Android 17
Android 17 引入了 ACCESS_LOCAL_NETWORK 运行时权限,以保护用户免遭未经授权的本地网络访问。由于此权限属于现有的 NEARBY_DEVICES 权限组,因此系统不会再次提示已授予其他 NEARBY_DEVICES 权限的用户。这项新要求可防止恶意应用利用不受限制的本地网络访问权限进行隐蔽的用户跟踪和指纹识别。通过声明和请求此权限,您的应用可以发现并连接到局域网 (LAN) 上的设备,例如智能家居设备或投屏接收器。
以 Android 17(API 级别 37)或更高版本为目标平台的应用现在可以通过两种方式与局域网设备保持通信:采用系统介导、可保护隐私的设备选择器来跳过权限提示,或在运行时明确请求这项新权限,以保持本地网络通信。
如需了解详情,请参阅本地网络权限文档。
Ocultar contraseñas de dispositivos físicos
Si una app se orienta a Android 17 (nivel de API 37) o una versión posterior, y el usuario utiliza un dispositivo de entrada físico (por ejemplo, un teclado externo), el sistema operativo Android aplica el nuevo parámetro de configuración show_passwords_physical a todos los caracteres del campo de contraseña. De forma predeterminada, ese parámetro de configuración oculta todos los caracteres de la contraseña.
El sistema Android muestra el último carácter de la contraseña que se escribió para ayudar al usuario a ver si la escribió de forma incorrecta. Sin embargo, esto es mucho menos necesario con teclados externos más grandes. Además, los dispositivos con teclados externos suelen tener pantallas más grandes, lo que aumenta el peligro de que alguien vea la contraseña que se escribe.
Si el usuario usa la pantalla táctil del dispositivo, el sistema aplica el nuevo parámetro de configuración show_passwords_touch.
Protección de OTP para mensajes SMS estándar
Beginning with Android 17, Android is extending its SMS OTP protection
to apply to standard SMS messages (SMS messages containing an OTP that do not
use the WebOTP or SMS Retriever formats). For most apps targeting
Android 17 (API level 37) or higher, these SMS messages do not become
available until three hours after receipt. This delay is intended to help
prevent OTP hijacking. During this three hour delay, the
SMS_RECEIVED_ACTION broadcast is withheld and
SMS provider database queries are filtered. The SMS message is
available to these apps after the delay.
Certain apps such as the default SMS assistant app, connected device companion apps, etc., are exempted from this delay. All apps that rely on reading SMS messages for OTP extraction should transition to using SMS Retriever or SMS User Consent APIs to ensure continued functionality.
Seguridad
Android 17 incluye las siguientes mejoras en la seguridad de los dispositivos y las apps.
Seguridad de la actividad
在 Android 17 中,平台继续向“默认安全”架构转变,引入了一系列旨在缓解高严重性漏洞利用(例如钓鱼式攻击、互动劫持和混淆代理攻击)的增强功能。此次更新要求开发者明确选择启用新的安全标准,以保持应用兼容性并保护用户。
对开发者产生的主要影响包括:
- BAL 强化和改进的选择启用:我们正在优化后台 activity 启动 (BAL) 限制,将保护范围扩展到
IntentSender。开发者必须停止使用旧版MODE_BACKGROUND_ACTIVITY_START_ALLOWED常量。相反,您应该采用精细控制,例如MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE,它会将 activity 启动限制在调用应用可见的场景中,从而显著减少攻击面。 - 采用工具:开发者应利用严格模式和更新后的 lint 检查来识别旧版模式,并确保为未来的目标 SDK 要求做好准备。
Habilitar la CT de forma predeterminada
Si una app se orienta a Android 17 (nivel de API 37) o versiones posteriores, el certificado de transparencia (CT) está habilitado de forma predeterminada. (En Android 16, la CT está disponible, pero las apps debían habilitarla).
DCL nativo más seguro: C
If your app targets Android 17 (API level 37) or higher, the Safer Dynamic Code Loading (DCL) protection introduced in Android 14 for DEX and JAR files now extends to native libraries.
All native files loaded using System.load() must be marked as read-only.
Otherwise, the system throws UnsatisfiedLinkError.
We recommend that apps avoid dynamically loading code whenever possible, as doing so greatly increases the risk that an app can be compromised by code injection or code tampering.
Restringe los campos de PII en la vista de datos de CP2
En el caso de las apps que se orientan a Android 17 (nivel de API 37) y versiones posteriores, el proveedor de contactos 2 (CP2) restringe ciertas columnas que contienen información de identificación personal (PII) de la vista de datos. Cuando se habilita este cambio, estas columnas se quitan de la vista de datos para mejorar la privacidad del usuario. Las columnas restringidas incluyen las siguientes:
Las apps que usan estas columnas de ContactsContract.Data
pueden extraerlas de ContactsContract.RawContacts
en su lugar, uniéndolas con RAW_CONTACT_ID.
Aplica verificaciones estrictas de SQL en CP2
En el caso de las apps que se orientan a Android 17 (nivel de API 37) y versiones posteriores, el Proveedor de contactos 2 (CP2) aplica una validación estricta de consultas en SQL cuando se accede a la tabla ContactsContract.Data sin el permiso READ_CONTACTS.
Con este cambio, si una app no tiene el permiso READ_CONTACTS, se configuran las opciones StrictColumns y StrictGrammar cuando se consulta la tabla ContactsContract.Data. Si una consulta
usa un patrón que no es compatible con estos, se
rechazará y se generará una excepción.
Inteligencia
Android 17 incluye los siguientes cambios en la inteligencia del sistema.
Baja de setContentCaptureEnabled
La captura de contenido está habilitada de forma predeterminada en ciertos dispositivos para permitir que las funciones de IA integradas en el dispositivo analicen el contenido de la pantalla y ofrezcan experiencias inteligentes.
A partir de Android 17, el método de la API de ContentCaptureManager.setContentCaptureEnabled(boolean) dejará de estar disponible. En el caso de las apps que se orientan a Android 17 (nivel de API 37) o versiones posteriores, llamar a setContentCaptureEnabled(false) ya no inhabilita la captura de contenido.
Si tu app necesita seguir inhabilitando la captura de contenido o restringir la captura del contenido de la pantalla por parte del sistema, debes realizar la transición para usar el parámetro de diseño de ventana FLAG_SECURE.
Para inhabilitar la captura de contenido, establece la marca FLAG_SECURE en tu ventana, como se muestra en el siguiente ejemplo:
Kotlin
window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
Java
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
Para obtener más detalles, consulta la documentación de referencia de WindowManager.LayoutParams.FLAG_SECURE.
Medios
Android 17 incluye los siguientes cambios en el comportamiento de los medios.
Refuerzo del audio en segundo plano
A partir de Android 17, el framework de audio aplica restricciones a las interacciones de audio en segundo plano, como la reproducción de audio, las solicitudes de foco de audio y las APIs de cambio de volumen, para garantizar que el usuario inicie estos cambios de forma intencional.
Algunas restricciones de audio se aplican a todas las apps. Sin embargo, las restricciones son más estrictas si una app se orienta a Android 17 (nivel de API 37). Si una de estas apps interactúa con el audio mientras está en segundo plano, debe tener un servicio en primer plano en ejecución. Además, la app debe cumplir con uno o ambos de estos requisitos:
- El servicio en primer plano debe tener capacidades de uso en curso (WIU).
- La app debe tener el permiso de alarma exacta y debe interactuar con las transmisiones de audio
USAGE_ALARM.
Para obtener más información, incluidas las estrategias de mitigación, consulta Endurecimiento del audio en segundo plano.
Factores de forma de los dispositivos
Android 17 incluye los siguientes cambios para mejorar la experiencia del usuario en una variedad de tamaños y factores de forma de dispositivos.
Cambios en la API de la plataforma para ignorar las restricciones de orientación, cambio de tamaño y relación de aspecto en pantallas grandes (sw>=600 dp)
We introduced Platform API changes in Android 16 to ignore orientation, resizability, and aspect ratio restrictions on large screens (sw >= 600dp) for apps targeting API level 36 or higher. Developers have the option to opt out of these changes with SDK 36, but this opt-out will no longer be available for apps that target Android 17 (API level 37) or higher.
For more information, see Restrictions on orientation and resizability are ignored.
Conectividad
Android 17 presenta el siguiente cambio para mejorar la coherencia y alinearse con el comportamiento estándar de Java InputStream para los sockets RFCOMM de Bluetooth.
Comportamiento coherente de read() de BluetoothSocket para RFCOMM
En el caso de las apps orientadas a Android 17 (nivel de API 37), el método read() de InputStream obtenido de un BluetoothSocket basado en RFCOMM ahora devuelve -1 cuando se cierra el socket o se interrumpe la conexión.
Este cambio hace que el comportamiento del socket de RFCOMM sea coherente con los sockets de LE CoC y se alinee con la documentación estándar de InputStream.read(), que indica que se devuelve -1 cuando se alcanza el final de la transmisión.
Es posible que este cambio afecte a las apps que dependen únicamente de detectar una IOException para salir de un bucle de lectura, por lo que deben actualizar los bucles de lectura de BluetoothSocket para verificar de forma explícita si se devuelve un valor de -1. Esto garantiza que el bucle finalice correctamente cuando el dispositivo remoto se desconecte o se cierre el socket. Para ver un ejemplo de la implementación recomendada, consulta el fragmento de código en la guía Transferencia de datos por Bluetooth.