studio persistencia memoria manejo interna externo example escribir datos crear carpeta cache archivos archivo almacenamiento android android-intent android-contentprovider android-7.0-nougat

persistencia - manejo de archivos en android studio



Android: cómo obtener un contenido:// URI para un archivo en el directorio PUBLIC de almacenamiento externo (2)

Esto es lo que estoy usando en mi aplicación para el directorio público de Imágenes.

  1. Crea el archivo como este:

    File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME");

  2. Especifique la siguiente ruta en los metadatos del proveedor de archivos:

    <paths> <external-path name="secure_name" path="Pictures/YOUR_APP_NAME" /> </paths>

"secure_name" se usa para ocultar el nombre del subdirectorio ( "YOUR_APP_NAME" en este caso) que está compartiendo por razones de seguridad.

"Imágenes" corresponde a Environment.DIRECTORY_PICTURES .

  1. Obtener Uri para enviar con Intent :

    final Uri theUri = FileProvider.getUriForFile(activity, getString(R.string.fileprovider_authorities), theFile); theIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); theIntent.putExtra(MediaStore.EXTRA_OUTPUT, theUri);

He seguido este tutorial de Google para iniciar un intento de capturar una imagen con una new Intent(MediaStore.ACTION_IMAGE_CAPTURE) . El tutorial recomienda usar el directorio público con getExternalStoragePublicDirectory que funcionaría muy bien para mi aplicación. Pero entonces su ejemplo en su lugar usa getExternalFilesDir . Luego, para pasar el URI del archivo a la intención con MediaStore.EXTRA_OUTPUT debo obtener un URI de contenido porque me gustaría apuntar a Android N. Antes de apuntar a NI solo pasaría un archivo: // URI y todos, excepto Google, estaban contentos. . Ahora en NI, comencé a obtener la FileUriExposedException que no parece ser muy favorable .

Así que dado que tengo un archivo como este ...

private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyAppFolder"); if (!storageDir.exists() && !storageDir.mkdir()) Log.w(TAG, "Couldn''t create photo folder: " + storageDir.getAbsolutePath()); File image = new File(storageDir, timeStamp + ".jpg"); mCurrentPhotoPath = image.getAbsolutePath(); return image; }

... ¿puedo usar un proveedor incorporado para el directorio público de imágenes para obtener un URI de contenido? ¿Si es así, cómo?

He intentado algo como

takePictureIntent.putExtra( MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this, MediaStore.AUTHORITY, createImageFile()));

pero solo tira

IllegalArgumentException: faltan los metadatos android.support.FILE_PROVIDER_PATHS

¿Es correcta la autoridad? Si debo usar mi propio proveedor para compartir el archivo público, ¿qué ruta puedo especificar en mis metadatos FILE_PROVIDER_PATHS? Todas las opciones que puedo encontrar son para directorios privados.


TL: DR <external-path name="MyAppFolder" path="." /> <external-path name="MyAppFolder" path="." /> funciona, pero es seguro?

Necesitará crear su propio FileProvider . Vale la pena leer su documentation , pero aquí hay un breve resumen.

Como mencionó @CommonsWare, deberá reemplazar MediaStore.AUTHORITY de su ejemplo con "com.example.fileprovider" , que es la autoridad que definirá en su manifiesto como ...

Dentro de la etiqueta <application> en el AndroidManifest, escriba lo siguiente:

<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>

La excepción que está obteniendo se debe a que no tiene esa etiqueta <meta-data> que se vincula a un archivo xml con todas las rutas que su FileProvider puede tocar. Pero es en este archivo que he estado luchando conmigo mismo.

Hacia el final del tutorial que vinculó, al final de la sección Guardar la foto de tamaño completo , el ejemplo que da Google para este file_paths.xml es:

<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> </paths>

"my_images" se reemplazaría con "MyAppFolder" en su ejemplo. En ese tutorial Google reclama.

El componente de ruta corresponde a la ruta que devuelve getExternalFilesDir () cuando se llama con Environment.DIRECTORY_PICTURES. Asegúrese de reemplazar com.example.package.name con el nombre del paquete real de su aplicación.

... y escribir eso me hizo darme cuenta de que NO se está refiriendo al directorio público de Imágenes que usted y yo estamos buscando. Lo que explica por qué usar esa ruta produce esta excepción:

java.lang.IllegalArgumentException: no se pudo encontrar la raíz configurada que contiene /storage/emulated/0/Pictures/MyAppFolder/{filename}.jpg

Dejaré eso aquí para futuras referencias, y continuaré con la respuesta a su gran pregunta: ¿qué ruta puede especificar para permitir que otras aplicaciones interactúen con un archivo en el directorio público de Imágenes creado por su aplicación que apunta a la API de nivel 24+?

Como dijo @CommonsWare, "los detalles de su subdirectorio deseado varían según el dispositivo", por lo que no puede declarar la ruta al directorio público de Imágenes, pero encontré una manera que funciona.

<external-path name="MyAppFolder" path="." /> <external-path name="MyAppFolder" path="." /> permitirá a su FileProvider dar un URI de contenido a otras aplicaciones (como la cámara), que luego puede leer y escribir en el archivo al que se resuelve.

Si hay algún peligro o desventaja en esto, me encantaría escucharlos.