4.5K Followers
·
Follow

Image for post
Image for post

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.

Yay! you made it to the end! We should hang out! feel free to follow me on Medium, LinkedIn, Google+ or Twitter.

Written by

A software engineer, an Android, and a ray of hope for your darkest code. Residing in Sydney.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store