Cambios de comportamiento en Android 7.0

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

Si publicaste anteriormente una app para Android, ten en cuenta que tu app 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 batería de los dispositivos y reducir el uso de RAM. Estos cambios pueden afectar el acceso de tu app a recursos del sistema, y también la manera en que tu app interactúa con otras mediante determinadas intents implícitas.

Descanso

Descanso, presentado en Android 6.0 (nivel de API 23), prolonga la duración de la batería aplazando actividades de CPU y red cuando un usuario deja un dispositivo desenchufado, quieto y con la pantalla apagada. Android 7.0 ofrece más mejoras para Descanso mediante la aplicación de un subconjunto de restricciones de CPU y red mientras el dispositivo se encuentra desenchufado y con la pantalla apagada, aunque no necesariamente quieto; por ejemplo, al ir dentro del bolsillo de un usuario en movimiento.

Ilustración del modo en que Descanso aplica un primer nivel de restricciones de actividad del sistema para prolongar la duración de la 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 la batería.

Cuando un dispositivo funciona con la batería y la pantalla permanece apagada durante un tiempo determinado, se activa en este el modo Descanso y se aplica el primer subconjunto de restricciones: Se desactiva el acceso de las apps a la red y se aplazan tareas y sincronizaciones. Si el dispositivo permanece quieto durante un tiempo determinado después de activar el modo Descanso, el sistema aplica el resto de las restricciones del modo Descanso a las búsquedas de PowerManager.WakeLock, AlarmManager, GPS y Wi-Fi. Independientemente de que se apliquen algunas restricciones del modo Descanso o todas ellas, el sistema activa el dispositivo durante períodos de mantenimiento breves en los cuales las aplicaciones tienen acceso a la red y pueden ejecutar sincronizaciones o procesos aplazados.

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 lo descrito en Optimización para Descanso y App Standby. De todos modos, debes seguir las recomendaciones; por ejemplo, la de usar Firebase Cloud Messaging (FCM) para enviar y recibir mensajes, y la de planificar actualizaciones para adaptar el comportamiento adicional de Descanso.

Project Svelte: Optimizaciones en segundo plano

En Android 7.0, se quitan 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 a menudo inician apps registradas para recibirlas en segundo plano. La eliminación de estas transmisiones puede mejorar sustancialmente el rendimiento del dispositivo y la experiencia del usuario.

Los dispositivos móviles están sujetos a cambios de conectividad frecuentes, como cuando se cambia entre Wi-Fi y datos móviles. Actualmente, las apps pueden realizar controles en busca de cambios en la conectividad registrando un receptor para la transmisión implícita CONNECTIVITY_ACTION en su manifiesto. Debido a que muchas apps se registran para recibir esta transmisión, un único 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 ACTION_NEW_PICTURE y ACTION_NEW_VIDEO de otras apps, como Cámara. Cuando un usuario toma una foto con la app Cámara, estas apps se activan para procesar la transmisión.

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

Si tu app usa alguno de estos intents, debes quitarles las dependencias tan pronto como sea posible para orientar de manera correcta a dispositivos con Android 7.0 o versiones posteriores. El framework de Android proporciona 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 específicas, como una conexión a una red de uso no medido. 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). Este parámetro de configuración evita la fuga 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 las apps orientadas a Android 7.0, el framework de Android aplica la política de la API de StrictMode que prohíbe exponer URIs de file:// fuera de tu app. Si un intent que contiene un URI de archivo sale de tu app, esta última experimenta una falla con una excepción de FileUriExposedException.

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

Mejoras de accesibilidad

Android 7.0 incluye cambios destinados a mejorar la usabilidad de la plataforma para usuarios con problemas de visión o problemas de visión. Estos cambios generalmente no deben exigir modificaciones en el código de tu app. Sin embargo, debes revisar estas funciones y probarlas con tu app para evaluar el posible impacto en la experiencia del usuario.

Zoom de la pantalla

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

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

Figura 3: En la pantalla de la derecha, se muestra el efecto que tiene aumentar Display size para un dispositivo con una imagen de 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 se orienta al nivel de API 23 o uno anterior, el sistema automáticamente finaliza todos los procesos en segundo plano. Esto significa que, si un usuario sale de una app de este tipo para abrir la pantalla Configuración y cambia el parámetro de configuración Tamaño de pantalla, el sistema finalizará 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 en la configuración como se describe en Manejo de cambios en tiempo de ejecución, así como lo haría si cambiara la orientación del dispositivo.
  • Si una app se orienta a Android 7.0, se notifica a todos sus procesos (en primer y segundo plano) el cambio en la configuración, como se describe en Manejo de cambios en tiempo de ejecución.

La mayoría de las apps no necesitan hacer ningún cambio para admitir esta función, siempre que sigan las prácticas recomendadas de Android. Verificaciones específicas que deben realizarse:

  • Prueba tu app en un dispositivo con un ancho de pantalla sw320dp y asegúrate de que funcione bien.
  • Cuando se modifique la configuración del dispositivo, actualiza la información almacenada en caché que dependa de la densidad, como los mapas de bits o los 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 incluir 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 responden a la densidad de pantalla. En su lugar, especifica 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, donde los usuarios pueden configurar los siguientes parámetros de accesibilidad en un nuevo dispositivo: Gesto de ampliación, Tamaño de fuente, Tamaño de la pantalla y TalkBack. Este cambio aumenta la visibilidad de errores relacionados con diferentes ajustes de pantalla. Para evaluar el impacto de esta función, debes probar tus apps con esta configuración habilitada. Puedes encontrar los parámetros 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 dinámicamente con bibliotecas que no pertenezcan al NDK, lo cual puede hacer que tu app falle. El objetivo de este cambio en el comportamiento es crear una experiencia de app coherente en diferentes actualizaciones de plataforma y 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 sí lo haga. Por lo tanto, todos los desarrolladores deben garantizar que sus apps no fallen en dispositivos con Android 7.0. Si tu app usa código nativo, solo debes usar APIs de NDK públicas.

Hay tres formas en las que tu app puede intentar acceder a las APIs de plataformas privadas:

  • Tu app accede directamente a bibliotecas de plataformas privadas. Debes actualizar tu app para incluir su propia copia de esas bibliotecas o usar las NDK APIs públicas.
  • Tu app usa una biblioteca de terceros que accede a bibliotecas de plataformas privadas. Incluso si estás seguro de que tu app no accede a bibliotecas privadas directamente, deberás hacer pruebas en tu app.
  • Tu app hace referencia a una biblioteca que no está incluida en su APK. Por ejemplo, esto podría suceder si intentaras usar tu propia copia de OpenSSL y olvidaras integrarla al APK de tu app. La app puede ejecutarse normalmente en versiones de la plataforma Android que incluyan libcrypto.so. Sin embargo, la app podría fallar en versiones posteriores de Android que no incluyan esta biblioteca (por ejemplo, Android 6.0 y versiones posteriores). Para solucionar esto, asegúrate de vincular 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 porque pueden cambiar o desaparecer entre diferentes versiones de Android. El cambio de OpenSSL a BoringSSL es un ejemplo de modificaciones como esta. Además, debido a que no existen requisitos de compatibilidad para bibliotecas de plataformas no incluidas en el NDK, diferentes dispositivos pueden ofrecer distintos niveles de compatibilidad.

Para reducir el impacto que esta restricción puede tener en las apps que se lanzaron actualmente, se puede acceder temporalmente a un conjunto de bibliotecas que se usan mucho (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 una notificación en el dispositivo objetivo. Si ves estas advertencias, debes actualizar tu app para que incluya su propia copia de esas bibliotecas o usar solo las APIs públicas del NDK. Las versiones futuras de la plataforma Android pueden restringir el uso de bibliotecas privadas y hacer que tu app falle.

Todas las apps generan un error en tiempo 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 hacer 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 estás seguro de si tu app usa bibliotecas privadas, puedes revisar logcat para identificar el error en tiempo de ejecución.

En la siguiente tabla, se describe el comportamiento que deberías esperar de una app según el uso que haga de las 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 Accesible 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 en tiempo de ejecución. Por ejemplo, si tu app se orienta al nivel de API 23 o a niveles inferiores e intenta acceder a una biblioteca privada en un dispositivo con Android 7.0, es posible que recibas 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 la biblioteca que intenta acceder a una API de plataforma privada, pero no harán que falle tu app. Sin embargo, si la app se orienta al nivel de API 24 o a niveles superiores, logcat genera el siguiente error en 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 visualices estos resultados de logcat si tu app usa bibliotecas de terceros que se vinculan de forma dinámica a APIs 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 ejecutando el siguiente comando:

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

Actualiza tu app

Estos son algunos pasos que puedes seguir para solucionar 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 NDK APIs públicas.
  • 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 JNI estándares 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 property_get privado de libcutils.so. Para ello, usa __system_property_get con la siguiente inclusión:
    #include <sys/system_properties.h>

    Nota: La disponibilidad y el contenido de las propiedades del sistema no se prueban mediante 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, deberías vincular estáticamente libcyrpto.a en tu archivo .so, o incluir una versión de libcrypto.so de BoringSSL/OpenSSL vinculada dinámicamente e incluirla en tu APK.

Android for Work

Android 7.0 contiene cambios para apps orientadas a Android for Work, entre los que se incluyen modificaciones 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 antes de que el DPC pueda configurarlo. Para 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 el instalador 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 modificar las que ya están establecidas. Los administradores de dispositivos aún 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 aun cuando haya restricciones. Los propietarios de dispositivos y perfiles pueden llamar a las APIs de administración de cuentas incluso si hay restricciones para el usuario de DISALLOW_MODIFY_ACCOUNTS.
  • Los propietarios de dispositivos pueden administrar usuarios secundarios de manera más sencilla. Cuando un dispositivo funciona en el modo de propietario de dispositivo, automáticamente se establece 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. Los propietarios de dispositivos pueden acceder a la dirección MAC de Wi-Fi de un dispositivo a través de DevicePolicyManager.getWifiMacAddress(). Si nunca se habilitó la función Wi-Fi en el dispositivo, este método devuelve un valor de null.
  • La configuración Work Mode controla el acceso a las apps de trabajo. Cuando este ajuste está desactivado, el lanzador del sistema indica que las apps de trabajo no están disponibles atenuándolas. Para volver a restaurar el comportamiento normal, habilita el modo de trabajo nuevamente.
  • Cuando se instala un archivo de PKCS n.o 12 que contiene una cadena de certificados de cliente y la clave privada correspondiente de la IU de configuración, el certificado de la AC 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 AC debe instalarse en el almacenamiento de credenciales confiable mediante la IU de configuración por separado, con un formato de codificación DER y una extensión de archivo .crt o .cer.
  • A partir de Android 7.0, el almacenamiento y la inscripción con huellas digitales se administran por usuario. Si el cliente de la política de dispositivos (DPC) de un propietario de perfil se orienta al nivel de API 23 (o versiones anteriores) 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 ella. Cuando el DPC se orienta al nivel de API 24 y versiones posteriores, el usuario puede configurar la huella dactilar específicamente para el perfil de trabajo dirigiéndose a 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 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 para el usuario o el perfil.
  • En Android 7.0, varios métodos que normalmente afectarían al dispositivo en su totalidad 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 todo el dispositivo. Para cada uno de estos métodos, puedes obtener el comportamiento antiguo llamando al método de la instancia superior de DevicePolicyManager. Para acceder a esta instancia, llama a DevicePolicyManager.getParentProfileInstance(). Por ejemplo, si llamas al método lockNow() de la instancia superior, se bloquea 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. Entre estas anotaciones, se incluyen las siguientes:

  • VISIBILITY_BUILD: Se diseñó para ser visible solo en el tiempo de compilación.
  • VISIBILITY_SYSTEM: Su objetivo es ser visible en el tiempo de ejecución, pero solo para el sistema subyacente.

Si tu app se basa en este comportamiento, agrega una política de retención para 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 TLS/SSL predeterminada que usan las apps para el tráfico HTTPS y otro tráfico TLS/SSL:

  • Los conjuntos de algoritmos de cifrado RC4 ahora están inhabilitados.
  • Los conjuntos de algoritmos de cifrado CHACHA20-POLY1305 ahora están habilitados.

La inhabilitación de RC4 de forma predeterminada puede provocar fallas en la conectividad HTTPS o TLS/SSL cuando el servidor no negocia conjuntos de algoritmos de cifrado modernos. La solución preferida es mejorar la configuración del servidor para habilitar conjuntos y protocolos de algoritmos de cifrado más sólidos y modernos. Idealmente, se deberían habilitar TLSv1.2 y AES-GCM; además, se deberían habilitar conjuntos de cifrado de confidencialidad directa (ECDHE), que son los preferidos.

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

Nota: Estos cambios no se relacionan con WebView.

Apps orientadas a Android 7.0

Estos cambios de comportamiento se aplican exclusivamente a apps orientadas a Android 7.0 (nivel de API 24) o versiones posteriores. Las apps que se compilan para Android 7.0 o que establecen targetSdkVersion en Android 7.0 o versiones posteriores deben modificarse para admitir correctamente estos comportamientos, cuando corresponda.

Cambios de serialización

Android 7.0 (nivel de API 24) corrigió un error en el cálculo del serialVersionUID predeterminado 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 fueron serializadas en una versión anterior o serializadas por una app orientada a una versión anterior. El mensaje de error se verá de la siguiente manera:

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

Para solucionar estos problemas, es necesario 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 recomendaciones de 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>. Según 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 del error, 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 a 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 la pantalla, el proceso de la app finaliza. La app debe tener capacidad para manejar correctamente esta situación. De lo contrario, se bloqueará cuando el usuario la restaure desde Recents.

    Debes probar tu app para garantizar que este comportamiento no tenga lugar. Puedes hacerlo generando un bloqueo idéntico cuando finalices manualmente el proceso de la app mediante DDMS.

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

  • En Android 7.0, las apps deben tener capacidad para manejar correctamente los cambios de configuración y no deben bloquearse durante inicios posteriores. Puedes verificar el comportamiento de las apps modificando el tamaño de la fuente (Setting > Display > Font size) y restaurándolas desde Recents.
  • Debido a un error en versiones anteriores de Android, el sistema no indicaba la escritura a un socket del TCP en el subproceso principal como una violación del modo strict. Android 7.0 resuelve este error. Las apps que demuestran este comportamiento ahora arrojan una android.os.NetworkOnMainThreadException. Por lo general, realizar operaciones de red en el subproceso principal no es una buena idea, ya que estas operaciones suelen tener una latencia alta que genera errores de ANR y bloqueos.
  • De forma predeterminada, la familia de métodos Debug.startMethodTracing() ahora almacena 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 la plataforma ahora comenzaron a verificar si se envían cargas útiles grandes a través de transacciones Binder. Además, el sistema ahora vuelve a emitir 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 la app se orienta a Android 7.0.
  • Si una app publica tareas Runnable en un View y View no está adjunta a una ventana, el sistema pone en cola la tarea Runnable con View. La tarea Runnable no se ejecuta hasta que View se adjunta a una ventana. Este comportamiento soluciona los siguientes errores:
    • Si una app publicó en una View desde un subproceso que no sea el de la IU de la ventana prevista, es posible que Runnable se ejecute en el subproceso incorrecto.
    • Si la tarea Runnable se publicaba desde un subproceso que no fuera un subproceso de looper, la app podía exponer la tarea Runnable.
  • Si una app en Android 7.0 con el permiso DELETE_PACKAGES intenta borrar un paquete instalado por otra, el sistema solicita 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 PackageInstaller.uninstall().
  • El proveedor de JCA llamado Crypto ya no está disponible, ya que su único algoritmo (SHA1PRNG) es débil desde el punto de vista criptográfico. Las apps ya no pueden usar SHA1PRNG para derivar (de forma insegura) claves debido a que este proveedor ya no está disponible. Para obtener más información, consulta la entrada de blog El proveedor de seguridad "Crypto" dejó de estar disponible en Android N.