WRITE_EXTERNAL_STORAGE al apuntar a Android 10

9 minutos de lectura

avatar de usuario
mihae kheel

Hay una advertencia de pelusa en AS con respecto a android.permission.WRITE_EXTERNAL_STORAGE. La advertencia dice que el permiso ya no proporcionará acceso de escritura cuando se dirija a Android 10 y superior. La eliminación de dicho permiso aún puede escribir en la carpeta de almacenamiento interno Pictures/MY_APP_NAME para guardar imágenes, pero solo funciona en Android 10 (SDK 29) y/o superior (todavía no se ha probado en Android R). Cuando lo probé nuevamente en una versión inferior como Android M (SDK 23), guardar imágenes dejó de funcionar, así que decidí devolver el android.permission.WRITE_EXTERNAL_STORAGE por lo tanto, la advertencia aparece de nuevo. ¿Es posible que la pelusa sea solo un falso positivo que diagnosticó incorrectamente el problema en diferentes casos? Porque actualmente mi SDK de soporte comienza con 21 hasta el último, que es 30, pero la pelusa solo señala que ya no es necesario cuando se apunta a Android 10 (SDK 29) y no consideró mirar hacia atrás en el soporte mínimo de SDK del proyecto.

  • can still write in internal storage folder Pictures/MY_APP_NAME Extraño. Indique la ruta completa de la carpeta.

    – aplicaciones negras

    6 de octubre de 2020 a las 7:44

  • Todavía puedes escribir a Internal Storage/Pictures/MY_APP_NAME usando MediaStore, ContentResolver y ContentValues ​​en Android 10.

    – Mihae Kheel

    6 de octubre de 2020 a las 7:48

  • @SiddharthKamaria sí, intenté agregar android:maxSdkVersion="29" pero no elimina la advertencia.

    – Mihae Kheel

    6 oct 2020 a las 8:20

  • @MihaeKheel Por extraño que parezca, mi AS no me muestra una advertencia de pelusa para WRITE_EXTERNAL_STORAGE incluso sin maxSdkVersion. ¿Tal vez intente reconstruir o invalidar cachés?

    – Siddharth Kamaria

    6 de octubre de 2020 a las 8:24


  • @SiddharthKamaria gracias por señalar, pero ya intenté invalidar, limpiar la compilación y reconstruir, la advertencia aún existe. Tal vez se deba a que tenemos una versión diferente de AS. De todos modos, estoy en la versión Canary de AS.

    – Mihae Kheel

    6 de octubre de 2020 a las 8:31


avatar de usuario
PerracoLabs

Una solución es ignorar la advertencia, ya que es solo informativa y, por lo tanto, inofensiva. Configurando maxSdkVersión a 28 no hay necesidad de preocuparse más.

<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"
    tools:ignore="ScopedStorage" />

Tenga en cuenta que usando el android:requestAlmacenamiento externo heredado flag como se indica en otras respuestas no es una solución, es solo un parche temporal que ya no funcionará en absoluto en Android 11 (API 30)y futuras versiones

ACTUALIZACIÓN, para aclarar las dudas y confusiones mostradas por algunos desarrolladores en los comentarios:

  • Si usa el solicitud de almacenamiento externo heredado bandera en Android 10 (API 29) entonces solicita el ESCRIBIR_ALMACENAMIENTO_EXTERNO permiso como de costumbre.

  • La bandera solicitud de almacenamiento externo heredado no hace nada en Android 11 (API 30)se ignora por completo y no hay solución para ello.

  • ESCRIBIR_ALMACENAMIENTO_EXTERNO no da ningún privilegio en Android 11 (API 30)no hace nada en absoluto, por lo tanto en API 11 necesitas configurar el maxSdkVersión a 29.

  • si en Android 10 (API 29) tu tampoco estas usando solicitud de almacenamiento externo heredado luego establecer maxSdkVersión a 28 en vez de 29.

  • A partir de Android 11 (API 30)el mas viejo API de archivo se puede volver a usar, pero “solo” al acceder a las carpetas públicas de “almacenamiento compartido” (DCIM, Música, etc.), o al directorio “privado” de su aplicación. Para otras ubicaciones la DocumentoArchivo Se requiere API.

  • Tenga en cuenta que la API de archivos ahora es mucho más lenta en Android 11 (API 30), porque ha sido refactorizado convirtiéndose esencialmente en un envoltorio. Esto es para hacer cumplir su uso solo en las ubicaciones permitidas. Por lo tanto, ya no es una API de archivo de sistema rápida, es solo un contenedor que internamente delega el trabajo a MediaStore. Al usar File API en Android 11 o superior, debe considerar la penalización de rendimiento, ya que, según el equipo de Android, será de 2 a 3 veces más lento que si accede directamente a MediaStore.

  • esta parece ser la peor solución de las mencionadas aquí, ya que evitará que las personas que usan Android 10 y superior instalen la aplicación

    – cristiano

    28 de enero de 2021 a las 14:02

  • gracias por sus comentarios, me sorprende leer eso, ya que la documentación bajo desarrollador.android.com/guide/topics/manifest/… dice que la instalación no será posible y en caso de revalidación después de una actualización del sistema, la aplicación incluso se eliminará

    – cristiano

    28 de enero de 2021 a las 15:38


  • @Christian Ok, ahora entiendo tu confusión. El enlace que menciona se refiere al elemento ““, y no a . Estos son 2 tipos diferentes de elementos, y “maxSdkVersion” es en realidad un “atributo” común que existe para cualquier tipo de elemento. Lo que “no debe hacer” es declarar “maxSdkVersion” en el elemento ““, pero esto no está relacionado con los permisos. Consulte la documentación real de donde explica cómo usar “maxSdkVersion” para limitar un permiso según el nivel de API: desarrollador.android.com/guide/topics/manifest/…

    – Perraco Labs

    28 de enero de 2021 a las 16:27

  • ok, ahora entiendo tu idea. Pero aún no obtendrá el acceso a archivos heredados en Android 10 y superior, ¿correcto? Como folder.listFiles() no funcionará

    – cristiano

    28/01/2021 a las 21:30

  • @Christian para Andorid 10 use requestLegacyExternalStorage. Y para Android 11, la API de archivos se puede usar “solo” al acceder a las carpetas públicas de “almacenamiento compartido” (DCIM, Música, etc.) o al directorio de su aplicación “privada”. Para otras ubicaciones, utilice la API de DocumentFile. Tenga en cuenta que la API de archivos es más lenta en la API 30, porque se ha refactorizado como un contenedor para imponer su uso solo en las ubicaciones permitidas. Delega internamente el trabajo a MediaStore. La marca “requestLegacyExternalStorage” ya no funciona en Android 11, ya que solo era temporal para dar a los desarrolladores tiempo suficiente para realizar la migración.

    – Perraco Labs

    28 de enero de 2021 a las 22:47


avatar de usuario
francesco bocci

Intente agregar esto en su Manifiesto:

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true" //Add this Line
android:label="@string/app_name">

 ---------<Activity, Sevices or Recivers>----------

</application>

y quitar el READ_EXTERNAL_STORAGE permiso de nuevo:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

  • No se necesita más requestLegacyExternalStorage y no es una buena solución para Android 10, ya que existen API como MediaStore, ContentResolver y ContentValues ​​para usar si desea almacenar sus archivos en Internal Storage/Pictures/MY_APP_NAME

    – Mihae Kheel

    6 de octubre de 2020 a las 7:51

  • No. Es una solución bastante buena. Puede seguir utilizando las rutas de archivo clásicas. Y en Android 11, también puede escribir en la carpeta Imágenes usando las rutas de archivo clásicas. Sin necesidad de mediastore y saf

    – aplicaciones negras

    6 de octubre de 2020 a las 8:07

  • Caution: After you update your app to target Android 11 (API level 30), the system ignores the requestLegacyExternalStorage attribute when your app is running on Android 11 devices, so your app must be ready to support scoped storage and to migrate app data for users on those devices. Ver también stackoverflow.com/questions/63364476/…

    – Mihae Kheel

    6 de octubre de 2020 a las 8:26


  • Sí, esa solicitud heredada no hace nada para un dispositivo Android 11. Pero todavía funciona para un dispositivo Android 10. Así que continúa usándolo, diría yo, y eso es lo que dije.

    – aplicaciones negras

    6 de octubre de 2020 a las 8:34

  • Y de nuevo: en un dispositivo con Android 11, su aplicación solo puede escribir en /storage/emulated/0/Pictures. No hay necesidad de tienda de medios y caja fuerte. No necesita MANAGE_EXTERNAL_STORAGE para eso como sugiere @Siddharth Kamaria.

    – aplicaciones negras

    6 de octubre de 2020 a las 8:36


avatar de usuario
chico tímido

¿Usando File-apis?

Según la respuesta de @PerracoLabs, los siguientes cambios harán que su aplicación funcione en los dispositivos que se ejecutan

  1. Android-9 y menos
  2. android-10
  3. Android-11 y superior

Archivo: “AndroidManifest.xml”

<!-- Without this folders will be inaccessible in Android-11 and above devices -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<!-- Without this entry storage-permission entry will not be visible under app-info permissions list Android-10 and below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>

<!-- Without this entry the folders will remain in-accessible in Android-10, even if WRITE_EXTERNAL_STORAGE as above is present. -->
<application
    android:requestLegacyExternalStorage="true"/>

Fuente Java:

  1. No olvide otorgar permisos de tiempo de ejecución antes de realizar operaciones con archivos. – Necesario para Android-10 e inferior. NO solicite permisos de tiempo de ejecución para Android-11, deben solicitarse para Android-10 e inferior.

  2. Navegue al usuario a la página de permisos de la aplicación para permitirle habilitar los permisos de archivos usando el siguiente código (necesario para la compatibilidad con Android-11 y superior):

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && false == Environment.isExternalStorageManager()) {
         Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
         startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
     }
    

  • ¿Dónde poner esto por condición? ¿En este archivo en qué línea?

    – Atif

    19 de febrero a las 15:55

avatar de usuario
Zhebzhik Babich

Como respondió @PerracoLabs, la advertencia es solo informativa. Será mejor si primero lees su respuesta. https://stackoverflow.com/a/65477206/6055194

yo suelo WRITE_EXTERNAL_STORAGE permiso solo para descargar archivos .pdf en Downloads y directorios “privados” de aplicaciones usando de DownloadManager (eso es importante y puede entender por qué si lee la discusión en la respuesta de @PerracoLabs). Así que acabo de agregar el nivel máximo de SDK para este permiso e ignorar la etiqueta para el almacenamiento con alcance.

<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"
    tools:ignore="ScopedStorage" />

pd si tools etiqueta no reconocida, debe declararla agregando xmlns:tools="http://schemas.android.com/tools" a su AndroidManifest.xml así.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.app.my">

Pero debes tener en cuenta que después de eso onRequestPermissionsResult no se llamará a la función Build.VERSION_CODES.Q y superior (API 29+). Entonces debes llamar para pedir permiso WRITE_EXTERNAL_STORAGE solo para API inferior a 29.

Entonces puede agregar una función de almacenamiento externo de verificación y escritura como esta (Kotlin).

   private fun hasWriteStoragePermission(): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return true
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (ActivityCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(
                        arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                        REQUEST_PERMISSIONS_CODE_WRITE_STORAGE
                )

                return false
            }
        }

        return true
    }

avatar de usuario
Ali Reza Zargi

Agregue la línea:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>

y agregue el siguiente código a AndroidManifest.xml:

 android:requestLegacyExternalStorage="true"

¿Ha sido útil esta solución?