Cambios de comportamiento en Android 8.0

Además de nuevas funciones y capacidades, Android 8.0 (nivel de API 26) incluye varios cambios en el comportamiento del sistema y de la API. En este documento, se destacan algunos de los cambios clave que debes comprender y tener en cuenta 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 una mayor claridad, esta página se divide en dos secciones: Cambios para todas las apps y Cambios para las apps orientadas a Android 8.0.

Cambios para todas las apps

Estos cambios de comportamiento se aplican a todas las apps cuando se ejecutan en la plataforma Android 8.0 (API nivel 26), independientemente del nivel de API al que se orienten. Todos los desarrolladores deben revisar estos cambios y modificar sus apps para admitirlos de manera adecuada, cuando corresponda.

Background execution limits

Como uno de los cambios que Android 8.0 (nivel de API 26) presenta para mejorar la duración de batería, cuando tu app entra en estado almacenado en caché, sin componentes activos, el sistema libera los bloqueos de activación de la app.

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:

  • Las apps que se ejecutan en segundo plano ahora tienen límites sobre la libertad de acceso a servicios en segundo plano.
  • Las apps no pueden usar sus manifiestos para registrarse en la mayoría de las transmisiones implícitas (es decir, 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 orientó 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 una IllegalStateException si una app orientada a Android 8.0 intenta usar ese método en una situación en la que no se permite crear servicios en segundo plano.
  • El nuevo método Context.startForegroundService() inicia un servicio en primer plano. El sistema permite que las apps llamen a Context.startForegroundService() incluso mientras están en segundo plano. Sin embargo, la app debe llamar al método startForeground() de ese servicio dentro de los cinco segundos posteriores a la creación del 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 estado del sistema, las apps en segundo plano reciben actualizaciones de ubicación con menos frecuencia cuando se usan en un dispositivo con Android 8.0. Este cambio en el 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
  • Wi-Fi Manager

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.
  • Prueba que tu app muestre 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 prácticos 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 los accesos directos a aplicaciones:

  • La transmisión de 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 un acceso directo a la app con el método requestPinShortcut() de la clase ShortcutManager.
  • El intent ACTION_CREATE_SHORTCUT ahora puede crear accesos directos a aplicaciones que puedas administrar usando la clase ShortcutManager. Este intent también puede crear accesos directos de selector heredados que no interactúan con ShortcutManager. Anteriormente, este intent solo podía crear combinaciones de teclas de selector heredadas.
  • Los accesos directos creados con requestPinShortcut() y los accesos directos creados en una actividad que controla el intent ACTION_CREATE_SHORTCUT ahora son accesos directos completos para apps. Como resultado, las apps ahora pueden actualizarlas usando los métodos en ShortcutManager.
  • Los accesos directos heredados conservan su funcionalidad de versiones anteriores de Android, pero debes convertirlos a accesos directos a aplicaciones de forma manual en tu app.

Para obtener más información sobre los cambios en los accesos directos a aplicaciones, consulta la guía de funciones Fija combinaciones de teclas y widgets.

Configuración regional e internacionalización

En Android 7.0 (nivel de API 24), se presentó el concepto de la capacidad de especificar una configuración regional de categoría predeterminada, pero algunas APIs continuaron usando el método genérico Locale.getDefault() sin argumentos cuando en su lugar deberían haber usado la configuración regional predeterminada de la categoría DISPLAY. En Android 8.0 (API nivel 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 displayScript especificado para el argumento Locale no está disponible.

A continuación, se indican los cambios adicionales relacionados con la configuración regional y la internacionalización:

  • Llamar a Currency.getDisplayName(null) arroja una NullPointerException 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 muestreado en el momento del inicio para almacenar en caché los nombres de zona horaria empleados al analizar las fechas y horas. Como resultado, el análisis podría verse afectado de manera negativa si el reloj del sistema no era el correcto en el momento del inicio o en otros casos poco frecuentes.

    Ahora, en casos comunes, la lógica de análisis usa ICU y el valor actual del reloj del sistema cuando se analizan los nombres de zona horaria. Este cambio proporciona resultados más correctos, que pueden diferir de 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 utiliza uno de los siguientes tipos de ventanas 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 se orienta a Android 8.0 (nivel de API 26), 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 las ventanas de alertas en los cambios de comportamiento de las apps orientadas a Android 8.0.

Entrada y navegación

Con la llegada de las apps para Android en ChromeOS y otros factores de forma grandes, como las tablets, observamos un resurgimiento del uso de la navegación con teclado en 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 que dio como resultado un modelo más confiable y predecible para la navegación basada en flechas y pestañas.

En particular, realizamos los siguientes cambios en el comportamiento del enfoque de elementos:

  • Si no definiste ningún color de estado de enfoque para un objeto View (ya sea su elemento de diseño en primer o segundo plano), el framework ahora establecerá un color de enfoque predeterminado para View. Este resalte de foco es un elemento de diseño de ondas que se basa en el tema de la actividad.

    Si no quieres que un objeto View use este resaltado predeterminado cuando recibe el foco, configura el atributo android:defaultFocusHighlightEnabled como false en el archivo en formato XML de diseño que contiene el View o pasa false a setDefaultFocusHighlightEnabled() en la lógica de la IU de tu app.

  • Para probar cómo la entrada del teclado afecta el enfoque de los elementos de la IU, puedes habilitar la opción para desarrolladores Dibujo > Mostrar límites de diseño. En Android 8.0, esta opción muestra un ícono "X" sobre el elemento que está enfocado actualmente.

Además, todos los elementos de la barra de herramientas de Android 8.0 son automáticamente clústeres de navegación con teclado, lo que facilita a los usuarios navegar hacia cada barra de herramientas y hacia ella con más facilidad.

Si quieres obtener más información para mejorar la compatibilidad con la navegación con teclado dentro de tu app, consulta la guía Compatibilidad con la navegación con teclado.

Autocompletado de formularios web

Ahora que Autofill Framework de Android brinda compatibilidad integrada con la función Autocompletar, cambiaron los siguientes métodos relacionados con los objetos WebView para las apps instaladas en dispositivos que ejecutan Android 8.0 (nivel de API 26):

WebSettings
WebViewDatabase
  • Llamar a clearFormData() ya no tiene ningún efecto.
  • El método hasFormData() ahora muestra false. Anteriormente, este método mostraba true cuando el formulario contenía datos.

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 presionar dos veces en acciones ACTION_CLICK. Este cambio permite que TalkBack se comporte de manera más similar a otros servicios de accesibilidad.

    Si los objetos View de tu app usan el control táctil personalizado, debes verificar que aún funcionen con TalkBack. Es posible que solo debas registrar el controlador de clics que usan tus objetos View. Si TalkBack aún no reconoce los gestos realizados en estos objetos View, anula performAccessibilityAction().

  • Los servicios de accesibilidad ahora reconocen todas las instancias de ClickableSpan dentro de los objetos TextView de tu app.

Si deseas obtener más información para mejorar la accesibilidad de tu app, consulta Accesibilidad.

Conectividad de red y HTTP(S)

Android 8.0 (nivel de API 26) incluye los siguientes cambios de comportamiento con respecto a las redes y la conectividad HTTP(S):

  • Las solicitudes de OPTIONS sin cuerpo tienen un encabezado Content-Length: 0. Anteriormente, no tenían un encabezado Content-Length.
  • HttpURLConnection normaliza las URL que contienen rutas de acceso vacías agregando una barra diagonal después del nombre de host o autoridad. Por ejemplo, convierte http://example.com en http://example.com/.
  • Un selector de proxy personalizado configurado a través de ProxySelector.setDefault() solo apunta a 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 admitía una solución alternativa para aceptar etiquetas vacías en nombres de host, lo cual es un uso ilegal de los URI. Esta solución alternativa era para brindar compatibilidad con versiones anteriores de libcore. Los desarrolladores que usaban la API de forma incorrecta veían el mensaje de ADB: "El URI example.com tiene etiquetas vacías en el nombre de host. Este tiene un formato incorrecto y no se aceptará en versiones futuras de Android". En Android 8.0, se quita esta solución alternativa; el sistema muestra un valor nulo para los URI con errores de formato.

  • La implementación de HttpsURLConnection en Android 8.0 no realiza resguardo de versiones no seguras del protocolo TLS/SSL.
  • El control de la tunelización de conexiones HTTP(S) presenta los siguientes cambios:
    • Cuando se establece la tunelización de la conexión HTTPS a través de la conexión, el sistema coloca correctamente el número de puerto (:443) en la línea de host al enviar esta información a un servidor intermedio. Anteriormente, el número de puerto solo ocurrí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.

      Del mismo modo, el sistema ya no copia el encabezado de usuario-agente de la solicitud tunelizada a la solicitud de proxy que configura el túnel. En cambio, 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 ICMP antes de volver al protocolo Echo TCP.
    • Ahora se podrá acceder a algunos hosts que bloquean el puerto 7 (TCP Echo), como google.com, si aceptan el protocolo Echo ICMP.
    • Para hosts verdaderamente inaccesibles, este cambio significa que se dedica el doble de tiempo a que se muestre 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 ningún cálculo respecto de la cantidad de bytes recibidos. Por lo tanto, las apps no deben depender de ninguna cantidad mínima o máxima de bytes que se muestran. En cambio, deben evaluar la longitud del array 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 de Wi-Fi para facilitar la elección de la red que ofrece la mejor experiencia del 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 Wi-Fi cuando se encuentra cerca una red guardada de alta calidad.

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 forma incorrecta la negociación de versión de protocolo TLS, HttpsURLConnection ya no intenta la solución alternativa de volver a versiones de protocolo anteriores y reintentar.
  • Android 8.0 (nivel de API 26) aplica un filtro de procesamiento seguro (SECCOMP) a todas las apps. La lista de llamadas del sistema permitidas se restringe a aquellas expuestas a través de bionic. Aunque se proporcionan varias llamadas de sistema para la retrocompatibilidad, no recomendamos su uso.
  • Los objetos WebView de tu app ahora se ejecutan en modo multiproceso. Para mejorar la seguridad, el contenido web se maneja en un proceso separado y aislado del proceso que contiene la app.
  • Ya no puedes suponer que los APKs 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 del directorio.
  • Para obtener 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 de fuentes desconocidas:

Para obtener más información sobre la instalación de apps desconocidas, 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.

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.
    • En el caso de las apps que se instalaron antes de la actualización inalámbrica a una versión de Android 8.0 (nivel de API 26) (nivel de API 26), el valor de ANDROID_ID sigue siendo el mismo, a menos que se desinstalen y se reinstalen después de manera inalámbrica. Para conservar los valores en las desinstalaciones después de una actualización inalámbrica, los desarrolladores pueden asociar los valores antiguos y nuevos mediante la copia de seguridad de 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 de ANDROID_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 ya no ven el mismo ID de Android (incluso para el mismo usuario).
    • El valor de ANDROID_ID no cambia cuando se desinstala o reinstala el paquete, siempre que la clave de firma sea la misma (y la app no se haya instalado antes de la 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.
    • Para el envío de dispositivos con un ID de publicidad y Servicios de Google Play, debes usar el ID de publicidad. El ID de publicidad, un sistema simple y estándar para monetizar apps, es un ID único que el usuario puede restablecer para publicidad. Lo proporcionan los Servicios de Google Play.

      Otros fabricantes de dispositivos deben seguir proporcionando ANDROID_ID.

  • La consulta de la propiedad del sistema net.hostname produce un resultado nulo.

Registro de excepciones no capturadas

Si una app instala un Thread.UncaughtExceptionHandler que no llama a través del Thread.UncaughtExceptionHandler predeterminado, el sistema no cierra 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 llamen 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 hacer que el código existente ahora tenga un tipo de datos ambiguo que se muestre; por ejemplo, si hay someMethod(View) y someMethod(TextView), el resultado de una llamada es findViewById().
  • Cuando se usa un lenguaje 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 las versiones anteriores de Android, el componente Proveedor de contactos permite a los desarrolladores obtener datos de uso de cada contacto. Estos datos de uso exponen información de cada dirección de correo electrónico y cada número de teléfono asociado con un contacto, incluida la cantidad de veces que se contactó al contacto y la última vez que se contactó con él. 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 (nivel de API 26) y versiones posteriores, las consultas de datos de uso muestran aproximaciones en lugar de valores exactos. El sistema Android mantiene internamente los valores exactos, por lo que este cambio no afecta a la API de autocompletado.

Este cambio de comportamiento afecta los siguientes parámetros de consulta:

Manejo de recopilaciones

AbstractCollection.removeAll() y AbstractCollection.retainAll() ahora siempre arrojan una NullPointerException. Antes, 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 API y funciones de las 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 conocer cómo podrían afectar a tu app, consulta Android en la empresa.

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 con Android 8.0 o que configuran targetSdkVersion en Android 8.0 o versiones posteriores deben modificar sus apps para admitir estos comportamientos de manera correcta, 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 cambio, 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 tipo de ventana nuevo:

  • 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 en la pantalla.
  • Cuando se abre el panel de notificaciones, los usuarios pueden acceder a la configuración para impedir que una app muestre 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) en las apps orientadas a Android 8.0.

Estas APIs ahora requieren que se defina un ContentProvider válido para la autoridad en todos los URI. Si defines un ContentProvider válido con permisos relevantes, podrás proteger tu app contra cambios de contenido proveniente de apps maliciosas y evitar que filtren datos potencialmente privados en ellas.

Enfoque de las vistas

De forma predeterminada, los objetos View en los que se puede hacer clic ahora también son enfocables. Si deseas que se pueda hacer clic en un objeto View, pero que no se pueda enfocar, configura el atributo android:focusable como 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.

Coincidencias de usuarios-agentes en la detección del navegador

Android 8.0 (nivel de API 26) y las versiones posteriores incluyen la string del identificador de compilación OPR. Algunas coincidencias de patrones pueden hacer que la lógica de detección del navegador identifique de forma incorrecta un navegador que no es de Opera como Opera. Un ejemplo de coincidencia de patrón 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 relacionados con una identificación incorrecta, usa una cadena que no sea OPR como coincidencia de patrón 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 inhabilita la compatibilidad con el tráfico de texto simple, los objetos WebView de la app no podrán acceder a los sitios web a través de HTTP. En su lugar, cada objeto WebView debe usar HTTPS.
  • Se quitó la configuración del sistema Permitir fuentes desconocidas. En su lugar, el permiso Instalar apps desconocidas administra las instalaciones de apps desconocidas de fuentes desconocidas. Para obtener más información sobre este nuevo permiso, consulta la guía Permisos desconocidos de instalación de apps.

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 sea el propietario de las cuentas o el usuario otorgue ese acceso. 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.

En Android 8.0, LOGIN_ACCOUNTS_CHANGED_ACTION deja de estar disponible. En su lugar, las apps deben usar addOnAccountsUpdatedListener() para obtener actualizaciones sobre las cuentas durante el tiempo de ejecución.

Si quieres obtener información sobre las APIs y los métodos nuevos que se agregaron para el acceso y la visibilidad de la cuenta, consulta Acceso y visibilidad para cuentas en la sección APIs nuevas 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 y net.dns4 ya no están disponibles, un cambio que mejora la privacidad en la plataforma.
  • Para obtener información de red, como los servidores DNS, las apps con el permiso ACCESS_NETWORK_STATE pueden registrar un objeto NetworkRequest o NetworkCallback. Estas clases están disponibles en Android 5.0 (nivel de API 21) y versiones posteriores.
  • Build.SERIAL es obsoleto. En cambio, las apps que necesitan conocer el número de serie del hardware deben usar el nuevo método Build.getSerial(), que requiere el permiso READ_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 tiene un perfil de trabajo, la API de LauncherApps se comporta como si no se instalaran apps en otros perfiles dentro del mismo grupo de perfiles. 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 durante el tiempo de ejecución y este se otorgaba, el sistema también le otorgaba de manera incorrecta el resto de los permisos que pertenecían al mismo grupo de permisos y estaban registrados en el manifiesto.

En el caso de las apps orientadas a Android 8.0, este comportamiento se corrigió. A la app solo se le otorgan los permisos que solicitó de manera explícita. Sin embargo, una vez que el usuario otorga un permiso a la app, todas las solicitudes posteriores de permisos en ese grupo de permisos se otorgan automáticamente.

Por ejemplo, supongamos que una app muestra READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE en su manifiesto. La app solicita READ_EXTERNAL_STORAGE, y el usuario lo otorga. Si la app tiene como objetivo el nivel de API 25 o un nivel inferior, el sistema también otorga WRITE_EXTERNAL_STORAGE al mismo tiempo, ya que pertenece al mismo grupo de permisos STORAGE y también está registrado en el manifiesto. Si la app se orienta a Android 8.0 (nivel de API 26), el sistema solo otorga READ_EXTERNAL_STORAGE en ese momento. Sin embargo, si la app más tarde solicita WRITE_EXTERNAL_STORAGE, el sistema otorga de inmediato ese privilegio sin pedirle permiso al usuario.

Contenido multimedia

  • El framework puede realizar disminución de volumen de audio automático por sí mismo. En este caso, cuando otra aplicación solicita el foco con AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, la aplicación que tiene el foco reduce su volumen, pero no suele recibir una devolución de llamada onAudioFocusChange() y no pierde el foco de audio. Hay nuevas APIs disponibles para anular este comportamiento en las aplicaciones que necesitan pausarse en lugar de atenuarse.
  • Cuando el usuario recibe una llamada telefónica, las transmisiones de contenido multimedia activos se silencian durante la llamada.
  • Todas las APIs relacionadas con el audio deben usar AudioAttributes en lugar de tipos de transmisión 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 siguen funcionando (por ejemplo, el argumento streamType para el constructor obsoleto AudioTrack), pero el sistema los 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 de contenido multimedia es diferente:
    1. El control de los botones multimedia en una actividad de la IU no cambió: las actividades de primer plano aún tienen prioridad en el control de eventos de botones multimedia.
    2. Si la actividad en primer plano no controla el evento del botón de medios, el sistema direcciona el evento a la app que reprodujo el audio de manera local más recientemente. El estado activo, las marcas y el estado de reproducción de una sesión multimedia no se tienen en cuenta cuando se determina qué app recibe eventos de botones multimedia.
    3. 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.
    4. 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 algún 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 puede cargar la biblioteca. Si apuntas a un nivel de API inferior al nivel de API en el que se produce el cambio del 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() llamada Collections.sort().

Este cambio permite que Collections.sort() aproveche las implementaciones optimizadas de List.sort(), pero tiene las siguientes restricciones:

  • Las implementaciones de List.sort() no deben llamar a Collections.sort(), ya que se produciría un desbordamiento de pila debido a una recurrencia infinita. En cambio, si deseas el comportamiento predeterminado en tu implementación de List, debes evitar anular sort().

    Si una clase superior implementa sort() de forma inapropiada, generalmente está bien anular List.sort() con una implementación compilada sobre List.toArray(), Arrays.sort() y ListIterator.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 se 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 quieres tener un método sort() disponible en todos los niveles de API, considera asignarle un nombre único, como sortCompat(), en lugar de anular sort().

  • Collections.sort() ahora cuenta como una modificación estructural en las implementaciones de List que llaman a sort(). Por ejemplo, en versiones de la plataforma anteriores a Android 8.0 (nivel de API 26), iterar sobre una ArrayList y llamar a sort() a mitad de la iteración habría generado una ConcurrentModificationException si el ordenamiento se hubiera realizado llamando a List.sort(). Collections.sort() no arrojó una excepción.

    Este cambio hace que el comportamiento de la plataforma sea más coherente: Cualquiera de los enfoques ahora genera una ConcurrentModificationException.

Comportamiento de carga de clases

Android 8.0 (nivel de API 26) realiza verificaciones para garantizar que los cargadores de clases no rompan las suposiciones del tiempo de ejecución cuando se cargan clases nuevas. Estas comprobaciones se realizan si se hace referencia a la clase desde Java (de 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 los cargadores de clases con buen comportamiento.

La plataforma verifica 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 muestra un error NoClassDefFoundError y, en la excepción, almacena un mensaje detallado en el que se señala la discrepancia.

La plataforma también comprueba que los descriptores de las clases solicitadas sean válidos. Esta verificación detecta llamadas de JNI que cargan clases de forma indirecta como GetFieldID() y pasan descriptores no válidos a esas clases. Por ejemplo, no se encuentra un campo con firma java/lang/String porque esa firma no es válida; debería ser Ljava/lang/String;.

Esto es diferente de una llamada de JNI a FindClass(), en la que java/lang/String es un nombre válido completamente calificado.

Android 8.0 (nivel de API 26) no admite que varios cargadores de clases intenten definir clases con el mismo objeto DexFile. Si se intenta hacerlo, el tiempo de ejecución de Android arroja un error InternalError con el mensaje "Intenta registrar el archivo dex <filename> con varios cargadores de clases".

La API de DexFile dejó de estar disponible y, en su lugar, te recomendamos que uses uno de los cargadores de clases de la plataforma, incluidos PathClassLoader o BaseDexClassLoader.

Nota: Puedes crear varios cargadores de clases que hagan referencia al mismo contenedor de archivo APK o JAR del 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 en ellos en lugar 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, gana el primer subproceso que completa la operación, y el resultado se usa para los otros subprocesos. Este comportamiento ocurre independientemente de si el cargador de clases devolvió la misma clase, devolvió una clase diferente o generó una excepción. La plataforma ignora de forma automática esas excepciones.

Precaución: En versiones de la plataforma anteriores a Android 8.0 (nivel de API 26), romper 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 produzcan otros efectos no deseados.