Con el objetivo de darles a los usuarios más control sobre sus archivos y acotar el desorden, en Android 10 se introdujo un nuevo paradigma de almacenamiento para apps llamado almacenamiento específico. El almacenamiento específico cambia la forma en la que las apps almacenan los archivos y acceden a ellos en el almacenamiento externo de un dispositivo. Si deseas migrar tu app para admitir el almacenamiento específico, sigue las prácticas recomendadas para casos de uso de almacenamiento comunes que se describen en esta guía. Se organizan los casos de uso en dos categorías: control de archivos multimedia y control de archivos que no son multimedia.
En muchos casos, la app crea archivos a los que otras apps no necesitan o no deberían acceder. El sistema proporciona ubicaciones de almacenamiento específicas de la app para administrar esos archivos.
Para obtener más información sobre almacenamiento de archivos y acceso a ellos en Android, consulta las guías de capacitación sobre almacenamiento.
Cómo controlar archivos multimedia
En esta sección se describen algunos de los casos de uso comunes para controlar archivos multimedia (archivos de video, imágenes y audio) y se explica el enfoque general que tu app puede usar. En la siguiente tabla, se resume cada uno de estos casos de uso y se incluyen vínculos a cada una de las secciones que contienen más detalles.
Caso de uso | Resumen |
---|---|
Cómo mostrar todos los archivos de imagen o video | Usa el mismo enfoque para todas las versiones de Android. |
Cómo mostrar imágenes o videos de una carpeta en particular | Usa el mismo enfoque para todas las versiones de Android. |
Cómo acceder a la información de ubicación desde las fotos | Usa un enfoque si tu app emplea el almacenamiento específico y otro en caso contrario. |
Cómo definir la ubicación del almacenamiento para las descargas nuevas | Usa un enfoque si tu app emplea el almacenamiento específico y otro en caso contrario. |
Cómo exportar archivos multimedia de usuarios a un dispositivo | Usa el mismo enfoque para todas las versiones de Android. |
Cómo modificar o borrar varios archivos multimedia en una sola operación | Usa un enfoque para Android 11. En Android 10, inhabilita el almacenamiento específico y usa el enfoque para Android 9 y versiones anteriores. |
Cómo importar una sola imagen que ya existe | Usa el mismo enfoque para todas las versiones de Android. |
Cómo capturar una sola imagen | Usa el mismo enfoque para todas las versiones de Android. |
Cómo compartir archivos multimedia con otras apps | Usa el mismo enfoque para todas las versiones de Android. |
Cómo compartir archivos multimedia con una app específica | Usa el mismo enfoque para todas las versiones de Android. |
Cómo acceder a archivos desde código o bibliotecas que usan rutas de archivos directas | Usa un enfoque para Android 11. En Android 10, inhabilita el almacenamiento específico y usa el enfoque para Android 9 y versiones anteriores. |
Cómo mostrar archivos de imagen o video de varias carpetas
Busca una colección multimedia con la API de query()
. Para ordenar o filtrar los archivos multimedia, ajusta los parámetros projection
, selection
, selectionArgs
y sortOrder
.
Cómo mostrar imágenes o videos de una carpeta en particular
Usa el siguiente enfoque:
- Sigue las prácticas recomendadas que se describen en Cómo solicitar permisos de la app y solicita el permiso
READ_EXTERNAL_STORAGE
. - Recupera archivos multimedia basados en el valor de
MediaColumns.DATA
, que contiene la ruta absoluta del sistema de archivos hasta el elemento multimedia del disco.
Nota: Cuando accedes a un archivo multimedia existente, puedes usar el valor de la columna DATA
en tu lógica. Esto se debe a que este valor tiene una ruta de archivo válida.
Sin embargo, no debes asumir que el archivo siempre está disponible. Prepárate para controlar cualquier error de E/S basado en archivos que se pueda producir.
Por otro lado, para crear o actualizar un archivo multimedia, no uses la columna DATA
. En su lugar, usa las columnas DISPLAY_NAME
y RELATIVE_PATH
.
Cómo acceder a la información de ubicación desde las fotos
Si tu app usa almacenamiento específico, sigue los pasos de la sección Información de ubicación en fotografías de la guía de almacenamiento de contenido multimedia.
Cómo definir la ubicación del almacenamiento para las descargas nuevas
Si tu app usa almacenamiento específico, ten en cuenta la ubicación en la que eliges almacenar los archivos multimedia que descargas.
Si otras apps requieren acceso a los archivos, te recomendamos usar colecciones multimedia bien definidas para las descargas o las colecciones de documentos.
En Android 11 y versiones posteriores, otras apps no pueden acceder a los archivos del directorio externo específico de la app, incluso si usas DownloadManager
para recuperar estos archivos.
Cómo exportar archivos multimedia de usuarios a un dispositivo
Define una ubicación predeterminada adecuada para almacenar archivos multimedia de usuarios:
- Permite que los usuarios elijan si otras apps pueden leer o no sus archivos multimedia, mediante el almacenamiento específico de la app o el almacenamiento compartido.
- Permite que los usuarios exporten archivos de directorios específicos de la app a una ubicación más accesible. Usa las colecciones de imágenes, video y audio de MediaStore para exportar los archivos multimedia a la galería del dispositivo.
Cómo modificar o borrar varios archivos multimedia en una sola operación
Incorpora lógica basada en las versiones de Android en las que se ejecuta tu app.
Si se ejecuta en Android 11
Usa el siguiente enfoque:
- Crea un intent pendiente para la solicitud de escritura o eliminación de tu app con
MediaStore.createWriteRequest()
oMediaStore.createTrashRequest()
y, luego, solicita al usuario permiso para invocar ese intent y editar un conjunto de archivos. Evalúa la respuesta del usuario:
- Si se otorgó el permiso, continúa con la operación de modificación o eliminación.
- Si no se otorgó el permiso, explícale al usuario por qué la función de tu app necesita el permiso.
Obtén más información para administrar grupos de archivos multimedia con estos métodos disponibles en Android 11 y versiones posteriores.
Si se ejecuta en Android 10
Si tu app está orientada a Android 10 (nivel de API 29), inhabilita el almacenamiento específico y continúa usando el enfoque para Android 9 y versiones anteriores para realizar esta operación.
Si se ejecuta en Android 9 o versiones anteriores
Usa el siguiente enfoque:
- Sigue las prácticas recomendadas que se describen en Cómo solicitar permisos de la app y solicita el permiso
WRITE_EXTERNAL_STORAGE
. - Usa la API de
MediaStore
para modificar o borrar los archivos multimedia.
Cómo importar una sola imagen que ya existe
Si deseas importar una sola imagen que ya existe (por ejemplo, para usarla como foto del perfil de un usuario), tu app puede usar su propia IU en la operación, o bien el selector del sistema.
Cómo presentar tu propia interfaz de usuario
Usa el siguiente enfoque:
- Sigue las prácticas recomendadas que se describen en Cómo solicitar permisos de la app y solicita el permiso
READ_EXTERNAL_STORAGE
. - Usa la API de
query()
para buscar en una colección de archivos multimedia. - Muestra los resultados en la IU personalizada de tu app.
Cómo usar el selector del sistema
Usa el intent ACTION_GET_CONTENT
, que le pide al usuario que elija una imagen para importar.
Si deseas filtrar los tipos de imágenes que el selector del sistema presenta al usuario, puedes usar setType()
o EXTRA_MIME_TYPES
.
Cómo capturar una sola imagen
Si deseas capturar una sola imagen para usarla en tu app (por ejemplo, como foto del perfil de un usuario), usa el intent ACTION_IMAGE_CAPTURE
para pedirle al usuario que tome una foto con la cámara del dispositivo. El sistema almacena la foto capturada en la tabla MediaStore.Images
.
Cómo compartir archivos multimedia con otras apps
Usa el método insert()
para agregar directamente registros a MediaStore. Para obtener más información, consulta la sección Cómo agregar un elemento de la guía de almacenamiento de contenido multimedia.
Cómo compartir archivos multimedia con una app específica
Usa el componente FileProvider
de Android, como se describe en la guía Cómo configurar el uso compartido de archivos.
Cómo acceder a archivos desde código o bibliotecas que usan rutas de archivos directas
Incorpora lógica basada en las versiones de Android en las que se ejecuta tu app.
Si se ejecuta en Android 11
Usa el siguiente enfoque:
- Sigue las prácticas recomendadas que se describen en Cómo solicitar permisos de la app y solicita el permiso
READ_EXTERNAL_STORAGE
. - Accede a los archivos mediante rutas de acceso directas.
Si quieres obtener más información, consulta la sección para abrir archivos multimedia con rutas de acceso a archivos directas.
Si se ejecuta en Android 10
Si tu app está orientada a Android 10 (nivel de API 29), inhabilita el almacenamiento específico y continúa usando el enfoque para Android 9 y versiones anteriores para realizar esta operación.
Si se ejecuta en Android 9 o versiones anteriores
Usa el siguiente enfoque:
- Sigue las prácticas recomendadas que se describen en Cómo solicitar permisos de la app y solicita el permiso
WRITE_EXTERNAL_STORAGE
. - Accede a los archivos mediante rutas de acceso directas.
Cómo controlar archivos que no son multimedia
En esta sección se describen algunos de los casos de uso comunes para controlar archivos que no son multimedia y se explica el enfoque general que tu app puede usar. En la siguiente tabla, se resume cada uno de estos casos de uso y se incluyen vínculos a cada una de las secciones que contienen más detalles.
Caso de uso | Resumen |
---|---|
Cómo abrir un archivo de documento | Usa el mismo enfoque para todas las versiones de Android. |
Cómo escribir en archivos de volúmenes de almacenamiento secundario | Usa un enfoque para Android 11. Usa un enfoque diferente para las versiones anteriores de Android. |
Cómo migrar archivos existentes desde una ubicación de almacenamiento heredado | Migra los archivos al almacenamiento específico cuando sea posible. Inhabilita el almacenamiento específico para Android 10 cuando sea necesario. |
Cómo compartir contenido con otras apps | Usa el mismo enfoque para todas las versiones de Android. |
Cómo almacenar en caché archivos que no son multimedia | Usa el mismo enfoque para todas las versiones de Android. |
Cómo exportar archivos que no son multimedia a un dispositivo | Usa un enfoque si tu app emplea el almacenamiento específico y otro en caso contrario. |
Cómo abrir un archivo de documento
Usa el intent ACTION_OPEN_DOCUMENT
para pedirle al usuario que elija un archivo para abrir mediante el selector del sistema. Si deseas filtrar los tipos de archivos que el selector del sistema presenta al usuario, puedes usar setType()
o EXTRA_MIME_TYPES
.
Por ejemplo, puedes usar el siguiente código para encontrar todos los archivos PDF, DDT y TXT:
Kotlin
startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" putExtra(Intent.EXTRA_MIME_TYPES, arrayOf( "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt )) }, REQUEST_CODE )
Java
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt }); startActivityForResult(intent, REQUEST_CODE);
Cómo escribir en archivos de volúmenes de almacenamiento secundario
Los volúmenes de almacenamiento secundario incluyen tarjetas SD. Puedes acceder a la información sobre un volumen de almacenamiento determinado mediante la clase StorageVolume
.
Incorpora lógica según la versión de Android en las que se ejecuta tu app.
Si se ejecuta en Android 11
Usa el siguiente enfoque:
- Usa el modelo de almacenamiento específico.
- Orienta la app a Android 10 (nivel de API 29) o versiones anteriores.
- Declara el permiso
WRITE_EXTERNAL_STORAGE
. - Realiza uno de los siguientes tipos de acceso:
- Accede a archivos con la API de
MediaStore
. - Acceso directo a la ruta del archivo con APIs como
File
ofopen()
- Accede a archivos con la API de
Si se ejecuta en versiones anteriores
Usa el framework de acceso a almacenamiento, que permite a los usuarios seleccionar la ubicación en un volumen de almacenamiento secundario en el que tu app puede escribir el archivo.
Cómo migrar archivos existentes desde una ubicación de almacenamiento heredado
Se considera que un directorio es una ubicación de almacenamiento heredado si no es un directorio específico de la app o un directorio público compartido. Si tu app crea o consume archivos en una ubicación de almacenamiento heredado, te recomendamos que migres los archivos a ubicaciones a las que se pueda acceder con almacenamiento específico y realizar los cambios necesarios para trabajar con archivos en este tipo de almacenamiento.
Cómo mantener el acceso a la ubicación de almacenamiento heredado para la migración de datos
Tu app debe mantener el acceso a la ubicación de almacenamiento heredado para migrar cualquier archivo de apps a ubicaciones a las que se pueda acceder con almacenamiento específico. El enfoque que debes usar depende del nivel de la API de destino de tu app.
Si tu app se orienta a Android 11
Establece la marca
preserveLegacyExternalStorage
entrue
a fin de conservar el modelo de almacenamiento heredado, de modo que tu app pueda migrar los datos de un usuario cuando este actualice a la nueva versión orientada a Android 11.Para continuar, inhabilita el almacenamiento específico de modo que tu app pueda seguir accediendo a tus archivos en la ubicación de almacenamiento heredado, en dispositivos Android 10.
Si tu app se orienta a Android 10
Inhabilita el almacenamiento específico para que sea más fácil mantener el comportamiento de tu app en todas las versiones de Android.
Cómo migrar los datos de la app
Cuando tu app esté lista para la migración, usa el siguiente enfoque:
- Orienta tu app a Android 10 o versiones anteriores.
- Inhabilita el almacenamiento específico para que tu app tenga acceso a los archivos que debes migrar.
-
Implementa un código que use la API
File
para transferir archivos de su ubicación actual en/sdcard/
a una ubicación a la que se pueda acceder con almacenamiento específico:- Transfiere los archivos de app privada al directorio que muestra el método
getExternalFilesDir()
. - Transfiere cualquier archivo no multimedia compartido a un subdirectorio dedicado de la app del directorio
Downloads/
.
- Transfiere los archivos de app privada al directorio que muestra el método
- Quita los directorios de almacenamiento heredado de tu app del directorio
/sdcard/
.
Una vez que los usuarios instalan la versión nueva de tu app, completan el proceso de migración de datos en sus dispositivos. Puedes supervisar el proceso de migración en toda la base de usuarios mediante la creación de un evento de estadísticas.
Una vez que los usuarios migren sus datos, publica otra actualización en la app, orientada a Android 11.
Cómo compartir contenido con otras apps
Para compartir los archivos de tu app con otra app, usa un FileProvider
. En el caso de las apps que necesitan compartir archivos entre sí, recomendamos que uses un proveedor de contenido para cada app y, luego, que sincronices los datos a medida que se agregan a la colección.
Cómo almacenar en caché archivos que no son multimedia
El enfoque que debes usar depende del tipo de archivos que necesitas almacenar en caché.
- Archivos pequeños o que contienen información sensible: usa
Context#getCacheDir()
. - Archivos grandes o que no contienen información sensible: usa
Context#getExternalCacheDir()
.
Cómo exportar archivos que no son multimedia a un dispositivo
Define una ubicación predeterminada adecuada para almacenar archivos que no son multimedia. Permite que los usuarios exporten archivos de directorios específicos de la app a una ubicación más accesible. Usa las colecciones de documentos o descargas de MediaStore para exportar archivos que no sean multimedia al dispositivo.
Cómo controlar archivos específicos de la app
En caso de que tu app cree archivos a los que otras apps no necesitan o no deberían acceder, puedes almacenarlos en ubicaciones de almacenamiento específicas de la app.
Directorios de almacenamiento interno
El sistema evita que otras apps accedan a las ubicaciones que, en Android 10 (API nivel 29) o versiones posteriores, están encriptadas. Estas ubicaciones son un buen lugar para almacenar datos sensibles a los que solo tu app puede acceder.
Directorios de almacenamiento externo
Si el almacenamiento interno no tiene espacio suficiente para almacenar archivos específicos de la app, considera usar el almacenamiento externo. Si bien es posible que otra app acceda a estos directorios si tiene los permisos adecuados, solo tu app debe usar los archivos almacenados en esos directorios.
En Android 4.4 (API nivel 19) o versiones posteriores, la app no necesita solicitar permisos relacionados con el almacenamiento para acceder a los directorios específicos de la app en el almacenamiento externo.
Cuando el usuario desinstala tu app, se quitan los archivos guardados en el almacenamiento específico de la app y, por lo tanto, no debes usar este almacenamiento para guardar nada que el usuario espere que persista independientemente de tu app.
Cómo inhabilitar temporalmente el almacenamiento específico
Antes de que tu app sea totalmente compatible con el almacenamiento específico, puedes inhabilitarla de forma temporal en tus pruebas y en tu app de producción.
Cómo dejar de participar en tus pruebas
En Android 10 (nivel de API 29) y versiones posteriores, las pruebas de tu app se ejecutan en una zona de pruebas de almacenamiento de forma predeterminada. Esta zona de pruebas evita que la app acceda a archivos fuera del directorio específico de la app y de directorios compartidos de forma pública.
Si una prueba genera archivos para el host, como capturas de pantalla, datos de depuración, datos de cobertura o métricas de rendimiento, puedes escribir estos archivos en directorios globales. Para ello, agrega la siguiente marca al agente relevante que invoca am instrument
:
-e no-isolated-storage 1
Esta marca afecta todo el comportamiento del caso de prueba de instrumentación y todo el código de prueba invocado. Por lo tanto, cuando usas esta marca, no puedes validar la compatibilidad de tu app con el almacenamiento específico. Para el resultado de la prueba, es conveniente escribir en el almacenamiento específico de la app que la shell pueda leer. Luego, puedes extraer ese directorio con almacenamiento específico. Para determinar el directorio desde el que se debe extraer, llama a getExternalMediaDirs()
.
Cómo inhabilitar tu app de producción
Si la app se orienta a Android 10 (nivel de API 29) o versiones anteriores, puedes inhabilitar temporalmente el almacenamiento específico de la app de producción. Sin embargo, si orientas tu app a Android 10, debes configurar el valor de requestLegacyExternalStorage
como true
en el archivo de manifiesto de tu app:
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
Si deseas probar el comportamiento de una app que se orienta a Android 10 o versiones anteriores cuando usas almacenamiento específico, puedes establecer el valor de requestLegacyExternalStorage
en false
. Si realizas pruebas en un dispositivo con Android 11, también puedes usar marcas de compatibilidad de apps para probar el comportamiento de tu app con o sin almacenamiento específico.
Recursos adicionales
Para obtener más información sobre el almacenamiento de Android, consulta los siguientes materiales: