Cuando intenté implementar un requisito muy simple — Descarga una imagen y guárdala en el almacenamiento local. — Al principio todo parecía estar bien.
- Honor (Android 10) – funciona
- Redmi (Android 11) – funciona
- Xiaomi (Android 13) – funciona
- Samsung (Android 13) – Falló por completo: el cuadro de diálogo de permisos de almacenamiento nunca aparecía.
Mismo código, misma función, pero un dispositivo en Android 13 simplemente se negó a mostrar la solicitud de permiso. Así es como esta pequeña tarea de "descargar imagen" se convirtió en una inmersión profunda en Almacenamiento con alcance y GESTIONAR_ALMACENAMIENTO_EXTERNO.
Esta publicación resume cómo adapté los permisos de almacenamiento para Android 11 y versiones posteriores, y cómo manejo los diferentes comportamientos en las distintas versiones.
1. El error: El diálogo de permisos de almacenamiento nunca aparece (Samsung Android 13)
El requisito es sencillo:
Descarga una imagen y guárdala en el dispositivo para que aparezca en la galería.
En mis tres dispositivos de prueba:
- Honor – Android 10 → OK
- Redmi – Android 11 → OK
- Xiaomi – Android 13 → OK
Pero en un Dispositivo Samsung con Android 13, el sistema Nunca se mostró el cuadro de diálogo de permisos de almacenamiento., sin importar cómo lo solicitara.



Al principio pensé que se trataba simplemente de otra peculiaridad del fabricante, pero después de comprobar los cambios en los permisos de almacenamiento en las distintas versiones de Android, me di cuenta de que estaba utilizando un comportamiento que, en la práctica, había quedado obsoleto en Android 13 al usar el SDK 33.
2. Causa raíz: Las funciones WRITE/READ_EXTERNAL_STORAGE están obsoletas en Android 13 (SDK 33).
En versiones anteriores de Android, podíamos simplemente declarar estos dos permisos en el manifiesto:
LECTURA_ALMACENAMIENTO_EXTERNOESCRIBIR_ALMACENAMIENTO_EXTERNO
y luego solicitarlas en tiempo de ejecución cuando sea necesario.
En Android 13 (SDK 33) con targetSdkVersion = 33, Ese enfoque empieza a fallar:
ESCRIBIR_ALMACENAMIENTO_EXTERNOes obsoleto y prácticamente inútil en versiones recientes de Android- Si añades
maxSdkVersion=32Estos permisos siguen funcionando en Android 11/12.
pero lo son ignorado en Android 13 al apuntar a 33 - Al mismo tiempo, Play Store exige que las nuevas aplicaciones tengan como objetivo al menos el SDK 33.
Por lo tanto, para Android 11+ debemos adaptarnos a:
- Almacenamiento con alcance
- Y en algunos casos, el permiso especial:
GESTIONAR_ALMACENAMIENTO_EXTERNO
GESTIONAR_ALMACENAMIENTO_EXTERNO otorga a una aplicación un amplio acceso a todo el contenido del almacenamiento compartido (incluidos los archivos que no son multimedia). no Permite el acceso a los directorios privados de otras aplicaciones, pero Google Play aún lo considera un permiso altamente sensible.
Para dar soporte a diferentes versiones de Android, terminé dividiendo el manejo de permisos en:
- Antes de Android 11 (API < 30) – Permisos de almacenamiento externo de estilo antiguo
- Android 11 y versiones posteriores – Almacenamiento delimitado + manipulación especial con
GESTIONAR_ALMACENAMIENTO_EXTERNOdonde sea estrictamente necesario
3. Adaptación paso a paso
3.1 Declarar MANAGE_EXTERNAL_STORAGE en el manifiesto
En el AndroidManifest.xml:
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />⚠️ Nota: Porque
GESTIONAR_ALMACENAMIENTO_EXTERNOEs un permiso delicado, está restringido en Google Play. Hablaré de alternativas más adelante si solo quieres guardar imágenes.
3.2 Comprobar si se ha concedido el permiso
Yo usé Permisos fáciles para simplificar las comprobaciones de permisos.
private fun checkPer(activity: PreViewActivity): Boolean { return if (Build.VERSION.SDK_INT >= 30) { EasyPermissions.hasPermissions( activity, android.Manifest.permission.MANAGE_EXTERNAL_STORAGE ) } else { EasyPermissions.hasPermissions( activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE ) } }
- En Android 11+ (API >= 30): Yo reviso
GESTIONAR_ALMACENAMIENTO_EXTERNO - En Android 10 y versiones anteriores: Todavía reviso
ESCRIBIR_ALMACENAMIENTO_EXTERNO
Esta división es crucial, porque ESCRIBIR_ALMACENAMIENTO_EXTERNO Ya no se comporta como lo hacía en las versiones más recientes.
3.3 Solicitar permiso cuando no esté disponible
Si no se concede el permiso, lo solicito de forma diferente según la versión del sistema.
private fun requestStoragePermission(activity: PreViewActivity, curImg: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ – redirigir a la página de configuración del sistema "Acceso a todos los archivos" val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:" + activity.packageName) activity.startActivityForResult(intent, 200) } else { // Android 10 y versiones anteriores – permiso de tiempo de ejecución normal val perm = android.Manifest.permission.WRITE_EXTERNAL_STORAGE PaperThreeVariable.isToRequestPer = true EasyPermissions.requestPermissions( PermissionRequest.Builder( activity, 200, perm ).build() ) } }
- En Android 11+: no puedes simplemente “abrir” un diálogo de tiempo de ejecución normal para
GESTIONAR_ALMACENAMIENTO_EXTERNO
Debe enviar al usuario a la página de configuración del sistema donde deberá otorgar manualmente el "Acceso a todos los archivos". - En Android 10 y versiones anteriores: El diálogo clásico de permisos en tiempo de ejecución sigue funcionando.
3.4 Manejo de devoluciones de llamada de permisos
EasyPermissions ayuda a conectar la función de devolución de llamada de la actividad con nuestra propia lógica:
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array , grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) } override fun onPermissionsGranted(requestCode: Int, perms: MutableList ) { AppInitUtils().saveFreshAppImageToGallery(this, curImg) PaperThreeVariable.isToRequestPer = false } override fun onPermissionsDenied(requestCode: Int, perms: MutableList ) { PaperThreeVariable.isToRequestPer = false if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) .setRationale("Esta función requiere que se habilite el permiso de almacenamiento") .setNegativeButton("No") .setPositiveButton("Sí") .build() .show() } }
Por qué utilizo EasyPermissions aquí:
- Los usuarios pueden negar permanentemente permisos, lo que provoca que las solicitudes repetidas fallen silenciosamente
- EasyPermissions facilita lo siguiente:
- Detectar estado de “denegación permanente”
- Mostrar un cuadro de diálogo que guíe a los usuarios a Configuración del sistema → Permisos de la aplicación para habilitar el acceso al almacenamiento manualmente
Una vez concedido el permiso, llamo:
AppInitUtils().saveFreshAppImageToGallery(this, curImg)
para guardar la imagen y actualizar la galería.
Tras esta adaptación, el dispositivo Samsung con Android 13 finalmente se comportó igual que los demás.
Nota al margen: Mi dispositivo Xiaomi se identificaba como Android 13, pero la sección "Dispositivos conectados históricos" de Android Studio lo reconocía como Android 12. Esto podría explicar por qué seguía funcionando en algunos casos, pero precisamente por eso es importante gestionar los permisos teniendo en cuenta la versión del sistema.
4. Acerca de MANAGE_EXTERNAL_STORAGE y las restricciones de Google Play
GESTIONAR_ALMACENAMIENTO_EXTERNO es poderoso:
Otorga acceso de lectura/escritura a todo el almacenamiento compartido en el dispositivo.
Debido a esto, Google Play lo trata como un permiso altamente confidencial:
- Está destinado principalmente a administrador de archivos / copia de seguridad / antivirus aplicaciones de tipo
- Debes presentar una justificación para usarlo.
- Si tu aplicación es solo una aplicación de consumo típica (por ejemplo, guardar imágenes, descargas simples), lo más probable es que tu solicitud sea rechazado
Entonces, si su único requisito es:
“Guarda una imagen en la galería y hazla visible para el usuario.”
entonces deberías Considere seriamente evitar GESTIONAR_ALMACENAMIENTO_EXTERNO y en su lugar:
- Usar MediaStore para insertar imágenes en la biblioteca de medios del sistema
- O bien, utilice API que puedan guardar imágenes sin necesidad de acceder al archivo completo.
Existen varios patrones para:
- Guarda una imagen en el directorio Pictures/DCIM.
- Notifica al escáner de medios o confía en MediaStore para que la galería pueda detectarlo.
- Haz todo esto sin solicitar MANAGE_EXTERNAL_STORAGE
Para la distribución interna o fuera de Play Store (por ejemplo, tiendas de aplicaciones internas empresariales), técnicamente aún puede usar Entorno.getExternalStorageDirectory(), pero no recomiendo diseñar una nueva aplicación basada en esto en 2025.
5. Resumen versión por versión (Android 9 → 13)
Para tenerlo todo claro, aquí tenéis un resumen general de cómo se comportan el almacenamiento externo y los permisos en las distintas versiones.
Android 9 y versiones anteriores (API 28 y anteriores)
- Permisos:
LECTURA_ALMACENAMIENTO_EXTERNOESCRIBIR_ALMACENAMIENTO_EXTERNO
- Comportamiento:
- Las aplicaciones pueden acceder libremente
/tarjeta sdy sus subdirectorios - Los archivos creados por la aplicación permanecen en el dispositivo incluso después de desinstalarla.
- Las aplicaciones pueden acceder libremente
- Enfoque típico:
- Lectura/escritura directa en rutas de almacenamiento externas.
Android 10 (API 29) – Introducción del almacenamiento con ámbito
- Permisos:
LECTURA_ALMACENAMIENTO_EXTERNOTodavía funcionaESCRIBIR_ALMACENAMIENTO_EXTERNOTodavía existe, pero su alcance efectivo se ha reducido.
- Comportamiento:
- Almacenamiento con alcance se presenta:
- Las aplicaciones están limitadas a su propio directorio específico de aplicaciones en
Android/datos/nombre.de.tu.paquete/ - El acceso directo a los archivos de otras aplicaciones está restringido.
- Las aplicaciones están limitadas a su propio directorio específico de aplicaciones en
- Se debe acceder a los archivos multimedia (imágenes, vídeos, audio) a través de MediaStore
requestLegacyExternalStorage=truepodría mantener temporalmente el comportamiento anterior
(pero esta bandera se ignora a partir de Android 11)
- Almacenamiento con alcance se presenta:
- Enfoque recomendado:
- Para imágenes/vídeos/audio: utilice MediaStore
- Para archivos privados: utilice
obtenerDirectorioDeArchivosExternos()oobtenerDirectorioDeDatos()
Android 11 (API 30) – Almacenamiento con ámbito restringido (aplicado)
- Permisos:
LECTURA_ALMACENAMIENTO_EXTERNOFunciona, pero solo para contenido multimedia gestionado por MediaStore.ESCRIBIR_ALMACENAMIENTO_EXTERNOes efectivamente obsoleto para almacenamiento externo generalGESTIONAR_ALMACENAMIENTO_EXTERNOIntroducido para casos de uso especiales de “acceso a todos los archivos”.
- Comportamiento:
requestLegacyExternalStorage=trueya no funciona; Almacenamiento con ámbito es siempre encendido- Acceso a
/tarjetas SD/La raíz está bloqueada - Las aplicaciones solo pueden:
- Acceda a sus propios directorios privados
- Acceda a los medios compartidos a través de MediaStore
- Enfoque recomendado:
- Para aplicaciones típicas:
- Utilice MediaStore o Fuerzas Armadas de Singapur (
ACCIÓN_ABRIR_DOCUMENTO,ACCIÓN_CREAR_DOCUMENTO) para archivos seleccionados por el usuario
- Utilice MediaStore o Fuerzas Armadas de Singapur (
- Solo considere
GESTIONAR_ALMACENAMIENTO_EXTERNOsi tu aplicación es realmente un administrador de archivos, una herramienta de copia de seguridad, una aplicación de seguridad, etc.
- Para aplicaciones típicas:
Android 13 (API 33) – División de permisos multimedia
- Permisos:
LEER_IMÁGENES_MEDIA– acceder a las imágenesLEER_VIDEO_MEDIA– acceder a los vídeosLEER_MEDIA_AUDIO– acceso al audio
- Comportamiento:
- Los permisos de los medios son de grano fino:
- Los usuarios pueden otorgar acceso solo a imágenes, solo a vídeos, etc.
- Las reglas de almacenamiento con ámbito de Android 11 siguen vigentes.
- Los permisos de los medios son de grano fino:
- Enfoque recomendado:
- Solicita los permisos de medios específicos que necesitas:
- Por ejemplo, si solo trabaja con imágenes, solicite solo
LEER_IMÁGENES_MEDIA
- Por ejemplo, si solo trabaja con imágenes, solicite solo
- Hacer no pedido
LECTURA_ALMACENAMIENTO_EXTERNOen Android 13+, ya que se reemplaza por los nuevos permisos de medios
- Solicita los permisos de medios específicos que necesitas:
Matriz rápida (conceptual)
- Android 9 y versiones anteriores
- El acceso al almacenamiento externo es amplio y está controlado por READ/WRITE_EXTERNAL_STORAGE.
- Android 10
- Se ha introducido el almacenamiento con ámbito, pero existen vías de escape (
solicitudAlmacenamientoExternoLegado)
- Se ha introducido el almacenamiento con ámbito, pero existen vías de escape (
- Android 11
- Se aplica el almacenamiento con ámbito restringido y se eliminan los conmutadores heredados.
GESTIONAR_ALMACENAMIENTO_EXTERNOaparece, pero está muy restringido.
- Android 13
- El acceso a los medios se dividió en
LEER_MEDIOS_*permisos - Las mismas reglas de almacenamiento con ámbito definido, pero con un control de usuario más preciso.
- El acceso a los medios se dividió en
6. Conclusiones
- No des por sentado que "funciona en un dispositivo Android 13" significa que funciona en todas partes; los fabricantes de equipos originales y los informes del sistema pueden ser inconsistentes.
- Para Android 11+, Piensa en términos de:
- Directorios privados de la aplicación + MediaStore + SAF, no “crudo”
/tarjeta sdacceso"”
- Directorios privados de la aplicación + MediaStore + SAF, no “crudo”
- Tratar
GESTIONAR_ALMACENAMIENTO_EXTERNOcomo un último recurso Para tipos de aplicaciones muy específicos, especialmente si planeas publicarlas en Google Play. - Siempre prueba en Múltiples dispositivos y versiones de Android, especialmente en lo que respecta a permisos y almacenamiento.
Este artículo surge de mi propia experiencia depurando y adaptando el texto en proyectos reales de Android (incluido un dispositivo Samsung con Android 13). GPT solo colaboró en la traducción y el perfeccionamiento de la redacción; todo el contenido técnico y las decisiones son responsabilidad mía.


