Paweł Beza
Estoy tratando de compartir archivos con FileProvider. Verifiqué que el archivo se comparte correctamente con aplicaciones como Gmail, Google Drive, etc. Aunque se lanza la siguiente excepción:
2019-08-28 11:43:03.169 12573-12595/com.example.name E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.example.name.provider/external_files/Android/data/com.example.name/files/allergy_report.pdf from pid=6005, uid=1000 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:729)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:602)
at android.content.ContentProvider$Transport.query(ContentProvider.java:231)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:104)
at android.os.Binder.execTransactInternal(Binder.java:1021)
at android.os.Binder.execTransact(Binder.java:994)
proveedor:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
</paths>
Compartir intención
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(targetPdf);
if (fileWithinMyDir.exists()) {
intentShareFile.setType("application/pdf");
Uri uri = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".provider", fileWithinMyDir);
intentShareFile.putExtra(Intent.EXTRA_STREAM, uri);
intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
intentShareFile.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
Espero que pueda señalar mi error de por qué se lanzan estas excepciones cuando parece que a las aplicaciones se les otorga el permiso correctamente y el uso compartido funciona como debería ser.
EDITAR:
Descubrí que el problema radica en la línea:
startActivity(Intent.createChooser(intentShareFile, "Share File"));
Cuando lo cambié simplemente a
startActivity(intentShareFile);
Sin embargo, muestra un diseño un poco diferente para la aplicación de recolección. Pero aún no puedo entender por qué el selector original no funciona.
Lo siento por la respuesta tardía. Lo resolví así:
Intent chooser = Intent.createChooser(intentShareFile, "Share File");
List<ResolveInfo> resInfoList = this.getPackageManager().queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
this.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivity(chooser);
Esto me ayudó: Denegación de permiso con el proveedor de archivos a través de la intención
-
¡Impresionante! Punto clave que inicialmente me perdí: pase el selector, no la intención de consultar IntentActivities ()
– lukas hansen
23 de febrero de 2020 a las 21:34
-
¡Dios mío, he estado lidiando con esto durante días! Esto resolvió mi problema y no tengo idea de por qué simplemente lo copié y pegué jaja. ¡Voy a leer lo que me salvó el trasero! ¡Gracias!
– NoobCoderChick
24 de febrero de 2020 a las 4:43
-
Lo extraño es que tengo 4 vistas de imágenes en la misma actividad y cuando haces clic en la primera (cualquiera de ellas) aparece la aplicación de la cámara, tomas la foto y se guarda en la vista de imagen sin problemas… la segunda haga clic, aparece la cámara, toma la foto y cuando selecciona la marca de verificación, se bloquea la aplicación. Lo que también es súper extraño es que el archivo de ruta que está en los documentos de Android no funciona y tengo que usar “/” como ruta… no sé.
– NoobCoderChick
24 de febrero de 2020 a las 4:45
-
Y que hay con
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
donde esta urisArrayList
?– t0m
16 de diciembre de 2020 a las 11:08
-
Esto funciona para el objetivo 31
– iadcialim24
17 de abril de 2022 a las 9:38
Liendre
También hay una manera de otorgar el permiso URI a través de la bandera Intent, sin hacerlo manualmente con grantUriPermission()
y manteniendo el uso de Intent.createChooser()
.
Él Intención.createChooser() la documentación dice:
Si la intención de destino ha especificado FLAG_GRANT_READ_URI_PERMISSION o FLAG_GRANT_WRITE_URI_PERMISSION, estas banderas también se establecerán en la intención del selector devuelto, con su ClipData establecido de manera adecuada: ya sea un reflejo directo de getClipData() si no es nulo, o un nuevo ClipData creado a partir de obtener datos().
Por lo tanto, si el Intent original tiene el Uri establecido en su ClipData
o en setData()
debería funcionar como quería.
En tu ejemplo, el ACCIÓN_ENVIAR Intent admite el conjunto de Uri a través de setClipData()
a partir de Jelly Bean (Android 4.1).
Para resumir, aquí hay un ejemplo funcional de su código:
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(targetPdf);
if(fileWithinMyDir.exists()) {
String mimeType = "application/pdf";
String[] mimeTypeArray = new String[] { mimeType };
intentShareFile.setType(mimeType);
Uri uri = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".provider", fileWithinMyDir);
// Add the uri as a ClipData
intentShareFile.setClipData(new ClipData(
"A label describing your file to the user",
mimeTypeArray,
new ClipData.Item(uri)
));
// EXTRA_STREAM is kept for compatibility with old applications
intentShareFile.putExtra(Intent.EXTRA_STREAM, uri);
intentShareFile.putExtra(Intent.EXTRA_SUBJECT,
"Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
intentShareFile.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
-
¡Gracias! Solución perfecta sin necesidad de consultar actividades.
– Derek K.
19 de febrero de 2021 a las 9:00
-
Cuál es el
path
utilizada enClipData.Item
? Lo intentéuri.path
pero la excepción todavía existe.– Samuel T. Chou
16 de febrero de 2022 a las 8:35
-
Uy, mi mal @SamuelT.Chou, deberías poner directamente el
Uri
al crear elClipData.Item()
. He editado mi respuesta con la corrección.– liendres
17 de febrero de 2022 a las 9:31
Harmen
Además de la respuesta de Nit anterior, es posible configurar el ClipData
directamente con el para ser compartido uri
como sigue.
intent.setClipData(ClipData.newRawUri("", uri));
Esto evita la excepción de seguridad al presentar el selector de intenciones.
Si desea compartir varios uri, puede configurar los datos de clip con varios uri para evitar la excepción de seguridad. Para resumir:
Intent intent = new Intent();
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (uris.size() == 0) {
return;
}
else if (uris.size() == 1) {
Uri uri = uris.get(0);
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setClipData(ClipData.newRawUri("", uri));
}
else {
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
ClipData clipData = ClipData.newRawUri("", uris.get(0));
for (int i = 1; i < uris.size(); i++) {
Uri uri = uris.get(i);
clipData.addItem(new ClipData.Item(uri));
}
intent.setClipData(clipData);
}
startActivity(Intent.createChooser(intent, title));
MOHO APRENDIZAJE
Esto funcionó para mí.
Intent sharableIntent = new Intent();
sharableIntent.setAction(Intent.ACTION_SEND);
sharableIntent.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION );
Uri imageUri = Uri.parse(ImgLoc);
File imageFile = new File(String.valueOf(imageUri));
Uri UriImage = FileProvider.getUriForFile(context, Author, imageFile);
sharableIntent.setType("image/*");
sharableIntent.putExtra(Intent.EXTRA_STREAM, UriImage);
sharableIntent.putExtra(Intent.EXTRA_TITLE, title);
sharableIntent.putExtra(Intent.EXTRA_TEXT, body);
Intent chooser = Intent.createChooser(sharableIntent, "Chooser Title");
chooser.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
context.startActivity(chooser);
crearChooser
Intent.createChooser(): Construye un nuevo Intent ACTION_CHOOSER que envuelve el intent de destino dado, y opcionalmente proporciona un título. Si la intención de destino ha especificado FLAG_GRANT_READ_URI_PERMISSION o FLAG_GRANT_WRITE_URI_PERMISSION, estas banderas también se establecerán en la intención del selector devuelto, con su ClipData establecido de manera adecuada: ya sea un reflejo directo de getClipData() si no es nulo, o un nuevo ClipData creado a partir de obtener datos()
stackoverflow.com/a/74052302/987762 para la respuesta
– kalandar
13 oct 2022 a las 8:04