Cambios de comportamiento en Android 5.0

Video

Dev Byte: novedades de Android 5.0

Video

Dev Byte: notificaciones

Nivel de API: 21

Además de nuevas funciones y capacidades, Android 5.0 incorpora varios cambios en el comportamiento del sistema y de la API. En este documento, se destacan algunos de los cambios claves que debes comprender y contemplar en tus apps.

Si publicaste anteriormente una app para Android, ten en cuenta que esta podría verse afectada por los cambios de Android 5.0.

Para ver en mayor profundidad las nuevas funciones de la plataforma, como alternativa consulta las Funciones destacadas de Android Lollipop.

Tiempo de ejecución de Android (ART)

En Android 5.0, el tiempo de ejecución ART reemplaza a Dalvik como la configuración predeterminada de la plataforma. El tiempo de ejecución ART se incorporó en Android 4.4 de forma experimental.

Para obtener información general sobre las nuevas funciones de ART, consulta Introducción a ART. Algunas de las principales funciones nuevas son las siguientes:

  • compilación por adelantado (AOT);
  • mejor recolección de elementos no usados (GC);
  • mayor compatibilidad de depuración.

La mayoría de las apps de Android deben funcionar en ART sin necesidad de realizar cambios. Sin embargo, algunas técnicas que funcionan en Dalvik no sirven en ART. Para obtener información sobre los problemas más importantes, consulta Verificación del comportamiento de la app en el tiempo de ejecución de Android (ART). Presta especial atención en los siguientes casos:

  • Si en tu app se usa la interfaz nativa Java (JNI) para ejecutar el código C/C++.
  • Si usas herramientas de programación que generan un código no estándar (por ejemplo, algunos ofuscadores).
  • Si usas técnicas incompatibles con la compactación de la recolección de elementos no usados.

Notificaciones

Asegúrate de que en tus notificaciones se tengan en cuenta estos cambios de Android 5.0. Para obtener más información sobre cómo diseñar tus notificaciones para Android 5.0 y versiones posteriores, consulta la guía de diseño de notificaciones.

Estilo de material design

Las notificaciones se crean con texto oscuro sobre fondos blancos (o de un tono muy suave) para que coincidan con los nuevos widgets de material design. Asegúrate de que todas tus notificaciones se visualicen de manera adecuada con el nuevo esquema de colores. Si tus notificaciones no tienen el aspecto correcto, corrígelas:

  • Usa setColor() para establecer un color de acento en un círculo detrás de la imagen del ícono.
  • Actualiza o quita los recursos que incluyen color. El sistema ignora todos los canales que no sean alfa en los íconos de acción y el ícono de notificación principal. Debes suponer que estos íconos serán solo alfa. El sistema dibuja los íconos de notificación en blanco y los de acción en gris oscuro.

Sonido y vibración

Si actualmente agregas sonidos y vibraciones a tus notificaciones usando las clases Ringtone, MediaPlayer o Vibrator, quita este código de modo que el sistema pueda presentar las notificaciones correctamente en el modo de prioridad. Como alternativa, usa métodos Notification.Builder para agregar sonidos y vibración.

Si se configura el dispositivo en RINGER_MODE_SILENT, este ingresa en el nuevo modo de prioridad. El dispositivo abandona el modo de prioridad si lo configuras en RINGER_MODE_NORMAL o RINGER_MODE_VIBRATE.

Anteriormente, en Android se usaba STREAM_MUSIC como flujo maestro para controlar el nivel de volumen en tablets. En Android 5.0, el flujo de volumen maestro para teléfonos y tablets ahora está unificado y se controla a través de STREAM_RING o STREAM_NOTIFICATION.

Visibilidad de la pantalla bloqueada

De manera predeterminada, las notificaciones ahora aparecen en la pantalla bloqueada del usuario en Android 5.0. Los usuarios pueden optar por proteger la información confidencial contra la exposición, en cuyo caso el sistema automáticamente redacta el texto que aparece en la notificación. Para personalizar esta notificación redactada, usa setPublicVersion().

Si la notificación no contiene información personal o si deseas activar el control de reproducción multimedia de la notificación, llama al método setVisibility() y configura el nivel de visibilidad de la notificación en VISIBILITY_PUBLIC.

Reproducción de medios

Si implementas notificaciones que presentan controles de transporte o estado de reproducción multimedia, analiza la posibilidad de usar la nueva plantilla Notification.MediaStyle en lugar de un objeto RemoteViews.RemoteView personalizado. Independientemente del enfoque que elijas, asegúrate de configurar la visibilidad de la notificación en VISIBILITY_PUBLIC de modo que puedas acceder a tus controles desde la pantalla bloqueada. Ten en cuenta que, a partir de Android 5.0, el sistema ya no muestra objetos RemoteControlClient en la pantalla bloqueada. Para obtener más información, consulta Si tu app usa RemoteControlClient.

Notificación emergente

Ahora las notificaciones pueden aparecer en una ventana flotante pequeña (también llamada “notificación emergente”) cuando el dispositivo está activo (es decir, cuando está desbloqueado y su pantalla está encendida). Estas notificaciones tienen una apariencia similar a la forma compacta de tu notificación, con la excepción de que en la notificación emergente también se muestran los botones de acción. Los usuarios pueden actuar conforme a una notificación emergente o descartarla sin salir de la app actual.

Entre los ejemplos de condiciones que pueden activar notificaciones emergentes se incluyen los siguientes:

  • La actividad del usuario se encuentra en el modo de pantalla completa (la app usa fullScreenIntent).
  • La notificación tiene prioridad alta y usa tonos o vibración.

Si en tu app se implementan notificaciones en alguno de estas condiciones, asegúrate de que las notificaciones emergentes se presenten de manera correcta.

Controles multimedia y RemoteControlClient

La clase RemoteControlClient ya no está disponible. Realiza un cambio a la nueva MediaSession API lo más pronto posible.

En las pantallas bloqueadas de dispositivos con Android 5.0, no se muestran los controles de transporte para tu clase MediaSession ni RemoteControlClient. Como alternativa, tu app puede ofrecer control de reproducción multimedia desde la pantalla bloqueada por medio de una notificación. De esta manera, tu app tiene más control sobre la presentación de los botones multimedia y, a su vez, se proporciona una experiencia coherente para los usuarios en dispositivos bloqueados y desbloqueados.

En Android 5.0 se presenta una nueva plantilla Notification.MediaStyle para este propósito. Notification.MediaStyle convierte las acciones de notificación que agregaste con Notification.Builder.addAction() en botones compactos incorporados en las notificaciones de reproducción multimedia de tu app. Pasa tu token de sesión al método setSession() para informar al sistema que esta notificación controla una sesión multimedia en curso.

Asegúrate de configurar la visibilidad de la notificación en VISIBILITY_PUBLIC a fin de marcarla como segura para la visualización en cualquier pantalla bloqueada (segura o de otras características). Para obtener más información, consulta Notificaciones en la pantalla bloqueada.

Para mostrar los controles de reproducción multimedia si tu app se encuentra en ejecución en la plataforma Android TV o Wear, implementa la clase MediaSession. Además, debes implementar MediaSession si tu app debe recibir eventos de botones multimedia en dispositivos Android.

getRecentTasks()

Con la introducción de la nueva función de tareas de documentos y actividades concurrentes en Android 5.0 (consulta Documentos y actividades concurrentes en la pantalla de recientes a continuación), el método ActivityManager.getRecentTasks() ya no está disponible para mejorar la privacidad del usuario. Para ofrecer compatibilidad con versiones anteriores, este método muestra un pequeño subconjunto de datos, incluidas las tareas propias de la aplicación que realiza la llamada y posiblemente algunas otras tareas no confidenciales (por ejemplo, la Página principal). Si tu app usa este método para recuperar sus propias tareas, usa getAppTasks() en su lugar para obtener esa información.

Compatibilidad con sistemas de 64 bits en el NDK de Android

Android 5.0 presenta compatibilidad con sistemas de 64 bits. Esta mejora aumenta el espacio de direcciones y mejora el rendimiento. Al mismo tiempo, mantiene la compatibilidad absoluta con las apps de 32 bits existentes. La compatibilidad con sistemas de 64 bits también mejora el rendimiento de OpenSSL para la criptografía. Además, esta versión presenta nuevas NDK API de medios nativas y también compatibilidad nativa con OpenGL ES (GLES) 3.1.

Para aprovechar la compatibilidad que Android 5.0 ofrece con la arquitectura 64 bits, descarga e instala la revisión 10c del NDK desde la página del NDK de Android. Consulta las notas de la versión de la revisión 10c para obtener más información sobre los cambios y las correcciones de errores importantes en el NDK.

Enlace con un servicio

El método Context.bindService() ahora requiere un elemento Intent explícito y genera una excepción si existe una intent implícita. Para garantizar que tu app sea segura, usa una intent explícita cuando inicies o enlaces tu Service y no declares filtros de intents para el servicio.

WebView

Android 5.0 cambia el comportamiento predeterminado de tu app.

  • Si tu app está orientada hacia el nivel de API 21 o un nivel superior:
    • El sistema bloquea el contenido mixto y las cookies de terceros de manera predeterminada. Para permitir contenido mixto y cookies de terceros, usa los métodos setMixedContentMode() y setAcceptThirdPartyCookies(), respectivamente.
    • El sistema ahora elige de manera inteligente partes del documento HTML para dibujar. Este nuevo comportamiento predeterminado ayuda a reducir la superficie de memoria y aumentar el rendimiento. Si deseas representar todo el documento de una vez, inhabilita esta optimización llamando a enableSlowWholeDocumentDraw().
  • Si tu app está orientada hacia niveles de API inferiores al 21: el sistema permite contenido mixto y cookies de terceros, y siempre representa todo el documento de una vez.

Requisito de singularidad para los permisos personalizados

Como se documenta en la descripción general Permisos, las apps de Android pueden definir permisos personalizados como medio para administrar el acceso a los componentes de manera privada, sin usar los permisos predefinidos del sistema de la plataforma. Las apps definen permisos personalizados en elementos <permission> que se declaran en los archivos de manifiesto de estas.

Existe una cantidad reducida de situaciones en las cuales la definición de permisos personalizados es un enfoque legítimo y seguro. Sin embargo, la creación de estos permisos a veces es innecesaria e incluso puede introducir posibles riesgos para una app, según el nivel de protección asignado a los permisos.

En Android 5.0 se incluye un cambio de comportamiento para garantizar que solo una app pueda definir un permiso personalizado determinado, a menos que esté firmada con la misma clave que otras apps que definen el permiso.

Apps que usan permisos personalizados duplicados

Cualquier app puede definir el permiso personalizado que desee. Por ello, puede suceder que varias apps definan el mismo permiso personalizado. Por ejemplo, si dos apps ofrecen una capacidad similar, es posible que asignen el mismo nombre lógico para sus permisos personalizados. Las apps también pueden incorporar bibliotecas públicas o ejemplos de códigos comunes que incluyan las mismas definiciones de permisos personalizados.

En Android 4.4 y versiones anteriores, los usuarios podían instalar varias apps de ese tipo en un dispositivo determinado, si bien el sistema asignaba el nivel de protección especificado por la app que se instalaba en primer lugar.

A partir de Android 5.0, el sistema aplica una nueva restricción de singularidad en lo que respecta a los permisos personalizados para las apps firmadas con claves diferentes. Ahora solo una app en un dispositivo puede definir un permiso personalizado determinado (como lo indica su nombre), a menos que la otra app que define el permiso esté firmada con la misma clave. Si el usuario intenta instalar una app con un permiso personalizado duplicado y esta no está firmada con la misma clave que la app residente que define el permiso, el sistema bloquea la instalación.

Consideraciones sobre tu app

En Android 5.0 y versiones posteriores, las apps pueden continuar definiendo sus propios permisos personalizados como lo hacían antes y solicitando permisos personalizados de otras apps por medio del mecanismo <uses-permission>. Sin embargo, con el nuevo requisito incorporado en Android 5.0, debes evaluar cuidadosamente el posible impacto en tu app.

A continuación se muestran algunos aspectos que deben tenerse en cuenta:

  • ¿Tu app declara algún elemento <permission> en su manifiesto? De ser así, ¿son realmente necesarios para el funcionamiento correcto de tu app o servicio? ¿Podrías usar un permiso predeterminado del sistema en su lugar?
  • Si cuentas con elementos <permission> en tu app, ¿sabes de dónde provienen?
  • ¿Realmente deseas que otras apps soliciten tus permisos personalizados mediante <uses-permission>?
  • ¿En tu app usas código estándar o de ejemplo en el que se incluyen elementos <permission>? ¿Son realmente necesarios esos elementos de permiso?
  • ¿Tus permisos personalizados usan nombres que son simples o se basan en términos comunes que otras apps podrían compartir?

Nuevas instalaciones y actualizaciones

Como se mencionó anteriormente, en el caso de las nuevas instalaciones y actualizaciones de tu app, los dispositivos que tienen instalado Android 4.4 o una versión anterior no se ven afectados, y no existen cambios en el comportamiento. En el caso de las instalaciones y actualizaciones nuevas en dispositivos que tienen instalado Android 5.0 o una versión posterior, el sistema bloquea la instalación de tu app si esta define un permiso personalizado que ya está definido por una app residente en existencia.

Instalaciones existentes con actualización de sistema a Android 5.0

Si tu app utiliza permisos personalizados y se distribuye e instala con mucha frecuencia, es posible que se vea afectada cuando los usuarios deban actualizar sus dispositivos a Android 5.0. Luego de instalar la actualización del sistema, este revalida las apps instaladas, incluida una revisión de los permisos personalizados. Si tu app define un permiso personalizado ya definido por otra app que ya se validó, y tu app no está firmada con la misma clave que la otra, el sistema no vuelve a instalar tu app.

Recomendaciones

En dispositivos que tengan instalado Android 5.0 o versiones posteriores, te recomendamos examinar tu app de inmediato, hacer cualquier ajuste que sea necesario y publicar la versión actualizada para los usuarios cuanto antes.

  • Si usas permisos personalizados en tu app, analiza el origen de estos y si los necesitas realmente. Quita todos los elementos <permission> de tu app, a menos que estés seguro de que sean necesarios para el correcto funcionamiento de la app.
  • Analiza la posibilidad de reemplazar tus permisos personalizados por los predeterminados del sistema cuando sea posible.
  • Si tu app requiere permisos personalizados, cámbiales el nombre para que sean exclusivos de tu app; por ejemplo, anéxalos al nombre completo del paquete de tu app.
  • Si tienes un conjunto de apps firmadas con diferentes claves y estas acceden a un componente compartido mediante un permiso personalizado, asegúrate de que dicho permiso solo esté definido una vez, en este componente. Las apps que usan el componente compartido no deben definir el permiso personalizado por sí mismas, sino que deben solicitar acceso a través del mecanismo <uses-permission>.
  • Si tienes un conjunto de apps que están firmadas con la misma clave, cada una de ellas puede definir el mismo permiso personalizado según sea necesario: el sistema permite instalar las apps de la forma convencional.

Cambios en la configuración predeterminada de TLS/SSL

Android 5.0 presenta cambios en la configuración TLS/SSL predeterminada que usan las apps para el tráfico HTTPS y otro tráfico TLS/SSL:

  • Los protocolos TLSv1.2 y TLSv1.1 ahora están habilitados.
  • Los conjuntos de cifrado AES-GCM (AEAD) ahora están habilitados.
  • Los conjuntos de cifrado MD5, 3DES, de exportación y ECDH de llave estática ahora están inhabilitados.
  • Se prefiere el uso de conjuntos de cifrado de confidencialidad directa (ECDHE y DHE).

Estos cambios pueden producir interrupciones en la conectividad HTTPS o TLS/SSL en una cantidad reducida de casos que se indican a continuación.

Ten en cuenta que el proveedor de seguridad ProviderInstaller de los servicios de Google Play ya ofrece estos cambios en diferentes versiones de la plataforma Android hasta Android 2.3.

El servidor no admite ninguno de los conjuntos de cifrado habilitados

Por ejemplo, es posible que un servidor solo sea compatible con los conjuntos de cifrado 3DES o MD5. La solución preferida es mejorar la configuración del servidor para habilitar protocolos y conjuntos 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, DHE), que son los preferidos.

Una alternativa es modificar la app de modo que use una clase SSLSocketFactory personalizada 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.

La app hace predicciones incorrectas respecto de los conjuntos de cifrado empleados para conectarse al servidor

Por ejemplo, algunas apps contienen una interfaz X509TrustManager personalizada que se daña porque espera que el parámetro authType sea RSA, pero encuentra ECDHE_RSA o DHE_RSA.

El servidor no admite TLSv1.1, TLSv1.2 ni extensiones TLS nuevas

Por ejemplo, el protocolo de enlace TLS/SSL con un servidor se rechaza por error o se bloquea. La solución preferida es actualizar el servidor para que cumpla con el protocolo TLS/SSL. De esta manera, el servidor negociará exitosamente estos protocolos más nuevos, o bien TLSv1 o protocolos anteriores, e ignorará las extensiones TLS que no comprenda. En algunos casos, la inhabilitación de TLSv1.1 y TLSv1.2 en el servidor puede funcionar como medida temporal hasta que se actualice el software del servidor.

Una alternativa es modificar la app de modo que use una clase SSLSocketFactory personalizada para comunicarse con el servidor. La fábrica debe diseñarse para crear instancias de SSLSocket que tengan habilitados solo esos protocolos que el servidor admite correctamente.

Compatibilidad con perfiles administrados

Los administradores de dispositivos pueden agregar un perfil administrado a un dispositivo. Este perfil es propiedad del administrador; por lo tanto, este último tiene el control de dicho perfil y al mismo tiempo permite que el usuario controle su perfil personal y el espacio de almacenamiento. Este cambio puede afectar el comportamiento de tu app existente de las siguientes maneras.

Administración de intents

Los administradores de dispositivos pueden restringir el acceso a las aplicaciones del sistema desde el perfil administrado. En este caso, si una app activa una intent desde el perfil administrado que normalmente sería controlado por dicha aplicación, y no hay un controlador adecuado para la intent en dicho perfil, la intent genera una excepción. Por ejemplo, el administrador del dispositivo puede restringir las apps en el perfil administrado para evitar que accedan a la aplicación de la cámara del sistema. Si tu app se ejecuta en el perfil administrado y llama a startActivityForResult() para MediaStore.ACTION_IMAGE_CAPTURE, y no hay ninguna app en dicho perfil que pueda controlar la intent, se genera una excepción ActivityNotFoundException.

Para evitar esto, asegúrate de que haya al menos un controlador para cualquier intent antes de activarla. Para buscar un controlador válido, llama a Intent.resolveActivity(). Para ver un ejemplo sobre este proceso, consulta Tomar fotos fácilmente: tomar una foto con la app de cámara.

Cómo compartir archivos entre perfiles

Cada perfil cuenta con su propio almacenamiento de archivos. Debido a que el URI de un archivo hace referencia a la ubicación específica en el almacenamiento de archivos, significa que el URI de un archivo que es válido en un perfil no lo es en el otro perfil. Por lo general, esto no representa un problema para una app, que normalmente solo accede a los archivos que crea. Sin embargo, si una app adjunta un archivo a una intent, no es seguro adjuntar el URI de un archivo, ya que en algunas circunstancias la intent puede controlarse en el otro perfil. Por ejemplo, en el administrador de un dispositivo se puede especificar que los eventos de captura de imágenes deben ser controlados por la app de cámara en el perfil personal. Si una app del perfil administrado desencadena la intent, la cámara debe poder escribir la imagen en una ubicación en la cual las apps del perfil administrado puedan leer dicha imagen.

Para tu seguridad, cuando necesites adjuntar un archivo a una intent que podría ir de un perfil al otro, deberás crear y usar un URI de contenido para el archivo. Para obtener más información sobre cómo compartir archivos con URI de contenido, consulta Cómo compartir archivos. Por ejemplo, el administrador del dispositivo puede incluir la cadena ACTION_IMAGE_CAPTURE en la lista blanca para que se controle a través de la cámara en el perfil personal. La cadena EXTRA_OUTPUT de la intent que se activa debe contar con un URI de contenido en el cual se especifique el lugar en el que se almacenará la fotografía. La app de cámara puede escribir la imagen en la ubicación especificada por ese URI, y la app que desencadenó la intent podría leer ese archivo, incluso si la app se encuentra en el otro perfil.

Eliminación de la compatibilidad con widgets de pantalla bloqueada

En Android 5.0 desaparece la compatibilidad con widgets de pantalla bloqueada, aunque aún se ofrece compatibilidad con widgets en la pantalla principal.