Scoped Storage — qué es, gestión de archivos y acceso al almacenamiento

Autor: IT Sectr Publicado: 2026-07-10 Tiempo de lectura: 10 min

Scoped Storage es un modelo de acceso al sistema de archivos introducido en Android 10 (API 29) que restringe el acceso arbitrario de las aplicaciones al almacenamiento compartido del dispositivo. Según la Documentación para Desarrolladores de Google Android (2024), Scoped Storage reemplaza el antiguo modelo de permisos READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE, otorgando a las aplicaciones acceso solo a sus propios archivos en un sandbox aislado y a colecciones compartidas a través de MediaStore. Este modelo mejora la privacidad de los datos del usuario y evita la recopilación no autorizada de información por parte de las aplicaciones.

Puntos clave

  • Scoped Storage es un modelo de acceso a archivos en Android 10+ que restringe la lectura arbitraria del almacenamiento compartido.
  • La aplicación tiene su propio sandbox con acceso completo sin permisos adicionales.
  • Para acceder a archivos compartidos (fotos, videos, audio) se usa la API MediaStore.
  • Para acceder a directorios y archivos arbitrarios se usa Storage Access Framework (SAF).
  • Los permisos READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE han perdido efecto para la mayoría de los escenarios.

¿Qué es Scoped Storage en Android?

Scoped Storage es un cambio arquitectónico en Android 10 (API 29) que transforma fundamentalmente la forma en que las aplicaciones acceden al sistema de archivos del dispositivo. En lugar de acceso completo al almacenamiento compartido, la aplicación obtiene acceso solo a su propio sandbox y a colecciones de medios específicas a través de MediaStore.

Antes de Scoped Storage, cualquier aplicación con permiso READ_EXTERNAL_STORAGE podía leer todos los archivos en el almacenamiento compartido — fotos, documentos, descargas, datos de otras aplicaciones. Esto creaba riesgos de privacidad: aplicaciones malintencionadas podían recopilar información del usuario sin su conocimiento.

Según Google I/O 2019, más del 65% de los usuarios de Android consideran la privacidad de los datos un factor crítico al elegir una aplicación. Scoped Storage es una respuesta directa a esta demanda: cada aplicación opera en un entorno aislado y obtiene acceso a los datos de otras aplicaciones solo con el consentimiento explícito del usuario.

Importante: Scoped Storage en Android 10 era opcional (la aplicación podía desactivarlo mediante requestLegacyExternalStorage). A partir de Android 11 (API 30), Scoped Storage se volvió obligatorio para todas las aplicaciones, independientemente del target SDK.

Por qué fue necesario Scoped Storage

Google introdujo Scoped Storage para resolver tres problemas fundamentales del antiguo modelo de acceso a archivos: privacidad, gestión de permisos y limpieza de archivos residuales.

Problema de privacidad

En el modelo antiguo, una aplicación con READ_EXTERNAL_STORAGE podía escanear todo el almacenamiento compartido y recopilar metadatos de los archivos del usuario — coordenadas geográficas de fotos, nombres de documentos, estructura de directorios. Scoped Storage elimina esta posibilidad: incluso con permiso, la aplicación solo ve los archivos que ella misma creó y los que el usuario seleccionó explícitamente a través de SAF.

Problema de limpieza al desinstalar la aplicación

Antes de Scoped Storage, las aplicaciones podían dejar archivos en el almacenamiento compartido después de la desinstalación. Con el tiempo se acumulaban directorios basura. Scoped Storage resuelve esto: todos los archivos en el sandbox de la aplicación se eliminan junto con la aplicación, y los archivos a través de MediaStore tienen un propietario y pueden ser limpiados por el sistema.

AspectoModelo antiguo (Legacy)Scoped Storage
Acceso al almacenamiento compartidoCompleto (con permiso)Solo su propio sandbox
Archivos multimediaRuta de archivo directaA través de URI de MediaStore
Archivos de otras aplicacionesSiempre accesiblesSolo a través de SAF
Limpieza al desinstalarLos archivos permanecenEl sandbox se elimina
Control del usuarioMínimoConsentimiento explícito por archivo

Scoped Storage es parte de la estrategia general de privacidad de Google en Android, que también incluye permisos "solo mientras se usa", indicadores de acceso a cámara y micrófono, y el Panel de privacidad.

Directorio privado de la aplicación

Cada aplicación en Android recibe su propio directorio privado, accesible a través de Context.getFilesDir() y context.getCacheDir(). Para acceder al directorio privado externo (compartido) se usa Context.getExternalFilesDir().

En Scoped Storage, una aplicación tiene acceso completo a su directorio privado externo sin ningún permiso. Este es el lugar principal para almacenar archivos que no deben ser accesibles para otras aplicaciones o que la aplicación crea para su propio uso.

kotlin
import android.os.Environment
import java.io.File
import java.io.IOException

class FileManager {

    fun saveToAppStorage(context: Context, fileName: String, data: ByteArray) {
        val appDir = context.getExternalFilesDir(null)
            ?: return
        val file = File(appDir, fileName)
        file.writeBytes(data)
    }

    fun readFromAppStorage(context: Context, fileName: String): ByteArray? {
        val appDir = context.getExternalFilesDir(null)
            ?: return null
        val file = File(appDir, fileName)
        return file.takeIf { it.exists() }?.readBytes()
    }
}

Ruta al directorio privado externo: /storage/emulated/0/Android/data/{packageName}/files/. A partir de Android 11, la ruta de archivo directa no está disponible — solo a través de la API. Esta es otra mejora de seguridad de Scoped Storage.

MediaStore — acceso a archivos multimedia

MediaStore es la API principal para acceder a archivos multimedia compartidos (imágenes, videos, audio) en Scoped Storage. La aplicación no trabaja con rutas de archivo, sino con content URIs proporcionados por el proveedor de MediaStore.

MediaStore se divide en tres colecciones principales: Images, Video y Audio. Cada colección admite operaciones CRUD a través de ContentResolver. Para insertar un nuevo archivo en la colección Images se usa MediaStore.Images.Media; para consultar los existentes — query con la URI correspondiente.

kotlin
import android.content.ContentValues
import android.provider.MediaStore
import android.os.Environment
import java.io.OutputStream

fun saveImageToGallery(context: Context, bitmap: Bitmap, title: String) {
    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "$title.jpg")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(
            MediaStore.Images.Media.RELATIVE_PATH,
            "${Environment.DIRECTORY_PICTURES}/MyApp"
        )
    }

    val uri = context.contentResolver
        .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        ?: return

    context.contentResolver.openOutputStream(uri)?.use { output: OutputStream ->
        bitmap.compress(
            Bitmap.CompressFormat.JPEG,
            95,
            output
        )
    }
}

Importante: MediaStore no admite rutas de archivo arbitrarias — solo content URIs. Intentar obtener una ruta de archivo desde una URI a través de MediaStore.Files.getContentUri() no dará una ruta directa al archivo en Android 11+. En su lugar, usa ContentResolver.openInputStream() y openOutputStream() para trabajar con el contenido.

Storage Access Framework (SAF)

Storage Access Framework (SAF) es una API para acceder a archivos y directorios arbitrarios fuera del sandbox de la aplicación. SAF proporciona al usuario una interfaz de selección de archivos o directorios, tras lo cual la aplicación recibe un content URI con acceso temporal.

SAF se utiliza para escenarios que no cubre MediaStore: trabajar con documentos arbitrarios (PDF, ZIP, APK), acceder a directorios en la tarjeta SD, importar y exportar archivos desde otras aplicaciones. El usuario selecciona explícitamente un archivo a través del selector de archivos del sistema — esto garantiza su consentimiento para el acceso.

kotlin
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.DocumentsContract

const val REQUEST_CODE_PICK_DIR = 1001

fun pickDirectory(activity: Activity) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    activity.startActivityForResult(intent, REQUEST_CODE_PICK_DIR)
}

fun handlePickResult(requestCode: Int, data: Intent?) {
    if (requestCode == REQUEST_CODE_PICK_DIR && data != null) {
        val treeUri: Uri = data.data ?: return

        // Take persistent URI permission
        val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                       Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        contentResolver.takePersistableUriPermission(treeUri, flags)
    }
}

SAF otorga a la aplicación acceso al directorio seleccionado por el usuario hasta que se reinicie el dispositivo (al usar takePersistableUriPermission). Esta es la única forma de obtener acceso a archivos arbitrarios en el almacenamiento compartido en Android 11+.

Migración de la aplicación a Scoped Storage

Migrar una aplicación Android existente a Scoped Storage requiere cambios en varias áreas clave. Google recomienda un enfoque por fases con pruebas en Android 11+.

Reemplazar rutas de archivo por content URIs

Reemplaza todas las operaciones directas con File en el almacenamiento compartido por ContentResolver.openInputStream / openOutputStream. Para archivos en el sandbox de la aplicación (getExternalFilesDir), las rutas de archivo siguen funcionando.

Actualizar AndroidManifest

Elimina READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE si no son necesarios para escenarios específicos (por ejemplo, gestión de archivos — para esto existe el permiso especial MANAGE_EXTERNAL_STORAGE).

EscenarioEnfoque antiguoEnfoque Scoped Storage
Guardar una fotoFile(path).writeBytes()MediaStore + ContentResolver
Leer PDFFile(path).inputStream()SAF ACTION_OPEN_DOCUMENT
Archivos propiosEnvironment.getExternalStorageDirectory()context.getExternalFilesDir()
CachéFile(cacheDir).writeBytes()context.cacheDir (sin cambios)

Después de la migración, prueba la aplicación en Android 11+ (API 30), configurando targetSdk = 30 o superior en build.gradle. Asegúrate de que todas las operaciones con archivos en el almacenamiento compartido funcionen a través de MediaStore o SAF, no mediante rutas de archivo directas.

kotlin
import android.os.Build

fun isScopedStorage(): Boolean {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}

fun compatReadFile(context: Context, uri: Uri): ByteArray? {
    return if (isScopedStorage()) {
        context.contentResolver
            .openInputStream(uri)?.readBytes()
    } else {
        File(uri.path ?: return null)
            .takeIf { it.exists() }
            ?.readBytes()
    }
}

Según Google Play Console (2024), más del 78% de los dispositivos Android activos funcionan con Android 10+ y Scoped Storage. La migración es un paso obligatorio para publicar actualizaciones en Google Play: las nuevas aplicaciones deben tener target API 31+, las actualizaciones — API 30+.

Preguntas frecuentes

¿Se puede desactivar Scoped Storage en Android 11?

No, a partir de Android 11 (API 30) Scoped Storage es obligatorio para todas las aplicaciones. El flag requestLegacyExternalStorage, disponible en Android 10, no funciona en API 30+. La única forma de obtener acceso amplio al sistema de archivos es el permiso MANAGE_EXTERNAL_STORAGE, pero está destinado solo para gestores de archivos y antivirus.

¿Qué es MANAGE_EXTERNAL_STORAGE y cómo obtenerlo?

MANAGE_EXTERNAL_STORAGE es un permiso especial para aplicaciones que necesitan acceso completo al sistema de archivos (gestores de archivos, herramientas de backup). La solicitud de permiso abre una pantalla del sistema con una advertencia para el usuario. Al publicar en Google Play, es necesario completar un formulario de Declaración sobre la necesidad de este permiso.

¿Cómo obtener una ruta de archivo desde un content URI en Scoped Storage?

En Scoped Storage en Android 11+ no se puede obtener una ruta de archivo directa desde un content URI. En su lugar, usa ContentResolver.openInputStream() para leer y openOutputStream() para escribir. Si necesitas una ruta de archivo para compatibilidad con una biblioteca de terceros, crea una copia del archivo en getCacheDir() y trabaja con la copia.

¿Cómo afecta Scoped Storage a FileProvider?

FileProvider sigue funcionando sin cambios — se usa para proporcionar acceso a archivos del sandbox de la aplicación a otras aplicaciones a través de content URIs. Scoped Storage no afecta a FileProvider, ya que FileProvider funciona a nivel de content URIs, no de rutas de archivo directas.

¿Cómo comprobar si un dispositivo es compatible con Scoped Storage?

Comprueba Build.VERSION.SDK_INT: si es >= Build.VERSION_CODES.Q (29), entonces el dispositivo es compatible con Scoped Storage. Sin embargo, en Android 10, Scoped Storage puede estar desactivado mediante requestLegacyExternalStorage. En Android 11+, verifica si el flag de manifiesto requestLegacyExternalStorage está establecido — si no, Scoped Storage está activo.

Resumen

  • Scoped Storage es un modelo de acceso a archivos en Android 10+ que restringe la lectura arbitraria del almacenamiento compartido.
  • La aplicación tiene acceso completo a su sandbox privado sin permisos adicionales.
  • Para acceder a archivos multimedia compartidos se usa la API MediaStore con content URIs.
  • Para acceder a archivos y directorios arbitrarios se usa Storage Access Framework (SAF).
  • A partir de Android 11, Scoped Storage es obligatorio para todas las aplicaciones.
  • Los permisos READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE no funcionan en la mayoría de los escenarios en Android 11+.
  • Al migrar, reemplaza las rutas de archivo directas por ContentResolver.openInputStream / openOutputStream.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también