No se puede crear el directorio en Android 10

10

No puedo crear el directorio en Android 10. Funciona en dispositivos hasta Android Oreo.

Intenté dos formas de crear carpetas.

Utilizando File.mkdir() :

   File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
                    if (!f.isFile()) {
                        if (!(f.isDirectory())) {
                               success =  f.mkdir();
                        }

Aquí, la variable success siempre es falsa, lo que significa que el directorio no se crea.

Utilizando Files.createDirectory() :

   File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pastebin");
                    if (!f.isFile()) {
                        if (!(f.isDirectory())) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                try {
                                    Files.createDirectory(Paths.get(f.getAbsolutePath()));
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    Toast.makeText(getApplicationContext(), R.string.unable_to_download, Toast.LENGTH_LONG).show();
                                }
                            } else {
                                f.mkdir();
                            }
                        }

lo que causa esta excepción:

pzy64.pastebinpro W/System.err: java.nio.file.AccessDeniedException: /storage/emulated/0/Pastebin
pzy64.pastebinpro W/System.err:     at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:391)
pzy64.pastebinpro W/System.err:     at java.nio.file.Files.createDirectory(Files.java:674)

He implementado los permisos de tiempo de ejecución y

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

están todos listos.

pz64_
fuente

Respuestas:

27

Como se reveló por primera vez en marzo de 2019, ya no tiene acceso por defecto a ubicaciones arbitrarias en almacenamiento externo o almacenamiento extraíble en Android 10+. Esto incluye Environment.getExternalStorageDirectory()y otros métodos en Environment(por ejemplo, getExternalStoragePublicDirectory().

Para Android 10, puede agregar android:requestLegacyExternalStorage="true"a su <application>elemento en el manifiesto. Esto lo lleva al modelo de almacenamiento heredado, y su código de almacenamiento externo existente funcionará. Sin embargo, eso no funcionará en Android R y superior, por lo que esto es solo una solución a corto plazo.

Sus elecciones son:

  • Use métodos Contextcomo, por ejemplo getExternalFilesDir(), para acceder a directorios en almacenamiento externo en los que su aplicación puede escribir. No necesita ningún permiso para usar esos directorios en Android 4.4+. Sin embargo, los datos que almacena allí se eliminan cuando se desinstala su aplicación.

  • Use el Marco de acceso de almacenamiento, como ACTION_OPEN_DOCUMENTy ACTION_CREATE_DOCUMENT.

  • Si su contenido es multimedia, puede usarlo MediaStorepara colocar los medios en ubicaciones de medios estándar.

CommonsWare
fuente
1
¿Estás diciendo que no hay forma de crear mi propio directorio en Android Q?
Xihuny
1
@ Xihuny: Puede crear subdirectorios getExternalFilesDir()y ubicaciones similares proporcionadas por Context. No puede crear subdirectorios directamente desde las raíces del almacenamiento externo o extraíble, utilizando las API del sistema de archivos.
CommonsWare
1
No quiero hacer eso porque los archivos se eliminarán cuando el usuario desinstale la aplicación.
Xihuny
1
@ Xihuny: luego use el Marco de acceso de almacenamiento y permita que el usuario elija dónde colocar el contenido del dispositivo en el dispositivo del usuario.
CommonsWare
1
Lo intenté, pero no pude crear mi propio directorio. ¿Hay alguna manera de crear mi propio directorio con nombre personalizado usando SAF?
Xihuny el
3

Para Android 10, puedes agregar

android:requestLegacyExternalStorage="true"

a su elemento en el manifiesto. Esto lo lleva al modelo de almacenamiento heredado, y su código de almacenamiento externo existente funcionará. Sin embargo, esta solución no funcionará en Android R y superior, por lo que esta es solo una solución a corto plazo.

Sujit Jamdade
fuente
1

Dado que Q beta 4 es posible optar por no participar de esa función:

api 28 de api (o inferior) mediante el atributo de manifiesto requestLegacyExternalStorage:

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting Android Q. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>
Amit_android
fuente
-1

Esto funciona para mí y creo que es funcional en Android 10>

            ContentResolver resolver = getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Folder Example");
            String path = String.valueOf(resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues));
            File folder = new File(path);
            boolean isCreada = folder.exists();
            if(!isCreada) {
                folder.mkdirs();
            }
JP711
fuente
Estás consultando a File, por lo que tendrás que agregar android:requestLegacyExternalStorage="true"cuando apuntes a Android 10>. En ese caso, es mejor que sigas usando getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).
HB.
getExternalStoragePublicDirectory está en desuso en el nivel de API 29
JP711
¿Si y? Como dice la documentación When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible, así que si tiene android:requestLegacyExternalStorage="true"en su manifiesto, aún puede usarlo.
HB.
"¿Si y?" y, como dice la documentación, Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENTsoy nuevo en esto, pero mi pregunta sería: ¿mi propuesta es incorrecta o por qué el voto negativo? No sé muy bien cómo funciona esto, ¿es mejor continuar getExternalStoragePublicDirectory?
JP711
1
No tiene que crear una carpeta. Cuando escribe en Urila carpeta, la carpeta se crea automáticamente.
HB.