Cambios de comportamiento en Android 7.0

Además de nuevas funciones y capacidades, Android 7.0 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.

Si publicaste anteriormente una app para Android, ten en cuenta que esta podría verse afectada por estos cambios en la plataforma.

Batería y memoria

Android 7.0 incluye cambios en el comportamiento del sistema para mejorar la duración de la batería de los dispositivos y reducir el uso de RAM. Estos cambios pueden afectar el acceso de tu app a los recursos del sistema, además de la forma en que tu app interactúa con otras apps mediante ciertos intents implícitos.

Descanso

Descanso, presentado en Android 6.0 (nivel de API 23), mejora la duración de la batería aplazando las actividades de la CPU y la red cuando un usuario deja un dispositivo desenchufado, quieto y con la pantalla apagada. Android 7.0 ofrece mejoras adicionales a Descanso mediante la aplicación de un subconjunto de restricciones de CPU y red mientras el dispositivo está desenchufado con la pantalla apagada, pero no necesariamente con el teléfono celular cuando el usuario está desenchufado (por ejemplo, cuando el usuario está desenchufado).

Ilustración de cómo Descanso aplica un primer nivel de restricciones de actividad del sistema para prolongar la duración de batería

Figura 1: Ilustración del modo en que Descanso aplica un primer nivel de restricciones de actividad del sistema para prolongar la duración de batería.

Cuando un dispositivo funciona con la batería y la pantalla permanece apagada durante un tiempo determinado, el dispositivo activa el modo Descanso y aplica el primer subconjunto de restricciones: desactiva el acceso a la red de las apps y aplaza tareas y sincronizaciones. Si el dispositivo permanece inactivo durante un tiempo determinado después de activar el modo Descanso, el sistema aplica el resto de las restricciones del modo Descanso a las alarmas PowerManager.WakeLock, AlarmManager, GPS y escaneos de Wi-Fi. Independientemente de si se aplican algunas o todas las restricciones de Descanso, el sistema activa el dispositivo durante períodos de mantenimiento breves, durante los cuales las aplicaciones tienen acceso a la red y pueden ejecutar cualquier tarea o sincronización aplazada.

Ilustración del modo en que Descanso aplica un segundo nivel de restricciones de actividad del sistema después de que el dispositivo permanece quieto durante un tiempo determinado

Figura 2: Ilustración del modo en que Descanso aplica un segundo nivel de restricciones de actividad del sistema después de que el dispositivo permanece quieto durante un tiempo determinado.

Ten en cuenta que, cuando se activa la pantalla o se enchufa el dispositivo, se desactiva el modo Descanso y se quitan estas restricciones de procesamiento. El comportamiento adicional no afecta las recomendaciones ni las prácticas recomendadas para adaptar tu app a la versión anterior de Descanso, presentada en Android 6.0 (nivel de API 23), según se describe en Cómo optimizar para Descanso y App Standby. Aun así, debes seguir esas recomendaciones, como usar Firebase Cloud Messaging (FCM) para enviar y recibir mensajes, y comenzar a planificar actualizaciones para adaptarse al comportamiento adicional de Descanso.

Project Svelte: Optimizaciones en segundo plano

Android 7.0 quita tres transmisiones implícitas para ayudar a optimizar el uso de la memoria y el consumo de energía. Este cambio es necesario porque las transmisiones implícitas suelen iniciar apps que se registran para escucharlas en segundo plano. Quitar estas transmisiones puede mejorar considerablemente el rendimiento del dispositivo y la experiencia del usuario.

Los dispositivos móviles cambian de conectividad con frecuencia, como cuando se alterna entre Wi-Fi y datos móviles. Actualmente, las apps pueden supervisar los cambios en la conectividad registrando un receptor para la transmisión CONNECTIVITY_ACTION implícita en su manifiesto. Dado que muchas apps se registran para recibir esta transmisión, un solo cambio de red puede hacer que todas se activen y procesen la transmisión a la vez.

Del mismo modo, en versiones anteriores de Android, las apps podían registrarse para recibir transmisiones implícitas de ACTION_NEW_PICTURE y ACTION_NEW_VIDEO de otras apps, como Cámara. Cuando un usuario toma una foto con la app de Cámara, estas apps se activan para procesar la transmisión.

Para solucionar estos problemas, en Android 7.0 se aplican las siguientes optimizaciones:

Si la app usa alguno de estos intents, debes quitarles las dependencias lo antes posible para poder orientar los dispositivos con Android 7.0 correctamente. El framework de Android ofrece varias soluciones para mitigar la necesidad de estas transmisiones implícitas. Por ejemplo, la API de JobScheduler proporciona un mecanismo sólido para programar operaciones de red cuando se cumplen condiciones especificadas, como una conexión a una red no medida. Incluso puedes usar JobScheduler para reaccionar a los cambios realizados en los proveedores de contenido.

Para obtener más información sobre las optimizaciones en segundo plano en Android 7.0 (nivel de API 24) y cómo adaptar tu app, consulta Optimizaciones en segundo plano.

Cambios en los permisos

En Android 7.0, se incorporan cambios en permisos que pueden afectar tu app.

Cambios en los permisos del sistema de archivos

Para mejorar la seguridad de los archivos privados, el directorio privado de las apps orientadas a Android 7.0 o versiones posteriores tiene acceso restringido (0700). Esta configuración evita la filtración de metadatos de archivos privados, como su tamaño o existencia. Este cambio en los permisos tiene varios efectos secundarios:

Intercambio de archivos entre apps

En el caso de las apps orientadas a Android 7.0, el framework de Android aplica la política de la API StrictMode que prohíbe exponer los URI de file:// fuera de la app. Si un intent que contiene un URI de archivo sale de tu app, esta falla con una excepción FileUriExposedException.

Para compartir archivos entre aplicaciones, debes enviar un URI content:// y otorgar un permiso de acceso temporal en el URI. La manera más fácil de otorgar este permiso es usar la clase FileProvider. Para obtener más información sobre permisos y cómo compartir archivos, consulta Cómo compartir archivos.

Mejoras de accesibilidad

En Android 7.0, se incluyen cambios destinados a mejorar la usabilidad de la plataforma para los usuarios con visión reducida o discapacidad visual. Por lo general, estos cambios no deben requerir modificaciones en el código de tu app. Sin embargo, debes revisar estas funciones y probarlas con tu app para evaluar los posibles impactos en la experiencia del usuario.

Zoom de la pantalla

Android 7.0 permite a los usuarios configurar Tamaño de visualización, que amplía o contrae todos los elementos de la pantalla, lo que mejora la accesibilidad del dispositivo para los usuarios con baja visión. Los usuarios no pueden acercar la pantalla más allá del ancho mínimo de sw320dp, que es el ancho de un Nexus 4, un teléfono común de tamaño mediano.

Pantalla en la que se muestra el tamaño sin zoom de un dispositivo que ejecuta una imagen del sistema de Android 7.0
Pantalla que muestra el efecto de aumentar el tamaño de la pantalla de un dispositivo que ejecuta una imagen del sistema de Android 7.0

Figura 3: En la pantalla de la derecha, se muestra el efecto de aumentar el tamaño de la pantalla de un dispositivo que ejecuta una imagen del sistema de Android 7.0.

Cuando cambia la densidad del dispositivo, el sistema notifica a las apps en ejecución de las siguientes maneras:

  • Si una app tiene como objetivo el nivel de API 23 o uno inferior, el sistema cierra automáticamente todos los procesos en segundo plano. Eso significa que, si un usuario abandona esa app para abrir la pantalla Configuración y cambia la configuración de Tamaño de visualización, el sistema cierra la app de la misma manera que lo haría en una situación de poca memoria. Si la app tiene procesos en primer plano, el sistema notifica a esos procesos el cambio de configuración según se describe en Cómo controlar los cambios en el tiempo de ejecución, como si la orientación del dispositivo hubiera cambiado.
  • Si una app se orienta a Android 7.0, todos sus procesos (en primer y segundo plano) reciben una notificación del cambio de configuración, como se describe en Cómo controlar los cambios en tiempo de ejecución.

En la mayoría de las apps no se necesitan cambios para admitir esta función, siempre y cuando sigan las prácticas recomendadas de Android. Verificaciones específicas que deben realizarse:

  • Prueba tu app en un dispositivo con un ancho de pantalla de sw320dp y asegúrate de que funcione bien.
  • Cuando cambie la configuración del dispositivo, actualiza la información almacenada en caché que dependa de la densidad, como los mapas de bits o recursos almacenados en caché que se carguen desde la red. Busca cambios en la configuración cuando se reanude la actividad de la app, después de la pausa.

    Nota: Si almacenas en caché datos que dependen de la configuración, te recomendamos que incluyas metadatos relevantes, como el tamaño de pantalla adecuado o la densidad de píxeles para esos datos. Guardar estos metadatos te permite decidir si necesitas actualizar los datos almacenados en caché después de un cambio de configuración.

  • Evita especificar dimensiones con unidades px, ya que no escalan con la densidad de pantalla. En cambio, especifica las dimensiones con unidades de píxeles independientes de la densidad (dp).

Vision Settings en el asistente de configuración

Android 7.0 incluye Vision Settings en la pantalla de bienvenida, en la que los usuarios pueden configurar las siguientes opciones de accesibilidad en un nuevo dispositivo: Gesto de ampliación, Tamaño de fuente, Tamaño de visualización y TalkBack. Este cambio aumenta la visibilidad de errores relacionados con diferentes configuraciones de pantalla. Para evaluar el impacto de esta función, debes probar tus apps con estos parámetros de configuración habilitados. Puedes encontrar los parámetros de configuración en Configuración > Accesibilidad.

Apps del NDK con vínculos a bibliotecas de plataformas

A partir de Android 7.0, el sistema evita que las apps se vinculen de forma dinámica con bibliotecas que no pertenezcan al NDK, lo que puede provocar que tu app falle. El objetivo de este cambio en el comportamiento es crear una experiencia de app coherente en todas las actualizaciones de la plataforma y en diferentes dispositivos. Si bien es posible que tu código no se vincule con bibliotecas privadas, es posible que una biblioteca estática de terceros de tu app lo esté haciendo. Por lo tanto, todos los desarrolladores deben asegurarse de que sus apps no fallen en dispositivos que ejecutan Android 7.0. Si tu app usa código nativo, solo debes usar APIs públicas del NDK.

Tu app podría intentar acceder a las APIs de plataformas privadas de las siguientes tres maneras:

  • Tu app accede directamente a bibliotecas de plataformas privadas. Debes actualizar tu app para incluir su propia copia de esas bibliotecas o usar las APIs públicas del NDK.
  • Tu app usa una biblioteca de terceros que accede a bibliotecas de plataformas privadas. Incluso si tienes la certeza de que tu app no accede a bibliotecas privadas de forma directa, debes probarla en este caso.
  • Tu app hace referencia a una biblioteca que no está incluida en su APK. Por ejemplo, esto podría suceder si intentas usar tu propia copia de OpenSSL, pero olvidas empaquetarla con el APK de la app. La app puede ejecutarse normalmente en versiones de la plataforma de Android que incluyan libcrypto.so. Sin embargo, la app podría fallar en versiones posteriores de Android que no incluyan esta biblioteca (como Android 6.0 y versiones posteriores). Para solucionar este problema, asegúrate de agrupar todas las bibliotecas que no pertenezcan al NDK con tu APK.

Las apps no deben usar bibliotecas nativas que no estén incluidas en el NDK, ya que pueden cambiar o quitarse entre diferentes versiones de Android. El cambio de OpenSSL a BoringSSL es un ejemplo de ese cambio. Además, debido a que no existen requisitos de compatibilidad para bibliotecas de plataformas no incluidas en el NDK, los diferentes dispositivos pueden ofrecer diferentes niveles de compatibilidad.

Para reducir el impacto que esta restricción puede tener en las apps lanzadas actualmente, se puede acceder temporalmente a un conjunto de bibliotecas que se usa de manera significativa, como libandroid_runtime.so, libcutils.so, libcrypto.so y libssl.so, en Android 7.0 (nivel de API 24) para las apps que se orientan al nivel de API 23 o versiones anteriores. Si tu app carga una de estas bibliotecas, logcat genera una advertencia y aparece un aviso en el dispositivo de destino para notificarte. Si ves estas advertencias, debes actualizar tu app para incluir su propia copia de esas bibliotecas o usar solo las APIs públicas del NDK. Las versiones futuras de la plataforma de Android podrían restringir el uso de bibliotecas privadas por completo y hacer que tu app falle.

Todas las apps generan un error de entorno de ejecución cuando llaman a una API a la que no se puede acceder de forma pública ni temporal. Como resultado, System.loadLibrary y dlopen(3) muestran NULL y pueden provocar que tu app falle. Debes revisar el código de tu app para quitar el uso de APIs de plataformas privadas y probar por completo tus apps con un dispositivo o emulador que ejecute Android 7.0 (nivel de API 24). Si no sabes con certeza si tu app usa bibliotecas privadas, puedes verificar logcat para identificar el error en el tiempo de ejecución.

En la siguiente tabla, se describe el comportamiento que deberías esperar de una app según su uso de bibliotecas nativas privadas y su nivel de API objetivo (android:targetSdkVersion).

Bibliotecas Nivel de API objetivo Acceso en tiempo de ejecución por medio de un vinculador dinámico Comportamiento de Android 7.0 (nivel de API 24) Comportamiento de la plataforma Android futura
Pública incluida en el NDK Cualquiera Fácil acceso Funciona como se espera. Funciona como se espera.
Privada (bibliotecas privadas temporalmente disponibles) 23 o inferior Temporalmente disponible Funciona como se espera, pero aparece una advertencia de logcat. Error en tiempo de ejecución
Privada (bibliotecas privadas temporalmente disponibles) 24 o superior Restringido Error en tiempo de ejecución Error en tiempo de ejecución
Privada (otra) Cualquiera Restringido Error en tiempo de ejecución Error en tiempo de ejecución

Verifica si tu app usa bibliotecas privadas

Para ayudarte a identificar problemas al cargar bibliotecas privadas, logcat puede generar una advertencia o un error de tiempo de ejecución. Por ejemplo, si tu app está orientada al nivel de API 23 o anterior, e intenta acceder a una biblioteca privada en un dispositivo con Android 7.0, es posible que veas una advertencia similar a la siguiente:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

Estas advertencias de logcat te indican qué biblioteca intenta acceder a una API de plataforma privada, pero no provocarán que tu app falle. Sin embargo, si la app se orienta al nivel de API 24 o superior, logcat genera el siguiente error de tiempo de ejecución y tu app puede fallar:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

También es posible que veas estos resultados de logcat si tu app usa bibliotecas de terceros que vinculan dinámicamente API de plataformas privadas. La herramienta readelf de Android 7.0DK te permite generar una lista de todas las bibliotecas compartidas vinculadas de forma dinámica de un archivo .so determinado mediante la ejecución del siguiente comando:

aarch64-linux-android-readelf -dW libMyLibrary.so

Actualiza tu app

A continuación, se incluyen algunos pasos que puedes seguir para corregir estos tipos de errores y asegurarte de que tu app no falle en futuras actualizaciones de la plataforma:

  • Si tu app usa bibliotecas de plataformas privadas, debes actualizarla para incluir su propia copia de esas bibliotecas o usar las APIs públicas del NDK.
  • Si tu app usa una biblioteca de terceros que accede a símbolos privados, comunícate con el autor de la biblioteca para actualizarla.
  • Asegúrate de incluir todas las bibliotecas que no pertenezcan al NDK en tu APK.
  • Usa funciones estándar de JNI en lugar de getJavaVM y getJNIEnv de libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • Usa __system_property_get en lugar del símbolo privado property_get de libcutils.so. Para ello, usa __system_property_get y agrega lo siguiente:
    #include <sys/system_properties.h>
    

    Nota: La disponibilidad y el contenido de las propiedades del sistema no se prueban a través de CTS. Una mejor solución sería evitar usar estas propiedades por completo.

  • Usa una versión local del símbolo SSL_ctrl de libcrypto.so. Por ejemplo, debes vincular estáticamente libcyrpto.a en tu archivo .so o incluir una versión de libcrypto.so vinculada de forma dinámica de BoringSSL/OpenSSL y empaquetarla en tu APK.

Android for Work

Android 7.0 contiene cambios para apps orientadas a Android for Work, como cambios en la instalación de certificados, el restablecimiento de contraseñas, la administración de usuarios secundarios y el acceso a identificadores de dispositivos. Si compilas apps para entornos de Android for Work, debes revisar estos cambios y modificar tu app según corresponda.

  • Debes instalar un instalador de certificados delegados para que el DPC pueda configurarlo. En el caso de las apps de propietarios de perfiles y de dispositivos orientadas a Android 7.0 (nivel de API 24), debes instalar el instalador de certificados delegados antes de que el controlador de política del dispositivo (DPC) llame a DevicePolicyManager.setCertInstallerPackage(). Si aún no está instalado, el sistema arroja una IllegalArgumentException.
  • Las restricciones de restablecimiento de contraseñas para administradores de dispositivos ahora se aplican a los propietarios de perfiles. Los administradores de dispositivos ya no pueden usar DevicePolicyManager.resetPassword() para borrar contraseñas ni cambiar las que ya están establecidas. Pueden establecer una contraseña, pero solo cuando el dispositivo no tiene contraseña, PIN ni patrón.
  • Los propietarios de dispositivos y perfiles pueden administrar cuentas incluso si se establecen restricciones. Los propietarios de dispositivos y perfiles pueden llamar a las APIs de administración de cuentas incluso si se aplican restricciones de usuario de DISALLOW_MODIFY_ACCOUNTS.
  • Los propietarios de dispositivos pueden administrar usuarios secundarios de manera más sencilla. Cuando un dispositivo se ejecuta en el modo de propietario de dispositivo, se establece automáticamente la restricción DISALLOW_ADD_USER. Esto evita que los usuarios creen usuarios secundarios no administrados. Además, los métodos CreateUser() y createAndInitializeUser() dejaron de estar disponibles; los reemplaza el nuevo método DevicePolicyManager.createAndManageUser().
  • Los propietarios de dispositivos pueden acceder a identificadores de dispositivos. El propietario de un dispositivo puede acceder a la dirección MAC de Wi-Fi de un dispositivo mediante DevicePolicyManager.getWifiMacAddress(). Si nunca se habilitó la conexión Wi-Fi en el dispositivo, este método muestra un valor de null.
  • La configuración Work Mode controla el acceso a las apps de trabajo. Cuando el modo de trabajo está desactivado, el selector del sistema indica que las apps de trabajo no están disponibles atenuándolas. Si habilitas el modo de trabajo nuevamente, se restablecerá el comportamiento normal.
  • Cuando se instala un archivo PKCS #12 que contiene una cadena de certificados de cliente y la clave privada correspondiente de la IU de configuración, el certificado de CA de la cadena ya no se instala en el almacenamiento de credenciales de confianza. Esto no afecta el resultado de KeyChain.getCertificateChain() cuando las apps intentan recuperar la cadena de certificados de cliente más tarde. Si es necesario, el certificado de CA debe instalarse en el almacenamiento de credenciales de confianza a través de la IU de configuración por separado, con un formato de codificación DER en una extensión de archivo .crt o .cer.
  • A partir de Android 7.0, el almacenamiento y la inscripción con huellas dactilares se administran por usuario. Si el cliente de Device Policy (DPC) de un propietario de perfil se orienta al nivel de API 23 (o anterior) en un dispositivo con Android 7.0 (nivel de API 24), el usuario aún puede establecer la huella digital en el dispositivo, pero las aplicaciones de trabajo no pueden acceder a la huella digital del dispositivo. Cuando el DPC se orienta al nivel de API 24 o superior, el usuario puede configurar la huella digital específicamente para el perfil de trabajo desde Configuración > Seguridad > Seguridad del perfil de trabajo.
  • DevicePolicyManager.getStorageEncryptionStatus() muestra un nuevo estado de encriptación ENCRYPTION_STATUS_ACTIVE_PER_USER para indicar que la encriptación está activa y que la clave de encriptación está vinculada al usuario. El nuevo estado solo se muestra si el DPC se orienta al nivel de API 24 y a niveles superiores. En el caso de las apps que se orientan a niveles de API anteriores, se muestra ENCRYPTION_STATUS_ACTIVE, incluso si la clave de encriptación es específica del usuario o perfil.
  • En Android 7.0, varios métodos que normalmente afectarían a todo el dispositivo se comportan de manera diferente si este tiene un perfil de trabajo instalado con una comprobación de trabajo separada. En lugar de afectar a todo el dispositivo, estos métodos se aplican solo al perfil de trabajo. (La lista completa de dichos métodos se encuentra en la documentación de DevicePolicyManager.getParentProfileInstance()). Por ejemplo, DevicePolicyManager.lockNow() bloquea solo el perfil de trabajo, en lugar de bloquear todo el dispositivo. Para cada uno de estos métodos, puedes obtener el comportamiento anterior llamando al método en la instancia superior de DevicePolicyManager; para obtener este superior, llama a DevicePolicyManager.getParentProfileInstance(). Por ejemplo, si llamas al método lockNow() de la instancia superior, se bloqueará todo el dispositivo.

Retención de anotaciones

Android 7.0 soluciona un error por el cual se ignoraba la visibilidad de las anotaciones. Este problema permitió que el tiempo de ejecución accediera a anotaciones a las que no debería haber podido acceder. Entre estas anotaciones, se incluyen las siguientes:

  • VISIBILITY_BUILD: Diseñado para ser visible solo en el tiempo de compilación.
  • VISIBILITY_SYSTEM: destinada a ser visible en el tiempo de ejecución, pero solo al sistema subyacente

Si tu app se basó en este comportamiento, agrega una política de retención a las anotaciones que deben estar disponibles en el tiempo de ejecución. Para ello, usa @Retention(RetentionPolicy.RUNTIME).

Cambios en la configuración predeterminada de TLS/SSL

Android 7.0 realiza los siguientes cambios en la configuración predeterminada de TLS/SSL que usan las apps para el tráfico HTTPS y otro tráfico TLS/SSL:

  • Se inhabilitaron los conjuntos de algoritmos de cifrado RC4.
  • Ahora los conjuntos de algoritmos de cifrado CHACHA20-POLY1305 están habilitados.

Si RC4 está inhabilitado de forma predeterminada, es posible que se generen fallas en la conectividad HTTPS o TLS/SSL cuando el servidor no negocia los conjuntos de algoritmos de cifrado modernos. La solución preferida es mejorar la configuración del servidor para habilitar conjuntos de algoritmos y protocolos de cifrado más sólidos y modernos. Lo ideal sería que se habiliten TLSv1.2 y AES-GCM; además, que se habiliten los conjuntos de algoritmos de cifrado de confidencialidad directa (ECDHE) y que estos sean preferidos.

Una alternativa es modificar la app para que use un SSLSocketFactory personalizado y se comunique con el servidor. La fábrica debe diseñarse para crear instancias SSLSocket que tengan habilitados algunos de los conjuntos de algoritmos de cifrado requeridos por el servidor, además de los conjuntos de algoritmos de cifrado predeterminados.

Nota: Estos cambios no corresponden a WebView.

Apps orientadas a Android 7.0

Estos cambios en el comportamiento se aplican exclusivamente a las apps orientadas a Android 7.0 (nivel de API 24) o versiones posteriores. Las apps que se compilan con Android 7.0 o que establecen targetSdkVersion en Android 7.0 o versiones posteriores deben modificar sus apps para admitir estos comportamientos de manera correcta, cuando corresponda.

Cambios en la serialización

Android 7.0 (nivel de API 24) corrigió un error en el cálculo del serialVersionUID predeterminado en el que no coincidía con la especificación.

Las clases que implementan Serializable y no especifican un campo serialVersionUID explícito podrían ver un cambio en su serialVersionUID predeterminado, lo que generaría una excepción cuando se intentaba deserializar instancias de la clase que se serializaron en una versión anterior o que se serializaron mediante una app orientada a una versión anterior. El mensaje de error será similar al siguiente:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

Para solucionar estos problemas, se requiere agregar un campo serialVersionUID a cualquier clase afectada con el valor de stream classdesc serialVersionUID del mensaje de error, p.ej., 1234 en este caso. Ese cambio cumple con todas las prácticas recomendadas para escribir código de serialización y funcionará en todas las versiones de Android.

El error específico que se corrigió estaba relacionado con la presencia de métodos de inicializador estáticos, es decir, <clinit>. De acuerdo con la especificación, la presencia o ausencia de un método de inicializador estático en la clase afectará el serialVersionUID predeterminado calculado para esa clase. Antes de la corrección de errores, el cálculo también verificaba la superclase en busca de un inicializador estático si una clase no tenía uno.

Para aclarar, este cambio no afecta a las apps orientadas al nivel de API 23 o versiones anteriores, a las clases que tienen un campo serialVersionUID o a las clases que tienen un método de inicializador estático.

Otros aspectos importantes

  • Cuando una app se ejecuta en Android 7.0, pero está orientada a un nivel de API inferior y el usuario cambia el tamaño de pantalla, el proceso de la app finaliza. La app debe poder manejar correctamente esta situación. De lo contrario, fallará cuando el usuario la restablezca desde Recents.

    Debes probar tu app para asegurarte de que este comportamiento no ocurra. Puedes hacerlo provocando una falla idéntica cuando se cierra la app de forma manual mediante DDMS.

    Las apps orientadas a Android 7.0 (nivel de API 24) y versiones posteriores no finalizan automáticamente por cambios de densidad. Sin embargo, es posible que respondan en forma deficiente a los cambios de configuración.

  • En Android 7.0, las apps deben tener capacidad para manejar correctamente los cambios de configuración y no deben fallar en inicios posteriores. Para verificar el comportamiento de la app, cambia el tamaño de la fuente (Configuración > Pantalla > Tamaño de fuente) y restablece la app desde Recientes.
  • Debido a un error en versiones anteriores de Android, el sistema no indicaba la escritura a un socket TCP en el subproceso principal como un incumplimiento de modo estricto. Android 7.0 resuelve este error. Las apps que muestran este comportamiento ahora arrojan una android.os.NetworkOnMainThreadException. En general, realizar operaciones de red en el subproceso principal no es una buena idea, ya que estas operaciones suelen tener una latencia alta que provoca ANR y bloqueos.
  • De forma predeterminada, la familia de métodos Debug.startMethodTracing() ahora almacena los resultados en el directorio específico del paquete en el almacenamiento compartido, en lugar de hacerlo en el nivel superior de la tarjeta SD. Esto significa que las apps ya no necesitan solicitar el permiso WRITE_EXTERNAL_STORAGE para usar estas APIs.
  • Muchas APIs de plataforma comenzaron a verificar si se envían cargas útiles grandes a través de transacciones Binder, y el sistema ahora vuelve a mostrar TransactionTooLargeExceptions como RuntimeExceptions, en lugar de registrarlas o suprimirlas silenciosamente. Un ejemplo común es almacenar demasiados datos en Activity.onSaveInstanceState(), lo que hace que ActivityThread.StopInfo arroje una RuntimeException cuando tu app se orienta a Android 7.0.
  • Si una app publica tareas Runnable en un View, y View no está conectado a una ventana, el sistema pone en cola la tarea Runnable con el View; la tarea Runnable no se ejecuta hasta que View se adjunta a una ventana. Este comportamiento corrige los siguientes errores:
    • Si una app publica en una View desde un subproceso que no sea el subproceso de IU de la ventana prevista, Runnable puede ejecutarse en el subproceso incorrecto como resultado.
    • Si la tarea Runnable se publicaba desde un subproceso que no fuera un subproceso de looper, la app podría exponer la tarea Runnable.
  • Si una app en Android 7.0 con el permiso DELETE_PACKAGES intenta borrar un paquete instalado por otra app, el sistema requiere la confirmación del usuario. En esta situación, las apps deben esperar STATUS_PENDING_USER_ACTION como el estado que se muestra cuando invocan a PackageInstaller.uninstall().
  • El proveedor de JCA llamado Crypto está obsoleto porque su único algoritmo (SHA1PRNG) es débil en términos criptográficos. Las apps ya no pueden usar SHA1PRNG para derivar claves (de forma no segura) porque este proveedor ya no está disponible. Para obtener más información, consulta la entrada de blog El proveedor de seguridad "Crypto" quedó obsoleto en Android N.