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.
Crea el archivo como este:
File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME");
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
.
Obtener
Uri
para enviar conIntent
: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.