Además de nuevas funciones y capacidades, Android 8.0 (nivel de API 26) incluye una variedad de cambios en el comportamiento del sistema y de la API. En este documento, se destacan algunos de los cambios clave que debes comprender y justificar en tus apps.
La mayoría de estos cambios afectan a todas las apps, independientemente de la versión de Android a la que se orienten. Sin embargo, varios cambios solo afectan a las apps orientadas a Android 8.0. Para brindar mayor claridad, esta página se divide en dos secciones: Cambios para todas las apps y Cambios en las apps orientadas a Android 8.0.
Cambios para todas las apps
Estos cambios de comportamiento se aplican a
Background execution limits
Uno de los cambios que Android 8.0 (nivel de API 26) presenta para mejorar la duración de batería consiste en que, cuando tu app ingresa en el estado almacenado en caché, sin componentes activos, el sistema libera las funciones wakelock de ella.
Además, para mejorar el rendimiento del dispositivo, el sistema limita ciertos comportamientos de las apps que no se ejecutan en primer plano. Más precisamente:
- Ahora, las apps que se ejecutan en segundo plano tienen límites sobre el nivel de libertad de acceso a los servicios en segundo plano que tienen.
- Las apps no pueden usar sus manifiestos para registrarse en la mayoría de las transmisiones implícitas (esto es, transmisiones que no están orientadas específicamente a la app).
De forma predeterminada, estas restricciones se aplican únicamente a apps orientadas a Android O. Sin embargo, los usuarios pueden habilitar estas restricciones para cualquier app desde la pantalla Configuración, incluso si la app no se orienta a O.
Android 8.0 (nivel de API 26) también incluye los siguientes cambios en métodos específicos:
- El método
startService()
ahora arroja unaIllegalStateException
si una app orientada a Android 8.0 intenta usar ese método en una situación en la que no está permitido crear servicios en segundo plano. - El nuevo método
Context.startForegroundService()
inicia un servicio en primer plano. El sistema permite que las apps llamen aContext.startForegroundService()
incluso mientras la app está en segundo plano. Sin embargo, la app debe llamar al métodostartForeground()
de ese servicio en un plazo de cinco segundos después de que se crea el servicio.
Para obtener más información, consulta Límites de ejecución en segundo plano.
Limites de ubicación en segundo plano de Android
Para preservar la batería, la experiencia del usuario y el funcionamiento correcto del sistema, las apps en segundo plano reciben actualizaciones de ubicación con menor frecuencia cuando se usan en un dispositivo con Android 8.0. Este cambio de comportamiento afecta a todas las apps que reciben actualizaciones de ubicación, incluidos los Servicios de Google Play.
Estos cambios afectan las siguientes API:
- Proveedor de ubicación combinada (FLP)
- Geovallado
- GNSS Measurements
- Location Manager
- Administrador de Wi-Fi
Para asegurarte de que tu app se ejecute de la forma prevista, completa los siguientes pasos:
- Revisa la lógica de tu app y asegúrate de usar las APIs de ubicación más recientes.
- Verifica, mediante una prueba, que tu app exhiba el comportamiento que esperas para cada caso de uso.
- Considera usar el proveedor de ubicación combinada (FLP) o el geovallado para manejar los casos de uso que dependen de la ubicación actual del usuario.
Para obtener más información sobre estos cambios, consulta Límites de ubicación en segundo plano.
Accesos directos a aplicaciones
Android 8.0 (nivel de API 26) incluye los siguientes cambios en las combinaciones de teclas para apps:
- La transmisión
com.android.launcher.action.INSTALL_SHORTCUT
ya no tiene ningún efecto en tu app, porque ahora es una transmisión implícita privada. En su lugar, debes crear una combinación de teclas para una app usando el métodorequestPinShortcut()
de la claseShortcutManager
. - El intent
ACTION_CREATE_SHORTCUT
ahora puede crear combinaciones de teclas para apps que podrás administrar usando la claseShortcutManager
. Esta intent también puede crear combinaciones de teclas de lanzadores heredados que no interactúan conShortcutManager
. Anteriormente, este intent solo podía crear accesos directos de selectores heredados. - Los accesos directos creados con
requestPinShortcut()
y los accesos directos creados en una actividad que controla el intentACTION_CREATE_SHORTCUT
ahora son accesos directos a aplicaciones completos. Como resultado, ahora las apps pueden actualizarlas con los métodos deShortcutManager
. - Las combinaciones de teclas heredadas mantienen la funcionalidad de versiones anteriores de Android, pero debes convertirlas a combinaciones de teclas para apps manualmente en tu app.
Para obtener más información sobre los cambios en combinaciones de teclas de apps, consulta la guía de funciones Fijación de combinaciones de teclas y Widgets.
Configuración regional e internacionalización
Android 7.0 (API nivel 24) introdujo el concepto de poder especificar una configuración regional de categoría predeterminada, pero algunas API siguieron usando el método genérico Locale.getDefault()
, sin argumentos, cuando deberían haber usado la configuración regional predeterminada de la categoría DISPLAY
. En Android 8.0 (nivel de API 26), los siguientes métodos ahora usan Locale.getDefault(Category.DISPLAY)
en lugar de Locale.getDefault()
:
Locale.getDisplayScript(Locale)
también recurre a Locale.getDefault()
cuando el valor de displayScript especificado para el argumento Locale
no está disponible.
A continuación, se incluyen los cambios adicionales relacionados con la configuración regional y la internacionalización:
- Las llamadas a
Currency.getDisplayName(null)
arrojan unaNullPointerException
, que coincide con el comportamiento documentado. - El análisis nombres de zonas horarias ha cambiado. Anteriormente, los dispositivos Android usaban el valor del reloj del sistema tomado en el momento del inicio para almacenar en caché los nombres de zonas horarias usados para analizar la fecha y la hora. Como resultado, el análisis podría verse afectado negativamente si el reloj del sistema no funcionaba bien en el momento del inicio o en otros casos poco comunes.
Ahora, en casos comunes, la lógica de análisis usa ICU y el valor actual del reloj del sistema cuando analiza los nombres de las zonas horarias. Este cambio ofrece resultados más correctos, que pueden ser diferentes en versiones anteriores de Android, cuando tu app usa clases como
SimpleDateFormat
. - Android 8.0 (nivel de API 26) actualiza la versión de ICU a la versión 58.
Ventanas de alerta
Si una app usa el permiso SYSTEM_ALERT_WINDOW
y uno de los siguientes tipos de ventana para intentar mostrar ventanas de alerta sobre otras apps y ventanas del sistema:
...estas ventanas siempre aparecen debajo de las ventanas que usan el tipo de ventana TYPE_APPLICATION_OVERLAY
. Si una app está orientada a Android 8.0 (nivel de API 26), esta usa el tipo de ventana TYPE_APPLICATION_OVERLAY
para mostrar ventanas de alerta.
Para obtener más información, consulta la sección Tipos comunes de ventanas para ventanas de alerta en los cambios de comportamiento de apps orientadas a Android 8.0.
Entrada y navegación
Con la aparición de las apps para Android en ChromeOS y otros factores de forma grandes, como las tablets, podemos ver un resurgimiento del uso de la navegación por teclado dentro de las apps para Android. En Android 8.0 (nivel de API 26), volvimos a abordar el uso del teclado como dispositivo de entrada de navegación, lo cual da como resultado un modelo más confiable y predecible para una navegación basada en flechas y pestañas.
En particular, realizamos los siguientes cambios en el comportamiento del enfoque de elementos:
-
Si no has definido ningún color de estado de foco para un objeto
View
(su elemento de diseño en primer o segundo plano), el framework ahora configurará un color de resalte de foco predeterminado para elView
. Este resalte de foco es un elemento de diseño de efecto de ondas que se basa en el tema de la actividad.Si no deseas que un objeto
View
use este resalte predeterminado cuando recibe enfoque, establece el atributoandroid:defaultFocusHighlightEnabled
enfalse
en el archivo XML de diseño que contiene elView
, o pasafalse
asetDefaultFocusHighlightEnabled()
en la lógica de IU de tu app. - Para probar la forma en que la entrada del teclado afecta el enfoque de los elementos de la IU, puedes habilitar la opción del desarrollador Drawing > Show layout bounds. En Android 8.0, esta opción muestra un ícono “X” en el elemento que actualmente tiene foco.
Además, todos los elementos de la barra de herramientas en Android 8.0 son automáticamente clústeres de navegación por teclado, lo que facilita la navegación de los usuarios hacia adentro y afuera de cada barra de herramientas en general.
Para obtener más información sobre cómo mejorar la compatibilidad con la navegación con teclado dentro de tu app, lee la guía Compatibilidad con la navegación por teclado.
Autocompletado de formularios web
Ahora que el Autofill Framework de Android proporciona asistencia integrada para la funcionalidad de autocompletado, los siguientes métodos relacionados con los objetos WebView
cambiaron para las apps instaladas en dispositivos con Android 8.0 (nivel de API 26):
WebSettings
-
- El método
getSaveFormData()
ahora muestrafalse
. Anteriormente, este método mostrabatrue
como alternativa. - Llamar a
setSaveFormData()
ya no tiene ningún efecto.
- El método
WebViewDatabase
-
- Llamar a
clearFormData()
ya no tiene ningún efecto. - El método
hasFormData()
ahora muestrafalse
. Anteriormente, este método mostrabatrue
cuando el formulario contenía datos.
- Llamar a
Accesibilidad
Android 8.0 (nivel de API 26) incluye los siguientes cambios en la accesibilidad:
-
El framework de accesibilidad ahora convierte todos los gestos de doble toque en acciones
ACTION_CLICK
. Este cambio permite que TalkBack se comporte más como otros servicios de accesibilidad.Si los objetos
View
de tu app usan un control táctil personalizado, debes verificar que sigan funcionando con TalkBack. Es posible que solo necesites registrar el controlador de clics que usan tus objetosView
. Si TalkBack aún no reconoce los gestos realizados en estos objetosView
, anulaperformAccessibilityAction()
. - Los servicios de accesibilidad ahora reconocen todas las instancias de
ClickableSpan
dentro de los objetosTextView
de tu app.
Para obtener más información sobre cómo hacer que tu app sea más accesible, consulta Accesibilidad.
Conectividad de red y HTTP(S)
Android 8.0 (nivel de API 26) incluye los siguientes cambios de comportamiento respecto de la conectividad de redes y HTTP(S):
- Las solicitudes de OPTIONS sin cuerpo tienen un encabezado
Content-Length: 0
. Antes no tenían un encabezadoContent-Length
. - HttpURLConnection normaliza URLs que contienen rutas de acceso vacías añadiendo una barra diagonal después del nombre de host o autoridad. Por ejemplo, convierte
http://example.com
enhttp://example.com/
. - Un selector de proxy personalizado a través de ProxySelector.setDefault() solo tiene como objetivo la dirección (esquema, host y puerto) de una URL solicitada. Como resultado, es posible que la selección se proxy se base únicamente en estos valores. Una URL que se pasa a un selector de proxy personalizado no incluye la ruta de acceso, los parámetros de consulta ni los fragmentos de la URL solicitada.
- Los URI no pueden contener etiquetas.
Anteriormente, la plataforma era compatible con el método alternativo de aceptar etiquetas vacías en nombres de host, lo cual representa un uso no permitido de los URI. Esta solución alternativa era para la compatibilidad con versiones anteriores de libcore. Los desarrolladores que usaban la API de manera incorrecta veían el siguiente mensaje de ADB: "URI example..com has empty labels in the hostname. El formato es incorrecto y no se aceptará en futuras versiones de Android". En Android 8.0, se quita esta solución alternativa; el sistema muestra un valor nulo para los URI con el formato incorrecto.
- La implementación de HttpsURLConnection en Android 8.0 no realiza resguardos de versiones no seguras del protocolo TLS/SSL.
- El control de tunelización de conexiones HTTP(S) presenta los siguientes cambios:
- Cuando se realiza la tunelización de conexiones HTTPS sobre la conexión, el sistema coloca correctamente el número de puerto (:443) en la línea de host cuando envía esta información a un servidor intermedio. Anteriormente, el número de puerto solo existía en la línea CONNECT.
- El sistema ya no envía encabezados de usuario-agente ni de autorización de proxy de una solicitud tunelizada al servidor proxy.
El sistema ya no envía un encabezado de autorización de proxy en una Http(s)URLConnection tunelizada al proxy cuando se configura el túnel. En su lugar, el sistema genera un encabezado de autorización de proxy y lo envía al proxy cuando este envía HTTP 407 en respuesta a la solicitud inicial.
De manera similar, el sistema ya no copia el encabezado del usuario-agente de la solicitud tunelizada a la solicitud de proxy que configura el túnel. En su lugar, la biblioteca genera un encabezado de usuario-agente para esa solicitud.
- El método
send(java.net.DatagramPacket)
genera una SocketException si el método connect() ejecutado anteriormente falla.- DatagramSocket.connect() establece una pendingSocketException si existe un error interno. Antes de Android 8.0, una llamada recv() posterior generaba una SocketException aunque una llamada send() se realizara con éxito. Para lograr uniformidad, ambas llamadas ahora producen una SocketException.
- InetAddress.isReachable() prueba el ICMP antes de volver al protocolo Echo TCP.
- El acceso a algunos hosts que bloquean el puerto 7 (TCP Echo), como google.com, ahora es posible si estos aceptan el protocolo Echo ICMP.
- En el caso de los hosts inaccesibles, este cambio significa que se invierte el doble de tiempo antes de que regrese la llamada.
Bluetooth
Android 8.0 (API nivel 26) realiza los siguientes cambios en la longitud de los datos que recupera el método ScanRecord.getBytes()
:
- El método
getBytes()
no hace suposiciones sobre la cantidad de bytes recibidos. Por lo tanto, las apps no deben depender de una cantidad mínima o máxima de bytes mostrados. En su lugar, deben evaluar la extensión de la matriz resultante. - Los dispositivos compatibles con Bluetooth 5 pueden mostrar una longitud de datos que excede el máximo anterior de ~60 bytes.
- Si un dispositivo remoto no proporciona una respuesta de análisis, también se pueden mostrar menos de 60 bytes.
Conectividad sin inconvenientes
Android 8.0 (nivel de API 26) realiza varias mejoras en la configuración Wi-Fi para facilitar la elección de la red de Wi-Fi que ofrece la mejor experiencia de usuario. Entre los cambios específicos se incluye lo siguiente:
- Mejoras en la estabilidad y la confiabilidad.
- Una IU de lectura más intuitiva.
- Un menú consolidado y único de preferencias de Wi-Fi.
- En dispositivos compatibles, la activación automática de la función Wi-Fi cuando se encuentre cerca una red de alta calidad guardada.
Seguridad
Android 8.0 incluye los siguientes cambios relacionados con la seguridad:
- La plataforma ya no es compatible con SSLv3.
- Cuando se establece una conexión HTTPS con un servidor que implementa de manera incorrecta la negociación de versión de protocolo TLS,
HttpsURLConnection
deja de probar la alternativa de volver a versiones de protocolo TLS anteriores y realizar nuevos intentos. - Android 8.0 (nivel de API 26) aplica un filtro de Secure Computing (SECCOMP) a todas las apps. La lista de todas las llamadas del sistema se restringe a aquellas que se exponen a través de bionic. Aunque se proporcionan varias llamadas de sistema para la compatibilidad con versiones anteriores, no recomendamos usarlas.
- Los objetos
WebView
de tu app ahora se ejecutan en el modo multiproceso. Para mayor seguridad, el contenido web se controla en un proceso separado y aislado del proceso que contiene la app. -
Ya no es posible suponer que los APK residen en directorios cuyos nombres terminan en -1 o -2. Las apps deben usar
sourceDir
para obtener el directorio y no depender directamente del formato de este. - Para obtener más información sobre las mejoras de seguridad relacionadas con el uso de bibliotecas nativas, consulta Bibliotecas nativas.
Además, Android 8.0 (nivel de API 26) presenta los siguientes cambios relacionados con la instalación de apps desconocidas desde fuentes desconocidas:
- Ahora, el valor de la configuración heredada
INSTALL_NON_MARKET_APPS
es siempre 1. Para determinar si una fuente desconocida puede instalar apps con el instalador de paquetes, debes usar el valor que se muestra decanRequestPackageInstalls()
. - Si intentas cambiar el valor de
INSTALL_NON_MARKET_APPS
consetSecureSetting()
, se genera unaUnsupportedOperationException
. Para evitar que los usuarios instalen apps desconocidas con fuentes desconocidas, debes aplicar la restricción de usuariosDISALLOW_INSTALL_UNKNOWN_SOURCES
. -
Los perfiles administrados creados en dispositivos que ejecutan Android 8.0 (nivel de API 26) tienen habilitada automáticamente la restricción del usuario
DISALLOW_INSTALL_UNKNOWN_SOURCES
. En el caso de los perfiles administrados existentes en dispositivos que se actualizan a Android 8.0, la restricción de usuariosDISALLOW_INSTALL_UNKNOWN_SOURCES
se habilita automáticamente, a menos que el propietario del perfil haya inhabilitado esta restricción de forma explícita (antes de la actualización) configurandoINSTALL_NON_MARKET_APPS
en 1.
Para obtener más detalles sobre la instalación de apps desconocidas, consulta la guía sobre Permisos de instalación de apps desconocidas.
Para obtener lineamientos adicionales sobre cómo hacer que tu app sea más segura, consulta Seguridad para desarrolladores de Android.
Privacidad
Android 8.0 (nivel de API 26) realiza los siguientes cambios relacionados con la privacidad en la plataforma.
- Ahora, la plataforma maneja los identificadores de manera diferente.
-
Para las apps que se instalaron antes de una actualización inalámbrica a una versión de Android 8.0 (nivel de API 26), el valor de
ANDROID_ID
sigue siendo el mismo, a menos que se desinstale y se reinstale después de la actualización inalámbrica. Para preservar los valores en desinstalaciones después de una actualización inalámbrica, los desarrolladores pueden asociar los valores anteriores y los nuevos con la copia de seguridad de par clave-valor. - En el caso de las apps instaladas en un dispositivo con Android 8.0, el valor de
ANDROID_ID
ahora se define por clave de firma de app y por usuario. El valor deANDROID_ID
es único para cada combinación de clave de firma de la app, usuario y dispositivo. Como resultado, las apps con diferentes claves de firma que se ejecutan en el mismo dispositivo dejan de detectar el mismo ID de Android (incluso para el mismo usuario). - El valor de
ANDROID_ID
no cambia al desinstalarse o instalarse un paquete, siempre y cuando la clave de firma sea la misma (y la app no se haya instalado antes de una actualización inalámbrica de una versión de Android 8.0). - El valor de
ANDROID_ID
no cambia incluso si una actualización del sistema cambia la clave de firma del paquete. - En los dispositivos que se envían con los Servicios de Google Play y el ID de publicidad, debes usar el
ID de publicidad. El ID de publicidad es un sistema estándar y simple para monetizar apps que es un ID único que el usuario puede restablecer para publicidad. Los Servicios de Google Play lo proporcionan.
Otros fabricantes de dispositivos deben seguir proporcionando
ANDROID_ID
.
-
Para las apps que se instalaron antes de una actualización inalámbrica a una versión de Android 8.0 (nivel de API 26), el valor de
- La consulta de la propiedad del sistema
net.hostname
da como resultado un valor nulo.
Registro de excepciones no capturadas
Si una app instala un Thread.UncaughtExceptionHandler
que no realiza una llamada a través del Thread.UncaughtExceptionHandler
predeterminado, el sistema no finaliza la app cuando se produce una excepción no detectada. A partir de Android 8.0 (nivel de API 26), el sistema registra el seguimiento de pila de la excepción en esta situación. En versiones anteriores de la plataforma, el sistema no registraba el seguimiento de pila de la excepción.
Recomendamos que las implementaciones de Thread.UncaughtExceptionHandler
personalizadas siempre realicen la llamada a través del controlador predeterminado. Las apps que siguen esta recomendación no se ven afectadas por el cambio en Android 8.0.
Cambio de firma de findViewById()
Todas las instancias del método findViewById()
ahora devuelven
<T extends View> T
en lugar de View
. Este cambio tiene las siguientes implicaciones:
- Esto puede provocar que el código existente ahora tenga un tipo de datos ambiguo que se muestra, por ejemplo, si hay
someMethod(View)
ysomeMethod(TextView)
que llevan el resultado de una llamada afindViewById()
. - Cuando se usa un idioma de origen Java 8, se requiere una conversión de tipos explícita a
View
cuando el tipo de datos que se muestra no tiene restricciones (por ejemplo,assertNotNull(findViewById(...)).someViewMethod())
). - En las anulaciones de métodos
findViewById()
no finales (por ejemplo,Activity.findViewById()
), será necesario actualizar el tipo de datos que se muestra.
Cambio en las estadísticas del uso de proveedores de contactos
En versiones anteriores de Android, el componente Proveedor de contactos permite que los desarrolladores obtengan datos de uso de cada contacto. Estos datos de uso exponen información para cada dirección de correo electrónico y cada número de teléfono asociado con un contacto, incluido el número de veces que el contacto ha sido contactado y la última vez que fue contactado. Las apps que solicitan el permiso READ_CONTACTS
pueden leer estos datos.
Las apps pueden leer estos datos si solicitan el permiso READ_CONTACTS
. En Android 8.0 (API nivel 26) y versiones posteriores, las consultas de datos de uso muestran aproximaciones en lugar de valores exactos. El sistema Android mantiene los valores exactos de forma interna, por lo que este cambio no afecta a la API de autocompletar.
Este cambio de comportamiento afecta los siguientes parámetros de consulta:
Manejo de recopilaciones
AbstractCollection.removeAll()
y AbstractCollection.retainAll()
ahora siempre arrojan una NullPointerException
. Anteriormente, no se arrojaba NullPointerException
cuando la colección estaba vacía. Este cambio hace que el comportamiento se adecue a la documentación.
Android para empresas
Android 8.0 (nivel de API 26) cambia el comportamiento de algunas APIs y funciones para apps empresariales, incluidos los controladores de políticas de dispositivos (DPC). Entre los cambios se incluye lo siguiente:
- Nuevos comportamientos que permiten la compatibilidad de las apps con perfiles de trabajo en dispositivos completamente administrados.
- Cambios en el manejo de actualizaciones del sistema, la verificación de apps y la autenticación para aumentar la integridad del dispositivo y del sistema.
- Mejoras en la experiencia del usuario para el aprovisionamiento, las notificaciones, la pantalla Recientes y la VPN siempre activa.
Para ver todos los cambios empresariales en Android 8.0 (nivel de API 26) y descubrir cómo podrían afectar a tu app, consulta Android en empresas.
Apps orientadas a Android 8.0
Estos cambios de comportamiento se aplican exclusivamente a las apps orientadas a Android 8.0 (nivel de API 26) o versiones posteriores. Las apps que se compilan para Android 8.0 o que establecen targetSdkVersion
en Android 8.0 o versiones posteriores deben modificarse para admitir correctamente estos comportamientos, cuando corresponda.
Ventanas de alerta
Las apps que usan el permiso SYSTEM_ALERT_WINDOW
ya no pueden usar los siguientes tipos de ventanas para mostrar ventanas de alerta sobre otras apps y ventanas del sistema:
En su lugar, las apps deben usar un nuevo tipo de ventana llamado TYPE_APPLICATION_OVERLAY
.
Cuando uses el tipo de ventana TYPE_APPLICATION_OVERLAY
para mostrar ventanas de alerta para tu app, ten en cuenta las siguientes características del nuevo tipo de ventana:
- Las ventanas de alerta de una app siempre aparecen en ventanas críticas del sistema, como la barra de estado y los IME.
- El sistema puede mover o cambiar el tamaño de las ventanas que usan el tipo de ventana
TYPE_APPLICATION_OVERLAY
para mejorar la presentación de la pantalla. - Al abrir el panel de notificaciones, los usuarios pueden acceder a la configuración para bloquear en una app la visualización de ventanas de alerta que se muestran con el tipo de ventana
TYPE_APPLICATION_OVERLAY
.
Notificaciones de cambios de contenido
Android 8.0 (nivel de API 26) cambia el comportamiento de ContentResolver.notifyChange()
y registerContentObserver(Uri, boolean, ContentObserver)
para las apps que se orientan a Android 8.0.
Estas APIs ahora solicitan la definición de un ContentProvider
válido para la autoridad en todos los URI. La definición de un ContentProvider
válido con permisos correspondientes ayudará a proteger tu app contra cambios de contenido desde aplicaciones maliciosas y prevendrá la posible fuga de datos privados hacia estas aplicaciones.
Enfoque de las vistas
Los objetos View
en los que se puede hacer clic ahora también se pueden enfocar de forma predeterminada. Si quieres que se pueda hacer clic en un objeto View
, pero que no se pueda enfocar, establece el atributo
android:focusable
en false
en el archivo en formato XML de diseño que contiene el View
o pasa false
a setFocusable()
en la lógica de la IU de tu app.
Coincidencia de usuario-agente en la detección de navegadores
Android 8.0 (nivel de API 26) y versiones posteriores incluyen la cadena de identificador de compilación OPR
. Algunas coincidencias de patrones pueden hacer que la lógica de detección de navegadores identifique incorrectamente un navegador que no es Opera como Opera.
Un ejemplo de esa coincidencia de patrones podría ser el siguiente:
if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}
Para evitar problemas derivados de una identificación errónea, usa una cadena distinta de OPR
como coincidencia de patrones para el navegador Opera.
Seguridad
Los siguientes cambios afectan la seguridad en Android 8.0 (nivel de API 26):
- Si en la configuración de seguridad de red de tu app se desactiva la compatibilidad con tráfico de texto simple, los objetos
WebView
de tu app no pueden acceder a los sitios web mediante HTTP. En su lugar, cada objetoWebView
debe usar HTTPS. - Se quitó el parámetro de configuración del sistema Permitir fuentes desconocidas. En su lugar, el permiso Instalar apps desconocidas administra las instalaciones de apps desconocidas desde fuentes desconocidas. Para obtener más información sobre este nuevo permiso, consulta la guía Permisos de instalación de apps desconocidas.
Para obtener lineamientos adicionales sobre cómo hacer que tu app sea más segura, consulta Seguridad para desarrolladores de Android.
Acceso y visibilidad para cuentas
En Android 8.0 (nivel de API 26), las apps ya no pueden acceder a las cuentas de usuario, a menos que el autenticador las posea o el usuario otorgue acceso a ellas. El permiso GET_ACCOUNTS
ya no es suficiente. Para obtener acceso a una cuenta, las apps deben usar AccountManager.newChooseAccountIntent()
o un método específico de autenticador. Después de obtener acceso a las cuentas, una app puede llamar a AccountManager.getAccounts()
para acceder a ellas.
Android 8.0 da de baja LOGIN_ACCOUNTS_CHANGED_ACTION
. En su lugar, las apps deben usar addOnAccountsUpdatedListener()
para obtener actualizaciones sobre las cuentas durante el tiempo de ejecución.
Si deseas obtener más información sobre las APIs y los métodos nuevos de acceso y visibilidad para cuentas, consulta Acceso y visibilidad para cuentas en la sección Nuevas APIs de este documento.
Privacidad
Los siguientes cambios afectan la privacidad en Android 8.0 (nivel de API 26).
-
Las propiedades del sistema
net.dns1
,net.dns2
,net.dns3
ynet.dns4
ya no están disponibles, un cambio que mejora la privacidad en la plataforma. -
Para obtener información de red, como la de servidores DNS, las apps con el permiso
ACCESS_NETWORK_STATE
pueden registrar un objetoNetworkRequest
oNetworkCallback
. Estas clases están disponibles en Android 5.0 (nivel de API 21) y versiones posteriores. -
Build.SERIAL es obsoleto.
Las apps que necesitan conocer el número de serie del hardware deben usar el nuevo método
Build.getSerial()
, que requiere el permisoREAD_PHONE_STATE
. -
La API de
LauncherApps
ya no permite que las apps de perfil de trabajo obtengan información sobre el perfil principal. Cuando un usuario está en un perfil de trabajo, la API deLauncherApps
se comporta como si no se instalaran apps en otros perfiles dentro del mismo grupo de perfil. Como antes, los intentos de acceder a perfiles no relacionados generan SecurityExceptions.
Permisos
Antes de Android 8.0 (nivel de API 26), si una app solicitaba un permiso en el tiempo de ejecución y este se otorgaba, el sistema también otorgaba a la app, de manera incorrecta, el resto de los permisos que pertenecían al mismo grupo de permisos y que estaban registrados en el manifiesto.
En las apps orientadas a Android 8.0, se corrigió este comportamiento. La app solo obtiene los permisos que ha solicitado explícitamente. Sin embargo, una vez que el usuario otorga un permiso a la app, todas las solicitudes posteriores de permisos de ese grupo de permisos se otorgan automáticamente.
Por ejemplo, supongamos que una app presenta READ_EXTERNAL_STORAGE
y WRITE_EXTERNAL_STORAGE
en su manifiesto.
La app solicita READ_EXTERNAL_STORAGE
y el usuario lo otorga. Si la app está orientada al nivel de API 25 o versiones anteriores, el sistema también otorga WRITE_EXTERNAL_STORAGE
al mismo tiempo, porque pertenece al mismo grupo de permisos STORAGE
y también está registrado en el manifiesto. Si la app está orientada a Android 8.0 (nivel de API 26), el sistema solo otorga READ_EXTERNAL_STORAGE
en ese momento. Sin embargo, si la app luego solicita WRITE_EXTERNAL_STORAGE
, el sistema inmediatamente otorga ese privilegio sin notificar al usuario.
Contenido multimedia
- El framework puede realizar la atenuación automática de audio por sí solo. En este caso, cuando otra aplicación solicita el foco con
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
, la aplicación que lo tiene reduce su volumen, pero, por lo general, no recibe una devolución de llamadaonAudioFocusChange()
y no pierde el foco de audio. Hay APIs nuevas disponibles para anular este comportamiento en las aplicaciones que deben hacer una pausa en lugar de aplicar atenuación automática. - Cuando el usuario recibe una llamada telefónica, los flujos de medios activos se silencian hasta que esta finaliza.
- Todas las APIs relacionadas con el audio deben usar
AudioAttributes
en lugar de tipos de transmisiones de audio para describir el caso de uso de reproducción de audio. Continúa usando los tipos de transmisión de audio únicamente para los controles de volumen. Otros usos de tipos de transmisión aún funcionan (por ejemplo, el argumentostreamType
para el constructorAudioTrack
obsoleto), pero el sistema lo registra como un error. - Cuando se usa un
AudioTrack
, si la aplicación solicita un búfer de audio lo suficientemente grande, el framework intentará usar la salida de búfer profundo si está disponible. - En Android 8.0 (nivel de API 26), el control de los eventos de botones multimedia es diferente:
- El manejo de botones multimedia en una actividad de IU no ha cambiado: las actividades en primer plano aún tienen prioridad en el manejo de eventos de botones multimedia.
- Si la actividad en primer plano no maneja el evento del botón multimedia, el sistema lo envía a la app que más recientemente reprodujo audio de manera local. No se tienen en cuenta el estado activo, las marcas ni el estado de reproducción de una sesión multimedia cuando se determina la app que recibe eventos de botones multimedia.
- Si se lanzó la sesión multimedia de la app, el sistema envía el evento del botón multimedia al
MediaButtonReceiver
de la app, si tiene uno. - Para cualquier otro caso, el sistema descarta el evento de botón multimedia.
Bibliotecas nativas
En las apps orientadas a Android 8.0 (nivel de API 26), las bibliotecas nativas ya no se cargan si contienen un segmento de carga que admite escritura y ejecución. Es posible que algunas apps dejen de funcionar debido a este cambio si tienen bibliotecas nativas con segmentos de carga incorrectos. Esta es una medida para reforzar la seguridad.
Para obtener más información, consulta Segmentos que admiten escritura y ejecución.
Los cambios de vinculadores están unidos al nivel de API que una app tiene como objetivo. Si se produce un cambio de vinculador en el nivel de API objetivo, la app no podrá cargar la biblioteca. Si tienes como objetivo un nivel de API inferior al nivel de API en el que se produce el cambio de vinculador, logcat muestra una advertencia.
Manejo de recopilaciones
En Android 8.0 (nivel de API 26), Collections.sort()
se implementa sobre List.sort()
. Sucedía lo contrario en Android 7.x (niveles de API 24 y 25): la implementación predeterminada de List.sort()
se llamaba Collections.sort()
.
Este cambio permite que Collections.sort()
aproveche implementaciones optimizadas de List.sort()
, pero tiene las siguientes limitaciones:
Las implementaciones de
List.sort()
no deben llamar aCollections.sort()
, ya que esto provocaría un desbordamiento de pila debido a una recurrencia infinita. Por el contrario, si deseas el comportamiento predeterminado en tu implementación deList
, debes evitar anularsort()
.Si una clase superior implementa
sort()
de forma inapropiada, suele ser correcto anularList.sort()
con una implementación compilada sobreList.toArray()
,Arrays.sort()
yListIterator.set()
. Por ejemplo:@Override public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } }
En la mayoría de los casos, también puedes anular
List.sort()
con una implementación que delegue a diferentes implementaciones predeterminadas según el nivel de API. Por ejemplo:@Override public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } }
Si haces esto último solo porque deseas tener un método
sort()
disponible en todos los niveles de API, considera darle un nombre único, comosortCompat()
, en lugar de anularsort()
.-
Collections.sort()
ahora cuenta como una modificación estructural en las implementaciones de List que llaman asort()
. Por ejemplo, en versiones de la plataforma anteriores a Android 8.0 (nivel de API 26), aplicar iteraciones sobre unArrayList
y llamar asort()
a medio camino a través de la iteración habría generado unaConcurrentModificationException
si el ordenamiento se hubiera realizado llamando aList.sort()
.Collections.sort()
no arrojó una excepción.Este cambio hace que el comportamiento de la plataforma sea más uniforme: cualquiera de los enfoques ahora genera un
ConcurrentModificationException
.
Comportamiento de carga de clases
Android 8.0 (nivel de API 26) realiza algunas comprobaciones para garantizar que los cargadores de clases no transgredan las suposiciones de tiempo de ejecución cuando se cargan clases nuevas. Estas verificaciones se realizan si se hace referencia a la clase desde Java (desde forName()
), Dalvik bytecode o JNI. La plataforma no intercepta llamadas directas de Java al método loadClass()
ni verifica los resultados de esas llamadas. Este comportamiento no debe afectar el funcionamiento de cargadores de clases con buen comportamiento.
La plataforma comprueba que el descriptor de la clase que muestra el cargador de clases coincida con el descriptor esperado. Si el descriptor que se muestra no coincide, la plataforma genera un error NoClassDefFoundError
y en la excepción se almacena un mensaje detallado en el cual se menciona la discrepancia.
La plataforma también comprueba que los descriptores de las clases solicitadas sean válidos. Esta comprobación detecta llamadas JNI que indirectamente cargan clases como GetFieldID()
, y se pasan descriptores inválidos a esas clases. Por ejemplo, no se encuentra un campo con firma java/lang/String
debido a que la firma no es válida; debe ser Ljava/lang/String;
.
Esto difiere de una llamada JNI a FindClass()
en la cual java/lang/String
es un nombre válido y completamente calificado.
Android 8.0 (nivel de API 26) no admite que varios cargadores de clases intenten definir clases con el mismo objeto DexFile. Un intento de hacerlo da como resultado que el tiempo de ejecución de Android genere un error InternalError
con el mensaje “Intento de registrar un archivo dex <filename>
con varios cargadores de clases”.
Ahora la API de DexFile es obsoleta y te recomendamos firmemente usar uno de los cargadores de clases de la plataforma, incluidos PathClassLoader
o BaseDexClassLoader
, como alternativa.
Nota: Puedes crear varios cargadores de clases que hagan referencia al mismo contenedor de archivo APK o JAR desde el sistema de archivos. Normalmente, hacer esto no genera demasiada sobrecarga de memoria: si los archivos DEX del contenedor se almacenan en lugar de comprimirse, la plataforma puede realizar una operación mmap
sobre ellos en vez de extraerlos directamente. Sin embargo, si la plataforma debe extraer el archivo DEX del contenedor, hacer referencia a un archivo DEX de este modo puede consumir mucha memoria.
En Android, se considera que todos los cargadores de clases tienen capacidad paralela. Cuando varios subprocesos compiten para cargar la misma clase con el mismo cargador de clases, el primer subproceso en completar la operación gana y el resultado se usa para los otros subprocesos. Este comportamiento ocurre sin importar si el cargador de clases mostró la misma clase o una diferente, o si produjo una excepción. La plataforma ignora de forma automática esas excepciones.
Precaución: En versiones de la plataforma inferiores a Android 8.0 (nivel de API 26), la transgresión de estas suposiciones puede hacer que se defina la misma clase varias veces, se dañe el montón debido a la confusión de clases y se generen otros resultados no deseables.