Guía de adaptación de permisos de almacenamiento de Android para Android 11+

Cuando intenté implementar un requisito muy simple, Descargue una imagen y guárdela 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 permiso de almacenamiento nunca aparecía

Mismo código, misma función, pero un dispositivo con Android 13 simplemente se negó a mostrar la solicitud de permiso. Así fue como esta pequeña tarea de "descargar imagen" se convirtió en una inmersión profunda en... Almacenamiento con alcance y ADMINISTRAR ALMACENAMIENTO EXTERNO.

Esta publicación resume cómo adapté los permisos de almacenamiento para Android 11 y superior, y cómo manejo los diferentes comportamientos en las distintas versiones.


1. Error: El cuadro de diálogo de permisos de almacenamiento nunca se muestra (Samsung Android 13)

El requisito es sencillo:

Descargue una imagen y guárdela 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 permiso de almacenamiento, no importa como lo solicité.

Al principio pensé que se trataba simplemente de otra peculiaridad del OEM, pero después de verificar los cambios en los permisos de almacenamiento en las versiones de Android, me di cuenta de que estaba confiando en un comportamiento que efectivamente había quedado obsoleto en Android 13 al apuntar al SDK 33.


2. Causa raíz: WRITE/READ_EXTERNAL_STORAGE están obsoletos en Android 13 (SDK 33)

En versiones anteriores de Android, simplemente podríamos declarar estos dos permisos en el manifiesto:

  • LEER ALMACENAMIENTO EXTERNO
  • ESCRIBIR ALMACENAMIENTO EXTERNO

y luego solicitarlos en tiempo de ejecución cuando sea necesario.

En Android 13 (SDK 33) con versiónSdk de destino = 33, ese enfoque empieza a fallar:

  • ESCRIBIR ALMACENAMIENTO EXTERNO es obsoleto y efectivamente inútil en versiones recientes de Android
  • Si agregas Versión máxima del SDK = 32 Para estos permisos, todavía funcionan en Android 11/12.
    pero lo son ignorado en Android 13 cuando se apunta a 33
  • Al mismo tiempo, Play Store requiere que las nuevas aplicaciones tengan como mínimo el SDK 33.

Entonces, para Android 11+ debemos adaptarnos a:

  • Almacenamiento con alcance
  • Y en algunos casos, el permiso especial: ADMINISTRAR ALMACENAMIENTO EXTERNO

ADMINISTRAR ALMACENAMIENTO EXTERNO Otorga a una aplicación acceso amplio a todo el contenido de almacenamiento compartido (incluidos los archivos no multimedia). no permite el acceso a los directorios privados de otras aplicaciones, pero Google Play aún lo considera un permiso muy 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 superior – Almacenamiento con alcance + manejo especial con ADMINISTRAR ALMACENAMIENTO EXTERNO donde sea estrictamente necesario

3. Adaptación paso a paso

3.1 Declarar MANAGE_EXTERNAL_STORAGE en el manifiesto

En el Archivo AndroidManifest.xml:

<uses-permission
    android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

⚠️ Nota: Porque ADMINISTRAR ALMACENAMIENTO EXTERNO Es un permiso confidencial, restringido en Google Play. Hablaré de alternativas más adelante si solo quieres guardar imágenes.


3.2 Comprobar si se concede el permiso

Yo usé Permisos fáciles para simplificar las comprobaciones de permisos.

diversión privada checkPer(actividad: PreViewActivity): Boolean { devolver si (Build.VERSION.SDK_INT >= 30) { EasyPermissions.hasPermissions( actividad, android.Manifest.permission.MANAGE_EXTERNAL_STORAGE ) } de lo contrario { EasyPermissions.hasPermissions( actividad, android.Manifest.permission.WRITE_EXTERNAL_STORAGE ) } }
  • En Android 11+ (API >= 30):Yo compruebo ADMINISTRAR ALMACENAMIENTO EXTERNO
  • En Android 10 y anteriores:Todavía lo reviso ESCRIBIR ALMACENAMIENTO EXTERNO

Esta división es crucial, porque ESCRIBIR ALMACENAMIENTO EXTERNO ya no se comporta como lo hacía en versiones más nuevas.


3.3 Solicitar permiso cuando falta

Si no se concede el permiso, lo solicito de forma diferente según la versión del sistema.

Solicitud privada de permiso de almacenamiento (actividad: 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 anteriores: permiso 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 cuadro de diálogo de tiempo de ejecución normal para ADMINISTRAR ALMACENAMIENTO EXTERNO
    Debe enviar al usuario a la página de configuración del sistema donde le otorgará manualmente “Acceso a todos los archivos”.
  • En Android 10 y anteriores:El cuadro de diálogo de permisos de tiempo de ejecución clásico aún funciona.

3.4 Manejar devoluciones de llamadas de permisos

EasyPermissions ayuda a unir la devolución de llamada de la actividad y nuestra propia lógica:

anular la función fun onRequestPermissionsResult( requestCode: Int, permissions: Array , grantResults: IntArray ) { super.onRequestPermissionsResult(códigoDeSolicitud, permisos, grantResults) EasyPermissions.onRequestPermissionsResult(códigoDeSolicitud, permisos, grantResults, esto) } anular fun onPermissionsGranted(códigoDeSolicitud: Int, permisos: MutableList ) { AppInitUtils().saveFreshAppImageToGallery(this, curImg) PaperThreeVariable.isToRequestPer = false } anular la función fun onPermissionsDenied(requestCode: Int, perms: MutableList ) { PaperThreeVariable.isToRequestPer = false if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { AppSettingsDialog.Builder(this) .setRationale("Esta función requiere que el permiso de almacenamiento esté habilitado") .setNegativeButton("No") .setPositiveButton("Sí") .build() .show() } }

¿Por qué uso EasyPermissions aquí?

  • Los usuarios pueden negar permanentemente Permisos, lo que hace que las solicitudes repetidas fallen silenciosamente
  • EasyPermissions facilita:
    • Detectar el estado de “negación permanente”
    • Mostrar un diálogo que guía a los usuarios a Configuración del sistema → Permisos de aplicaciones Para habilitar el acceso al almacenamiento manualmente

Una vez concedido el permiso, llamo:

AppInitUtils().saveFreshAppImageToGallery(esto, curImg)

para guardar la imagen y actualizar la galería.

Después de esta adaptación, el dispositivo Samsung Android 13 finalmente se comportó igual que los demás.

Nota al margen: Mi dispositivo Xiaomi reportó Android 13, pero los "dispositivos conectados históricos" de Android Studio lo reconocieron como Android 12. Eso podría explicar por qué todavía funcionaba en algunos casos, pero es exactamente por eso que el manejo de permisos teniendo en cuenta la versión es importante.


4. Acerca de MANAGE_EXTERNAL_STORAGE y las restricciones de Google Play

ADMINISTRAR ALMACENAMIENTO EXTERNO es poderoso:

Otorga acceso de lectura/escritura a todo el almacenamiento compartido en el dispositivo.

Por eso, Google Play lo trata como un permiso altamente sensible:

  • Está destinado principalmente a administrador de archivos / copia de seguridad / antivirus aplicaciones de tipo
  • Debes presentar una justificación para usarlo.
  • Si su aplicación es solo una aplicación de consumo típica (por ejemplo, guardar imágenes, descargas simples), lo más probable es que su solicitud sea rechazado

Entonces, si su único requisito es:

“Guardar una imagen en la galería y hacerla visible para el usuario”.”

Entonces deberías considere seriamente evitar ADMINISTRAR ALMACENAMIENTO EXTERNO y en su lugar:

  • Usar MediaStore para insertar imágenes en la biblioteca multimedia del sistema
  • O utilice API que puedan guardar imágenes sin requerir acceso completo al archivo

Existen varios patrones para:

  • Guardar una imagen en el directorio Imágenes/DCIM
  • Notifique al escáner de medios o confíe en MediaStore para que la galería pueda recogerlo
  • Haz todo esto sin solicitar MANAGE_EXTERNAL_STORAGE

Para la distribución interna o fuera de Play Store (por ejemplo, tiendas de aplicaciones internas de empresas), técnicamente aún puedes usar Entorno.getExternalStorageDirectory(), pero no recomiendo diseñar una nueva aplicación en torno a esto en 2025.


5. Resumen versión por versión (Android 9 → 13)

Para poner todo en un solo lugar, aquí hay un resumen de alto nivel de cómo se comportan el almacenamiento externo y los permisos en las distintas versiones.

Android 9 y anteriores (API 28 y anteriores)

  • Permisos:
    • LEER ALMACENAMIENTO EXTERNO
    • ESCRIBIR ALMACENAMIENTO EXTERNO
  • Comportamiento:
    • Las aplicaciones pueden acceder libremente /tarjeta sd y sus subdirectorios
    • Los archivos creados por la aplicación permanecen en el dispositivo incluso después de desinstalarla.
  • Enfoque típico:
    • Leer/escribir directamente en rutas de almacenamiento externas

Android 10 (API 29): Se introduce el almacenamiento con alcance

  • Permisos:
    • LEER ALMACENAMIENTO EXTERNO todavía funciona
    • ESCRIBIR ALMACENAMIENTO EXTERNO Todavía existe, pero su alcance efectivo es reducido
  • Comportamiento:
    • Almacenamiento con alcance Se introduce:
      • Las aplicaciones están limitadas a su propio directorio específico de aplicaciones en
        Android/datos/su.nombre.de.paquete/
      • El acceso directo a los archivos de otras aplicaciones está restringido
    • Se debe acceder a los archivos multimedia (imágenes, vídeos, audio) a través de MediaStore
    • requestLegacyExternalStorage=verdadero Podría mantener temporalmente el comportamiento anterior
      (pero esta bandera se ignora a partir de Android 11)
  • Enfoque recomendado:
    • Para imágenes/vídeos/audio: utilizar MediaStore
    • Para archivos privados: utilice obtenerDirectorioDeArchivosExternos() o obtenerDataDir()

Android 11 (API 30): Almacenamiento con alcance implementado

  • Permisos:
    • LEER ALMACENAMIENTO EXTERNO Funciona, pero solo para medios administrados por MediaStore
    • ESCRIBIR ALMACENAMIENTO EXTERNO es efectivamente obsoleto para almacenamiento externo general
    • ADMINISTRAR ALMACENAMIENTO EXTERNO Introducido para casos de uso especiales de "acceso a todos los archivos"
  • Comportamiento:
    • requestLegacyExternalStorage=verdadero ya no funciona; el almacenamiento con alcance es siempre encendido
    • Acceso a /tarjeta sd/ la raíz está bloqueada
    • Las aplicaciones solo pueden:
      • Acceder a sus propios directorios privados
      • Acceda a medios compartidos a través de MediaStore
  • Enfoque recomendado:
    • Para aplicaciones típicas:
      • Utilice MediaStore o Fuerzas Armadas Sudafricanas (ACCIÓN_ABRIR_DOCUMENTO, ACCIÓN_CREAR_DOCUMENTO) para archivos seleccionados por el usuario
    • Sólo considere ADMINISTRAR ALMACENAMIENTO EXTERNO si su aplicación es realmente un administrador de archivos, una herramienta de respaldo, una aplicación de seguridad, etc.

Android 13 (API 33): Permisos multimedia divididos

  • Permisos:
    • LEER IMÁGENES MULTIMEDIA – acceder a imágenes
    • LEER VIDEO MULTIMEDIA – acceder a vídeos
    • LEER AUDIO DE MEDIOS – acceder al audio
  • Comportamiento:
    • Los permisos de los medios son de grano fino:
      • Los usuarios pueden conceder únicamente acceso a imágenes, únicamente acceso a vídeos, etc.
    • Las reglas de almacenamiento con alcance de Android 11 siguen vigentes
  • Enfoque recomendado:
    • Solicita los permisos de medios específicos que necesitas:
      • Por ejemplo, si solo trabaja con imágenes, solicite únicamente LEER IMÁGENES MULTIMEDIA
    • Hacer no pedido LEER ALMACENAMIENTO EXTERNO en Android 13+, ya que se reemplaza por los nuevos permisos de medios

Matriz rápida (conceptual)

  • Android 9 y anteriores
    • El acceso al almacenamiento externo es amplio y está controlado por READ/WRITE_EXTERNAL_STORAGE
  • Android 10
    • Se introdujo el almacenamiento con alcance, pero hay escotillas de escape (solicitud de almacenamiento externo heredado)
  • Android 11
    • Se implementa el almacenamiento con alcance, se eliminan los conmutadores heredados
    • ADMINISTRAR ALMACENAMIENTO EXTERNO Aparece pero está muy restringido
  • Androide 13
    • El acceso a los medios se divide en LEER_MEDIA_* permisos
    • Las mismas reglas de almacenamiento con alcance, pero un control de usuario más preciso

6. Conclusiones

  • No asuma que "funciona en un dispositivo Android 13" significa que funciona en todas partes; los informes de los OEM y del sistema pueden ser inconsistentes.
  • Para Android 11+, piensa en términos de:
    • Directorios privados de aplicaciones + MediaStore + SAF, no “crudo /tarjeta sd acceso"”
  • Tratar ADMINISTRAR ALMACENAMIENTO EXTERNO como un último recurso para tipos de aplicaciones muy específicos, especialmente si planea publicar en Google Play.
  • Pruebe siempre en Múltiples dispositivos y versiones de Android, especialmente cuando se trata de permisos y almacenamiento.

Este artículo es el resultado de mi propia depuración y adaptación en proyectos reales de Android (incluido un dispositivo Samsung con Android 13). GPT solo ayudó a traducir y pulir la redacción; todo el contenido técnico y las decisiones son mías.

Acerca del autor

Compartir publicación:

Resumir con IA

Tabla de contenido

Mantente conectado

Más actualizaciones