Además de nuevas funciones y capacidades, Android 7.0 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.
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 la batería de los dispositivos y reducir el uso de RAM. Estos cambios pueden afectar el acceso de la app a los recursos del sistema, además de la forma en que esta interactúa con otras apps mediante ciertos intents implícitos.
Descanso
Esta función, que se introdujo en Android 6.0 (nivel de API 23), mejora la duración de la batería, ya que aplaza las actividades de la CPU y la red cuando un usuario deja un dispositivo desconectado, quieto y con la pantalla apagada. Android 7.0 ofrece mejoras adicionales a esta función mediante la aplicación de un subconjunto de restricciones de CPU y red mientras el dispositivo está desconectado con la pantalla apagada, pero no necesariamente con la pantalla apagada, pero no necesariamente con la pantalla apagada.
![Ilustración de cómo Descanso aplica el primer nivel de restricciones de actividad del sistema para mejorar la duración de batería](https://developer.android.com/static/images/android-7.0/doze-diagram-1.png?authuser=7&hl=es)
Figura 1: Ilustración de cómo Descanso aplica el primer nivel de restricciones de actividad del sistema para mejorar la duración de batería.
Cuando un dispositivo funciona con batería y la pantalla estuvo apagada durante un tiempo determinado, se activa el modo Descanso en el dispositivo y se 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 de Descanso a las alarmas PowerManager.WakeLock
, AlarmManager
, GPS y búsqueda de Wi-Fi. Independientemente de que se apliquen 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 de cómo Descanso aplica un segundo nivel de restricciones de actividad del sistema después de que el dispositivo permanece quieto durante un tiempo determinado](https://developer.android.com/static/images/android-7.0/doze-diagram-2.png?authuser=7&hl=es)
Figura 2: Ilustración de cómo 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), como se describe en Cómo optimizar para Descanso y App Standby. De todas maneras, deberás 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. La eliminación de estas transmisiones puede beneficiar de forma sustancial el rendimiento del dispositivo y la experiencia del usuario.
Los dispositivos móviles experimentan cambios de conectividad frecuentes, como cuando se alternan entre Wi-Fi y datos móviles. Actualmente, las apps pueden supervisar los cambios de conectividad registrando un receptor para la transmisión CONNECTIVITY_ACTION
implícita en su manifiesto. Debido a que muchas apps se registran para recibir esta transmisión, un solo cambio de red puede provocar 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 corregir estos problemas, en Android 7.0 se aplican las siguientes optimizaciones:
- Las apps que se orientan a Android 7.0 (nivel de API 24) y versiones posteriores no recibirán transmisiones de
CONNECTIVITY_ACTION
si declaran su receptor de emisión en el manifiesto. Las apps seguirán recibiendo transmisiones deCONNECTIVITY_ACTION
si registran suBroadcastReceiver
conContext.registerReceiver()
, y ese contexto sigue siendo válido. - El sistema ya no envía transmisiones
ACTION_NEW_PICTURE
niACTION_NEW_VIDEO
. Esta optimización afecta a todas las apps, no solo a las orientadas a Android 7.0.
Si tu app usa alguno de estos intents, debes quitar las dependencias en ellos lo antes posible para poder orientar dispositivos con Android 7.0 de manera correcta.
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 no medida. Incluso puedes usar JobScheduler
para reaccionar a los cambios 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 la manera de 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:
-
El propietario ya no debe reducir los permisos de archivo de los archivos privados, y un intento de hacerlo con
MODE_WORLD_READABLE
oMODE_WORLD_WRITEABLE
activará unaSecurityException
.Nota: A partir de ahora, esta restricción no se aplicará plenamente. Las apps aún pueden modificar los permisos de su directorio privado mediante APIs nativas o la API de
File
. Sin embargo, no recomendamos reducir los permisos para el directorio privado. -
Cuando se pasan URI de
file://
fuera del dominio del paquete, es posible que el receptor tenga una ruta inaccesible. Por lo tanto, los intentos de pasar un URIfile://
activan unaFileUriExposedException
. La forma recomendada de compartir el contenido de un archivo privado es usarFileProvider
. -
DownloadManager
ya no puede compartir archivos almacenados de forma privada por nombre. Las aplicaciones heredadas pueden terminar con una ruta inaccesible cuando acceden aCOLUMN_LOCAL_FILENAME
. Las apps que se orientan a Android 7.0 o versiones posteriores activan unaSecurityException
cuando intentan acceder aCOLUMN_LOCAL_FILENAME
. Las aplicaciones heredadas que establecen la ubicación de descarga en una ubicación pública medianteDownloadManager.Request.setDestinationInExternalFilesDir()
oDownloadManager.Request.setDestinationInExternalPublicDir()
aún pueden acceder a la ruta de acceso enCOLUMN_LOCAL_FILENAME
. Sin embargo, no es recomendable usar este método. La forma preferida de acceder a un archivo expuesto porDownloadManager
es usarContentResolver.openFileDescriptor()
.
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 forma más fácil de otorgar este permiso es usar la clase FileProvider
. Para obtener más información sobre permisos y uso compartido de 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 baja 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 el posible impacto en la experiencia del usuario.
Zoom de la pantalla
Android 7.0 permite a los usuarios configurar el Tamaño de pantalla, 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 podrán hacer zoom en la pantalla más allá del ancho mínimo de sw320dp, que es el ancho de un Nexus 4, un teléfono común 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](https://developer.android.com/static/images/android-7.0/screen-zoom-1.png?authuser=7&hl=es)
![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](https://developer.android.com/static/images/android-7.0/screen-zoom-2.png?authuser=7&hl=es)
Figura 3: En la pantalla de la derecha, se muestra el efecto de aumentar el tamaño de visualización 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 de las siguientes maneras:
- Si una app tiene como objetivo el nivel de API 23 o uno inferior, el sistema finaliza automáticamente todos los procesos en segundo plano. Es decir, si un usuario deja de usar 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 les notificará a esos procesos sobre el cambio de configuración como se describe en Cómo controlar los cambios en el tiempo de ejecución, como si hubiera cambiado la orientación del dispositivo.
- Si una app se orienta a Android 7.0, se notifica a todos los procesos (en primer y segundo plano) el cambio en la configuración, como se describe en Cómo controlar los cambios en el tiempo de ejecución.
La mayoría de las apps no necesitan hacer cambios 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 cambie 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. Comprueba si hay cambios de 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 la 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 los siguientes parámetros de accesibilidad en un dispositivo nuevo: Gesto de ampliación, Tamaño de fuente, Tamaño de la pantalla y TalkBack. Este cambio aumenta la visibilidad de los 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 la configuración en Configuración > Accesibilidad.
Apps del NDK con vínculos a bibliotecas de plataformas
A partir de Android 7.0, el sistema impide que las apps se vinculen de forma dinámica con bibliotecas que no pertenezcan al NDK, lo que puede hacer 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 diferentes dispositivos. Si bien es posible que tu código no esté vinculado 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 con Android 7.0. Si tu app usa código nativo, solo debes usar las APIs públicas del NDK.
Existen tres maneras en las que tu app podría 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 APIs públicas del NDK.
- 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 directamente a las bibliotecas privadas, debes probarla para esta situación.
- 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 tu 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 porque 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 hay 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 considerablemente (como libandroid_runtime.so
, libcutils.so
, libcrypto.so
y libssl.so
) en Android 7.0 (nivel de API 24) para las apps orientadas al nivel de API 23 o versiones anteriores. Si tu app carga una de esas 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 por completo el uso de bibliotecas privadas 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 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 consultar 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 | 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 con la carga de 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 versiones posteriores, 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 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 mediante la ejecución del siguiente comando:
aarch64-linux-android-readelf -dW libMyLibrary.so
Actualiza la 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
ygetJNIEnv
delibandroid_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 privadoproperty_get
delibcutils.so
. Para ello, usa__system_property_get
con lo siguiente:#include <sys/system_properties.h>
Nota: La disponibilidad y el contenido de las propiedades del sistema no se prueban a través del CTS. Una mejor solución sería evitar usar estas propiedades por completo.
- Usa una versión local del símbolo
SSL_ctrl
delibcrypto.so
. Por ejemplo, debes vincularlibcyrpto.a
de forma estática en tu archivo.so
o incluir una versión delibcrypto.so
de BoringSSL/OpenSSL vinculada de forma dinámica y empaquetarla en tu APK.
Android for Work
Android 7.0 contiene cambios para apps orientadas a Android for Work, como modificaciones en la instalación de certificados, el restablecimiento de contraseñas, la administración secundaria de usuarios 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 el instalador no está instalado, el sistema arroja unIllegalArgumentException
. - 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. Aun así, 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 Account Management incluso si se aplican restricciones de usuario
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, se establece automáticamente la restricción
DISALLOW_ADD_USER
. Esto evita que los usuarios creen usuarios secundarios no administrados. Además, los métodosCreateUser()
ycreateAndInitializeUser()
dejaron de estar disponibles; los reemplaza el nuevo métodoDevicePolicyManager.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 a través de
DevicePolicyManager.getWifiMacAddress()
. Si nunca se habilitó la conexión Wi-Fi en el dispositivo, este método muestra un valor denull
. - La configuración Work Mode controla el acceso a las apps de trabajo. Cuando este modo está desactivado, el selector del sistema indica que las apps de trabajo no están disponibles atenuándolas. Si vuelves a habilitar el modo de trabajo, 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 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 del cliente más tarde. Si es necesario, se debe instalar el certificado de la AC en el almacenamiento de credenciales de confianza a través de la IU de configuración por separado, con un formato codificado en DER con 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 configurar 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 si va a Configuración > Seguridad > Seguridad del perfil de trabajo.
DevicePolicyManager.getStorageEncryptionStatus()
muestra un nuevo estado de encriptaciónENCRYPTION_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 muestraENCRYPTION_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 independiente. En lugar de afectar a todo el dispositivo, estos métodos se aplican solo al perfil de trabajo. (La lista completa de estos 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 anterior llamando al método en la instancia superior deDevicePolicyManager
; para obtener este superior, llamando aDevicePolicyManager.getParentProfileInstance()
. Por ejemplo, si llamas al métodolockNow()
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 acceder. Entre estas anotaciones, se incluyen las siguientes:
VISIBILITY_BUILD
: Diseñada para ser visible solo en el tiempo de compilación.VISIBILITY_SYSTEM
: destinada a 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 a las anotaciones que deben estar disponibles durante 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 fallen en la conectividad HTTPS o TLS/SSL cuando el servidor no negocia conjuntos de cifrado modernos. La solución preferida es mejorar la configuración del servidor para habilitar conjuntos y protocolos de cifrado más sólidos y modernos. Lo ideal es que se habiliten TLSv1.2 y AES-GCM, así como que se habiliten los conjuntos de cifrado de confidencialidad directa (ECDHE) y se prefieran.
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 de 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 están relacionados con WebView
.
Apps orientadas a Android 7.0
Estos cambios de 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 configuran targetSdkVersion
en Android 7.0 o versiones posteriores deben modificarlas para que admitan correctamente estos comportamientos, cuando corresponda.
Cambios en la serialización
Android 7.0 (nivel de API 24) corrigió un error en el cálculo del serialVersionUID predeterminado por 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 al intentar 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, 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 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 inicialización estáticos, es decir, <clinit>
. Según la especificación, la presencia o ausencia de un método de inicialización 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.
A modo de aclaración, este cambio no afecta a las apps orientadas al nivel de API 23 o versiones anteriores, a las clases que tienen un campo serialVersionUID
ni 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 se orienta a un nivel de API inferior, y el usuario cambia el tamaño de visualización, el proceso de la app finaliza. La app debe tener capacidad para 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. Para ello, causa una falla idéntica cuando finalizas 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 debido a los cambios de densidad. Sin embargo, es posible que respondan de manera deficiente a los cambios de configuración.
- En Android 7.0, las apps deben poder 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 en un socket TCP en el subproceso principal como una infracción de modo estricto. Android 7.0 resuelve este error.
Las apps que muestran este comportamiento ahora arrojan un
android.os.NetworkOnMainThreadException
. En general, no es recomendable realizar operaciones de red en el subproceso principal, ya que estas operaciones suelen tener una latencia alta que provoca ANR y bloqueos. -
La familia de métodos
Debug.startMethodTracing()
ahora almacena de forma predeterminada 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 permisoWRITE_EXTERNAL_STORAGE
para usar estas APIs. -
Muchas APIs de plataforma comenzaron a verificar si hay cargas útiles grandes que se envíen a través de transacciones
Binder
, y el sistema ahora vuelve a arrojarTransactionTooLargeExceptions
comoRuntimeExceptions
, en lugar de registrarlas o suprimirlas silenciosamente. Un ejemplo común es almacenar demasiados datos enActivity.onSaveInstanceState()
, lo que hace queActivityThread.StopInfo
arroje unaRuntimeException
cuando tu app se orienta a Android 7.0. -
Si una app publica tareas
Runnable
en unaView
yView
no está adjunta a una ventana, el sistema pone en cola la tareaRunnable
con elView
; la tareaRunnable
no se ejecutará hasta queView
esté adjunta a una ventana. Este comportamiento corrige los siguientes errores: -
Si una app en Android 7.0 con el permiso
DELETE_PACKAGES
intenta borrar un paquete, pero otra app lo instaló, el sistema requiere la confirmación del usuario. En este caso, las apps deberían esperar que el estado que se muestra seaSTATUS_PENDING_USER_ACTION
cuando invoquen aPackageInstaller.uninstall()
. - El proveedor de JCA llamado Crypto está obsoleto porque su único algoritmo, SHA1PRNG, es débil desde el punto de vista criptográfico. 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 sobre el proveedor de seguridad "Crypto" que dejó de estar disponible en Android N.