What is android.os.FileUriExposedException and what you can do about it
If you have an app that shares files with other apps using a Uri, you may have encountered this error on API 24+.
This error occurs when you try to share a file:// Uri in an Intent broadcast to share data with other apps. Using file:// Uri’s are discouraged in this scenario because it makes some assumptions about the destination app. For one thing, we assume that the destination app has READ_EXTERNAL_PERMISSION which may not be the case. If the destination app does not have READ_EXTERNAL_PERMISSION, this may result in unexpected behaviour at best or at worst, result in a crash.
As of Android N, in order to work around this issue, you need to use the FileProvider API.
There are 3 main steps here.
Step 1: Manifest Entry
<manifest ...>
<application ...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>
Step 2: Create XML file res/xml/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>
Step 3: Code changes
File file = ...;
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// Old Approach
install.setDataAndType(Uri.fromFile(file), mimeType);
// End Old approach
// New Approach
Uri apkURI = FileProvider.getUriForFile(
context,
context.getApplicationContext()
.getPackageName() + ".provider", file);
install.setDataAndType(apkURI, mimeType);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// End New Approach
context.startActivity(install);
That should do it!
Note
You don’t have to do this in all instances. This seems to cause an issue when using setDataAndType() in Intent as show above (Don’t know of any other instances where this exception has come up). In my tests using Uri.fromFile(file) is still working when an Intent is built for sending an email. So, the code below keeps working even through the Uri is a file:// Uri. I’m assuming this continues to work because there is an implicit understanding that any email app will expect a file:// Uri in it’s Intent extra Intent.EXTRA_STREAM and should have READ_EXTERNAL_PERMISSION.
private void sendEmail(Uri screenshot) {
String email = getString(R.string.report_issues_link);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
intent.putExtra(Intent.EXTRA_SUBJECT, "Feedback for App " + getAppVersion(getContext()));
intent.putExtra(Intent.EXTRA_TEXT, "\n\n\n\n\nApp Version:" + getAppVersion(getContext()) + "\nAndroid Version:" + getAndroidVersion() + "\nDevice:" + getDeviceName());
if (screenshot != null) {
intent.putExtra(Intent.EXTRA_STREAM, screenshot);
}
startActivity(Intent.createChooser(intent, "Send feedback..."));
}
Finally
In order to build great Android apps, read more of my articles.