Permission Denial while sharing file with FileProvider
Solution 1
Sorry about the late response. I solved it like this:
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);
This helped me: Permission Denial with File Provider through intent
Solution 2
There is also a way to grant the URI permission through the Intent flag, without doing in manually with grantUriPermission()
and by keeping the usage of Intent.createChooser()
.
The Intent.createChooser() documentation states:
If the target intent has specified FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION, then these flags will also be set in the returned chooser intent, with its ClipData set appropriately: either a direct reflection of getClipData() if that is non-null, or a new ClipData built from getData().
Therefore, if the original Intent has the Uri set in its ClipData
or in setData()
, it should work as wanted.
In your example, the ACTION_SEND Intent supports the Uri set through setClipData()
as of Jelly Bean (Android 4.1).
Long story short, here is a working example of your code:
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"));
}
Solution 3
In addition to the answer of Nit above, it is possible to set the ClipData
directly with the to be shared uri
as follows.
intent.setClipData(ClipData.newRawUri("", uri));
This prevents the security exception when presenting the intent chooser.
If you want to share multiple uris, you can set the clipdata with multiple uris to prevent the security exception. To summarize:
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));
Paweł Bęza
Hi ;) I'm Paul and I am currently studying Computer Science at Warsaw University of Technology.
Updated on June 14, 2022Comments
-
Paweł Bęza almost 2 years
I am trying to share file with FileProvider. I checked that file is shared properly with apps like Gmail, Google Drive etc. Even though following exception is thrown:
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)
provider:
<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>
Sharing Intent
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")); }
Hopefully you can point out my mistake why this exceptions is thrown when it seems like apps are granted permission properly and sharing works as it should be.
EDIT:
I found that the problem lies in line:
startActivity(Intent.createChooser(intentShareFile, "Share File"));
When I changed it simply to
startActivity(intentShareFile);
However it displays a little bit different layout for picking application. But still I cannot figure out why original chooser is not working.
-
lukas hansen about 4 yearsAwesome! Key takeaway I initially missed: Pass the chooser, not the intent to queryIntentActivities()
-
NoobCoderChick about 4 yearsOMG, I have been dealing with this for days! This solved my issue and I have no idea why I just copy and pasted it haha. Gonna read through what just saved my butt! Thanks!
-
NoobCoderChick about 4 yearsWhats weird is I have 4 image views on the same activity and when you click the first one (any of them) the camera app comes up, you take the pic and it saves to the image view just fine...the second one I click, camera comes up, you take the pic and when you select select the checkmark it crashes the app. What's also super weird is the path file that is in Android docs does not work and I have to use "/" as the path...idk
-
Rahul Matte over 3 yearsDoes anybody comment for more details please
-
t0m over 3 yearsAnd what about
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
where uris isArrayList
? -
Peter Csala over 3 yearsPlease provide some explanation why do you think your proposed solution might help the OP.
-
Admin over 3 yearsIntent.createChooser():Builds a new ACTION_CHOOSER Intent that wraps the given target intent, also optionally supplying a title. If the target intent has specified FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION, then these flags will also be set in the returned chooser intent, with its ClipData set appropriately: either a direct reflection of getClipData() if that is non-null, or a new ClipData built from getData().
-
Peter Csala over 3 yearsPlease amend your answer to include what you have written in the comment.
-
Admin over 3 yearsoh, sorry I'm New Here. I will do
-
Derek K about 3 yearsThanks! Perfect solution without the need of querying activities.
-
Samuel T. Chou over 2 yearsThe
FLAG_GRANT_PERSISTABLE_URI_PERMISSION
solution does not solve the problem in Android 11. -
Samuel T. Chou over 2 yearsWhat is the
path
used inClipData.Item
? I trieduri.path
, but exception still exists. -
Nit about 2 yearsOops, my bad @SamuelT.Chou, you should directly put the
Uri
when creating theClipData.Item()
. I have edited my answer with the fix. -
iadcialim24 about 2 yearsThis works for target 31