Actualizaciones de almacenamiento en Android 11

Android 11 mejora aún más la plataforma, ya que brinda mayor protección a los datos de las apps y del usuario en el almacenamiento externo. La versión preliminar incluye varias mejoras que se presentaron el año pasado en Android Dev Summit, como la posibilidad de habilitar el acceso de ruta de archivos sin procesar para contenido multimedia, operaciones de edición por lotes para contenido multimedia y una IU actualizada para marco de trabajo de acceso al almacenamiento.

A fin de facilitar la transición al uso del almacenamiento específico, la plataforma les ofrece mejoras adicionales a los desarrolladores. Para obtener más información sobre cómo comenzar a usar el almacenamiento específico según los casos prácticos de tu app, consulta la sección almacenamiento específico de esta página, además de la guía de casos prácticos y prácticas recomendadas de almacenamiento en Android..

Como siempre, te invitamos a enviar comentarios para ayudar a dar forma a la próxima versión de Android. Usa la herramienta de seguimiento de errores para enviarnos tus comentarios.

Nos interesan tus comentarios. Responde esta breve encuesta para contarnos cómo utilizas la función. En concreto, queremos conocer casos prácticos afectados por esta función.

Aplicación de almacenamiento específico

A fin de que los desarrolladores tengan tiempo adicional para realizar pruebas, las aplicaciones orientadas a Android 10 (API nivel 29) aún pueden solicitar el atributo requestLegacyExternalStorage. Esta función experimental permite que las aplicaciones inhabiliten temporalmente los cambios asociados con el almacenamiento específico, como otorgar acceso a diferentes directorios y a distintos tipos de archivos multimedia. Después de que actualizas la aplicación para que se oriente a Android 11, el sistema ignora la marca requestLegacyExternalStorage.

Cómo mantener la compatibilidad con Android 10

Si tu app inhabilita el almacenamiento específico cuando se ejecuta en dispositivos Android 10, se recomienda que configures requestLegacyExternalStorage como true en el archivo de manifiesto de tu app. De esta manera, tu app puede seguir comportándose como se espera en los dispositivos que ejecutan Android 10.

Cómo migrar datos a directorios visibles cuando uses el almacenamiento específico

Si tu app usa el modelo de almacenamiento heredado y antes estaba orientada a Android 10 o versiones anteriores, es posible que estés almacenando datos en un directorio al que tu app no puede acceder cuando se habilita el modelo de almacenamiento específico. Antes de orientarla a Android 11, migra los datos a un directorio que sea compatible con el almacenamiento específico. En la mayoría de los casos, puedes migrar datos al directorio específico de tu app.

Si tienes datos para migrar, es posible conservar el modelo de almacenamiento heredado cuando un usuario actualiza a la nueva versión de tu app orientada a Android 11. De esta manera, el usuario retiene el acceso a los datos de app que se almacenan en los directorios donde tu app había guardado los datos. Si deseas habilitar el modelo de almacenamiento heredado para una actualización, establece el atributo preserveLegacyExternalStorage como true en el manifiesto de tu app.

Nota: La mayoría de las apps no deberían tener que usar preserveLegacyExternalStorage. Esta marca está diseñada solo para los casos en que migraste datos de apps a una ubicación compatible con almacenamiento específico y quieres que los usuarios conserven el acceso a los datos cuando actualices tu app. Cuando usas esta marca, es más difícil probar cómo afecta el almacenamiento específico a los usuarios de tu app, ya que, cuando ellos la actualizan, esta continúa usando el modelo de almacenamiento heredado.

Si usas preserveLegacyExternalStorage, el modelo de almacenamiento heredado permanecerá vigente solo hasta que el usuario desinstale tu app. Si el usuario instala o reinstala tu app en un dispositivo que ejecuta Android 11, tu app no podrá inhabilitar el modelo de almacenamiento específico, independientemente del valor de preserveLegacyExternalStorage.

Cómo comprobar el almacenamiento específico

Para habilitar el almacenamiento específico en tu app, independientemente de los valores de la marca de manifiesto y la versión del SDK de destino de la app, habilita las siguientes marcas de compatibilidad de apps:

Para inhabilitar el almacenamiento específico y usar el modelo de almacenamiento heredado, desactiva ambas marcas.

Cómo administrar el almacenamiento del dispositivo

En Android 11, las apps que usan el modelo de almacenamiento específico solo pueden acceder a los archivos de caché específicos de la app. Si tu app debe administrar el almacenamiento del dispositivo, haz lo siguiente:

  1. Para comprobar el espacio libre, invoca la acción de intent ACTION_MANAGE_STORAGE.
  2. Si no hay suficiente espacio libre en el dispositivo, pídele al usuario que dé su consentimiento para borrar todas las cachés. Para ello, invoca la acción de intent ACTION_CLEAR_APP_CACHE.

Directorio específico de la app en el almacenamiento externo

En Android 11, las apps no pueden crear su propio directorio específico de la app en el almacenamiento externo. Para acceder al directorio que proporciona el sistema a tu app, llama al método getExternalFilesDirs().

Acceso a archivos multimedia

Para facilitar el acceso al contenido sin perder la privacidad del usuario, en Android 11 se agregaron las siguientes funciones.

Cómo realizar operaciones por lotes

Para garantizar la coherencia en todos los dispositivos y aumentar la comodidad del usuario, en Android 11 se agregaron varios métodos a la API de MediaStore. Esos métodos son particularmente útiles para las apps que necesitan un flujo optimizado a fin de modificar archivos multimedia específicos, como editar una foto en el lugar.

Los métodos que se agregaron son los siguientes:

createWriteRequest()
Solicita al usuario que otorgue acceso de escritura a la app para el grupo especificado de archivos multimedia.
createFavoriteRequest()
Solicita al usuario que marque los archivos multimedia especificados como algunos de sus archivos multimedia "favoritos" en el dispositivo. Cualquier app que tenga acceso de lectura a este archivo podrá ver que el usuario marcó el archivo como "favorito".
createTrashRequest()

Solicita al usuario que coloque los archivos multimedia especificados en la papelera del dispositivo. Se borran de forma permanente los elementos de la papelera después de un período definido por el sistema.

createDeleteRequest()

Solicita al usuario que borre de forma permanente e inmediata los archivos multimedia especificados, sin colocarlos antes en la papelera.

Después de llamar a cualquiera de estos métodos, el sistema compila un objeto PendingIntent. Una vez que tu app invoca este intent, los usuarios ven un diálogo que solicita su consentimiento para que tu app actualice o borre los archivos multimedia especificados.

Por ejemplo, aquí se muestra cómo estructurar una llamada a createWriteRequest():

Kotlin

val urisToModify = /* A collection of content URIs to modify. */
val editPendingIntent = MediaStore.createWriteRequest(contentResolver,
        urisToModify)

// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
    null, 0, 0, 0)

Java

List<Uri> urisToModify = /* A collection of content URIs to modify. */
PendingIntent editPendingIntent = MediaStore.createWriteRequest(contentResolver,
                  urisToModify);

// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.getIntentSender(),
    EDIT_REQUEST_CODE, null, 0, 0, 0);

Evalúa la respuesta del usuario y, si no dio su consentimiento, explícale por qué tu app necesita el permiso:

Kotlin

override fun onActivityResult(requestCode: Int, resultCode: Int,
                 data: Intent?) {
    ...
    when (requestCode) {
        EDIT_REQUEST_CODE ->
            if (resultCode == Activity.RESULT_OK) {
                /* Edit request granted; proceed. */
            } else {
                /* Edit request not granted; explain to the user. */
            }
    }
}

Java

@Override
protected void onActivityResult(int requestCode, int resultCode,
                   @Nullable Intent data) {
    ...
    if (requestCode == EDIT_REQUEST_CODE) {
        if (resultCode == Activity.RESULT_OK) {
            /* Edit request granted; proceed. */
        } else {
            /* Edit request not granted; explain to the user. */
        }
    }
}

Puedes usar este mismo patrón general con createFavoriteRequest(), createTrashRequest() y createDeleteRequest().

Cómo acceder a archivos mediante rutas de archivos directas y bibliotecas nativas

Para que tu app funcione sin problemas con bibliotecas multimedia de terceros, Android 11 te permite acceder a los archivos multimedia atribuidos a tu app de las siguientes dos maneras:

  • La API File.
  • Bibliotecas nativas, como fopen().

Si tu app tiene el permiso READ_EXTERNAL_STORAGE, puede acceder a todos los archivos multimedia, independientemente de si se atribuyeron a tu app.

Si accedes a los archivos multimedia con la API File o las bibliotecas nativas, te recomendamos inhabilitar el almacenamiento específico configurando requestLegacyExternalStorage como true en el archivo de manifiesto de tu app. De esa manera, tu app se comportará de la forma esperada en los dispositivos que ejecutan Android 10.

Cómo acceder a directorios privados de otras apps

En Android 11, las apps ya no pueden acceder a los archivos en cualquier directorio dedicado y específico de la app dentro del almacenamiento externo.

Restricciones de acceso a documentos

Para que los desarrolladores puedan realizar pruebas, solo se aplican los siguientes cambios relacionados con el marco de trabajo de acceso al almacenamiento (SAF) si tu app está orientada a Android 11.

Cómo acceder a directorios

Ya no puedes usar la acción del intent ACTION_OPEN_DOCUMENT_TREE para solicitar acceso a los siguientes directorios:

  • El directorio raíz del volumen de almacenamiento interno
  • El directorio raíz de cada volumen de la tarjeta SD que el fabricante del dispositivo considera confiable, sin importar si la tarjeta está emulada o es extraíble. Un volumen confiable es aquel al que una app puede acceder correctamente la mayor parte del tiempo.
  • El directorio Download.

Cómo acceder a archivos

Ya no puedes usar la acción del intent ACTION_OPEN_DOCUMENT_TREE o ACTION_OPEN_DOCUMENT para solicitar al usuario que seleccione archivos individuales de los siguientes directorios:

  • El directorio Android/data/ y todos los subdirectorios.
  • El directorio Android/obb/ y todos los subdirectorios.

Cómo probar el cambio

Para probar este cambio de comportamiento, haz lo siguiente:

  1. Invoca un intent con la acción ACTION_OPEN_DOCUMENT. Comprueba que no aparezcan los directorios Android/data/ y Android/obb/.
  2. Realiza alguna de las siguientes acciones:
  3. Invoca un intent con la acción ACTION_OPEN_DOCUMENT_TREE. Verifica que aparezca el directorio Download y que esté inhabilitado el botón de acción asociado con el directorio.

Permisos

Android 11 incluye los siguientes cambios relacionados con los permisos de almacenamiento.

Orientación a cualquier versión

El primer diálogo presenta un vínculo llamado Permitir en la configuración
Figura 1: Se muestra un diálogo cuando una app usa almacenamiento específico y solicita el permiso READ_EXTERNAL_STORAGE

Los siguientes cambios entran en vigor en Android 11, independientemente de la versión del SDK de destino de tu app:

  • Se cambió el nombre del permiso de tiempo de ejecución de Almacenamiento a Archivos y contenido multimedia.
  • Si tu app no inhabilitó el almacenamiento específico y solicitó el permiso READ_EXTERNAL_STORAGE, los usuarios verán un cuadro de diálogo diferente al de Android 10. El cuadro de diálogo indica que tu app solicita acceso a fotos y contenido multimedia, como se muestra en la figura 1.

    Los usuarios pueden ver qué apps tienen el permiso READ_EXTERNAL_STORAGE en la configuración del sistema. En la página Configuración > Privacidad > Administrador de permisos > Archivos y contenido multimedia, cada app que tiene el permiso aparece en Se permite para todos los archivos.

    Nota: Si tu app está orientada a Android 11, ten en cuenta que este acceso a "todos los archivos" es de solo lectura. Para leer y escribir en todos los archivos del almacenamiento compartido con esta aplicación, debes tener el permiso de acceso a todos los archivos.

Orientación a Android 11

Si tu app está orientada a Android 11, ni el permiso WRITE_EXTERNAL_STORAGE ni el permiso con privilegios WRITE_MEDIA_STORAGE otorgan acceso adicional.

Ten en cuenta que, en dispositivos que ejecutan Android 10 (API nivel 29) o versiones posteriores, tu app puede contribuir a colecciones de contenido multimedia bien definidas, como MediaStore.Downloads, sin solicitar permisos relacionados con el almacenamiento. Obtén más información sobre cómo solicitar solamente los permisos necesarios cuando trabajas con archivos multimedia en tu app.

Cómo acceder a todos los archivos

Algunas apps tienen un caso de uso principal que requiere acceso amplio a los archivos, como la administración de archivos o las operaciones de copia de seguridad y restablecimiento. Para obtener el permiso Acceso a todos los archivos, haz lo siguiente:

  1. Declara el permiso MANAGE_EXTERNAL_STORAGE.
  2. Usa la acción de intent ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION a fin de direccionar a los usuarios a una página de configuración del sistema en la que puedan habilitar la siguiente opción para tu app: Permitir administrar todos los archivos.

Para determinar si tu app recibió el permiso de acceso a todos los archivos, llama a Environment.isExternalStorageManager().

El permiso Acceso a todos los archivos concede lo siguiente:

  • Acceso de lectura y escritura a todos los archivos dentro del almacenamiento compartido.

  • Acceso al contenido de la tabla MediaStore.Files.

  • Acceso al directorio raíz de la unidad USB sobre la marcha (OTG) y la tarjeta SD.

  • Acceso de escritura a todos los directorios de almacenamiento interno⁠, excepto /Android/data/, /sdcard/Android y la mayoría de los subdirectorios de /sdcard/Android. Este acceso de escritura incluye el acceso a la ruta del archivo.

    Las apps a las que se les otorgó este permiso aún no pueden acceder a los directorios específicos de otras apps porque estos directorios aparecen como subdirectorios de Android/data/ en un volumen de almacenamiento.

Cuando una app tiene el permiso de acceso a todos los archivos, puede acceder a estos archivos y directorios adicionales mediante la API o las rutas de archivos de MediaStore. Sin embargo, cuando usas el marco de trabajo de acceso al almacenamiento, solo puedes acceder a un archivo o directorio si puedes hacerlo sin tener el permiso de acceso a todos los archivos.

Para obtener más información sobre este permiso especial, así como otros cambios en las API de almacenamiento de Android en Android 11, consulta el artículo de medios titulado Almacenamiento de usuario moderno en Android.