Cambios de comportamiento en Android 8.0

Además de nuevas funciones y capacidades, Android 8.0 (API nivel 26) incluye diversos cambios de 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 mayor claridad, esta página se divide en dos secciones: Cambios para todas las apps y Cambios para 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 correcta, cuando corresponda.

Background execution limits

Como uno de los cambios que presenta Android 8.0 (nivel de API 26) para mejorar la duración de batería, cuando la app entra en el estado 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 el nivel de libertad que tienen para acceder a los 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 le 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 reciban 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 práctico.
  • Considera usar el proveedor de ubicación combinada (FLP) o el geovallado para manejar los casos prácticos que dependan 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 y 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 administres 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 accesos directos de selector heredados.
  • Los atajos creados con requestPinShortcut() y los accesos directos creados en una actividad que controla el intent ACTION_CREATE_SHORTCUT ahora son accesos directos a aplicaciones completos. 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 en 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 Cómo fijar accesos directos y widgets.

Configuración regional e internacionalización

Android 7.0 (nivel de API 24) introdujo el concepto de poder especificar una configuración regional de categoría predeterminada, pero algunas APIs 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 recurrirá 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:

  • La llamada 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 de reloj del sistema muestreado en el momento del inicio a fin de almacenar en caché los nombres de zona horaria usados para analizar la fecha y la hora. Como resultado, el análisis podría verse afectado de manera negativa si la hora del sistema no era la correcta en el momento del inicio o en otros casos menos comunes.

    Ahora, en casos comunes, la lógica de análisis usa la ICU y el valor del reloj del sistema actual cuando se analizan los nombres de zona horaria. Este cambio proporciona resultados más correctos, que pueden diferir de las 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 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 ventanas de alerta en los cambios de comportamiento de 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, estamos viendo 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 generó 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 resaltado predeterminado para View. Este resaltado del enfoque es un elemento de diseño de ondas que se basa en el tema de la actividad.

    Si no deseas que un objeto View use este resaltado predeterminado cuando reciba el foco, configura el atributo android:defaultFocusHighlightEnabled como false en el archivo en formato XML de diseño que contiene 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 de "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 dentro y fuera de cada barra de herramientas como un todo.

Si deseas 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 proporciona compatibilidad integrada con la funcionalidad de autocompletado, 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 de 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 como otros servicios de accesibilidad.

    Si los objetos View de tu app usan el control táctil personalizado, debes verificar que funcionen de todas formas con TalkBack. Quizás solo necesites registrar el controlador de clics que usan tus objetos View. Si TalkBack aún no reconoce los gestos que se realizan 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 URLs que contienen rutas vacías agregando una barra diagonal después del nombre del host o de la autoridad. Por ejemplo, convierte http://example.com en http://example.com/.
  • Un selector de proxy personalizado que se establece a través de ProxySelector.setDefault() solo se orienta 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 los nombres de host, lo que es un uso ilegal de los URI. Esta solución alternativa era para fines de compatibilidad con versiones anteriores de libcore. Los desarrolladores que usen la API de forma incorrecta verían un mensaje de ADB: "El URI example.com tiene etiquetas vacías en el nombre de host. Este formato 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 URIs con formato incorrecto.

  • La implementación de HttpsURLConnection que realiza Android 8.0 no realiza un resguardo de versiones no seguras del protocolo TLS/SSL.
  • La tunelización de conexiones HTTP(S) cambió de la siguiente manera:
    • Cuando se tuneliza 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 desde 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) arroja una SocketException si el método connect() ejecutado anteriormente falla.
    • DatagramSocket.connect() establece una pendingSocketException si hay un error interno. Antes de Android 8.0, una llamada recv() posterior generaba una SocketException aunque una llamada send() se realizara correctamente. Para lograr uniformidad, ambas llamadas ahora producen una SocketException.
  • InetAddress.isReachable() intenta el ICMP antes de volver al protocolo Echo de TCP.
    • Se podrá acceder a algunos hosts que bloquean el puerto 7 (TCP Echo), como google.com, si aceptan el protocolo Echo ICMP.
    • En el caso de hosts verdaderamente inaccesibles, este cambio significa que se invierte el doble de tiempo antes de que se muestre la llamada.

Bluetooth

Android 8.0 (nivel de API 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 con respecto a la cantidad de bytes recibidos. Por lo tanto, las apps no deben depender de una 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 exceda 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 una serie de mejoras en la configuración de Wi-Fi para facilitar la elección de la red Wi-Fi 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, activación automática de 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 ya no intenta la solución alternativa de recurrir a versiones de protocolo anteriores y volver a intentarlo.
  • Android 8.0 (nivel de API 26) aplica un filtro de procesamiento seguro (SECCOMP) a todas las apps. La lista de llamadas de sistema permitidas se restringe a las expuestas a través de bionic. Aunque se proporcionan varias otras 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 controla 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 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.

Privacidad

Android 8.0 (nivel de API 26) realiza los siguientes cambios en la plataforma relacionados con la privacidad.

  • 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 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 que ejecuta Android 8.0, el valor de ANDROID_ID ahora se define por clave de firma de la 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 con la desinstalación o reinstalación del paquete, siempre que la clave de firma sea la misma (y la app no se haya instalado antes de una versión inalámbrica de Android 8.0).
    • El valor de ANDROID_ID no cambia incluso si una actualización del sistema hace que cambie la clave de firma del paquete.
    • Para los dispositivos que se envían con un ID de publicidad y Servicios de Google Play, debes usar el ID de publicidad. El ID de publicidad es un sistema estándar y simple para monetizar apps. Se trata de un ID único que el usuario puede restablecer para la 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 este caso. 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:

  • Como resultado, el código existente ahora puede mostrar un tipo de datos ambiguo que se muestra. Por ejemplo, si hay someMethod(View) y someMethod(TextView), el resultado de una llamada es findViewById().
  • Cuando se usa el lenguaje de origen Java 8, se requiere una conversión 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()), se deberá 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 a los desarrolladores obtener datos de uso de cada contacto. Estos datos de uso muestran información de cada dirección de correo electrónico y de 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 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 activada

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 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 modificarlas para que admitan 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 cambio, las apps deben usar un nuevo tipo de ventana llamado TYPE_APPLICATION_OVERLAY.

Cuando uses el tipo de ventana TYPE_APPLICATION_OVERLAY a fin de 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 pantalla.
  • Cuando los usuarios abren el panel de notificaciones, 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. La definición de un ContentProvider válido con permisos relevantes te ayudará a proteger tu app contra cambios de contenido por parte de apps maliciosas y a evitar que se filtren datos potencialmente privados en apps maliciosas.

Enfoque de las vistas

Los objetos View en los que se puede hacer clic ahora también son enfocables de forma predeterminada. 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 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 erróneamente 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 que surjan de una identificación errónea de este tipo, utiliza 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 la configuración de seguridad de red de tu app inhabilita la compatibilidad con tráfico de texto simple, los objetos WebView de tu app no podrán acceder a los sitios web mediante HTTP. 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 de instalación de apps desconocidos.

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 deseas obtener información sobre las nuevas APIs y los métodos agregados para el acceso y la visibilidad de las cuentas, consulta Acceso a la cuenta y visibilidad 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 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 del 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 causan 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 a la app el resto de los permisos que pertenecían al mismo grupo de permisos y que estaban registrados en el manifiesto.

En el caso de las apps orientadas a Android 8.0, se corrigió este comportamiento. 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 enumera 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 uno anterior, 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 luego solicita WRITE_EXTERNAL_STORAGE, el sistema otorga ese privilegio de inmediato sin pedirle al usuario.

Contenido multimedia

  • El framework puede realizar disminución automática del audio por sí mismo. En ese caso, cuando otra aplicación solicita el enfoque 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 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 disminuir el volumen.
  • Cuando el usuario recibe una llamada telefónica, las transmisiones de contenido multimedia activas se silencian durante la llamada.
  • Todas las APIs relacionadas con 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 aún funcionan (por ejemplo, el argumento streamType para el constructor obsoleto AudioTrack), 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 eventos de botones multimedia es diferente:
    1. El manejo de los botones multimedia en una actividad de la IU no cambió: las actividades en primer plano siguen teniendo prioridad en el control de los eventos de botones multimedia.
    2. Si la actividad en primer plano no controla el evento del botón de medios, el sistema enruta el evento a la app que reprodujo el audio más reciente de forma local. El estado activo, las marcas y el estado de reproducción de una sesión multimedia no se tienen en cuenta para determinar qué app recibe eventos de botones multimedia.
    3. Si se liberó la sesión multimedia de la app, el sistema envía el evento de 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 admita 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 de endurecimiento de la seguridad.

Para obtener más información, consulta Segmentos que se pueden escribir y ejecutar.

Los cambios de vinculadores están unidos al nivel de API que una app tiene como objetivo. Si hay 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(). Lo contrario ocurría 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() porque generarí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() durante la iteración habría generado una ConcurrentModificationException si la ordenación se hubiera realizado llamando a List.sort(). Collections.sort() no mostró ninguna 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) comprueba que los cargadores de clases no rompan las suposiciones del tiempo de ejecución cuando se cargan clases nuevas. Estas comprobaciones se realizan sin importar si se hace referencia a la clase desde Java (desde forName()), Dalvik bytecode o JNI. La plataforma no intercepta las llamadas directas de Java al método loadClass() ni verifica los resultados de esas llamadas. Este comportamiento no debería afectar el funcionamiento de los cargadores de clases que se comportan bien.

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 que 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 la firma java/lang/String porque la 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. Un intento de hacerlo provoca que el tiempo de ejecución de Android arroje un error InternalError con el mensaje "Try to register dex file <filename> with multiple class loaders".

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

Nota: Puedes crear varios cargadores de clases que hagan referencia al mismo contenedor de archivos APK o JAR del sistema de archivos. Normalmente, esto no genera mucha 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 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 corren para cargar la misma clase con el mismo cargador de clases, gana el primer subproceso en completar la operación, y el resultado se usa para los otros subprocesos. Este comportamiento se produce independientemente de si el cargador de clases devolvió la misma clase, mostró una clase diferente o arrojó una excepción. La plataforma ignora de forma automática esas excepciones.

Precaución: En las versiones de la plataforma anteriores a Android 8.0 (nivel de API 26), romper estas suposiciones puede llevar a definir la misma clase varias veces, a dañar el montón debido a la confusión de clases y a otros efectos no deseados.