During development, it is often necessary to pass a file to another application, such as uploading an image to another application or copying and pasting files between different storage paths. This can be understood as the application receiving the file sending a request to the application providing the file.
Starting from Android 7.0, Android enforces the StrictMode policy, which prohibits exposing file://URLs outside of the application. If an application above Android 7.0 does not use FileProvider, a FileUriExposedException will be thrown. To share files between applications after Android 7.0, you need to use content://URL to grant temporary access permission to the URL. In other words, you need to use FileProvider to grant temporary access permission. URLs with temporary access permission are secure, and these temporary URLs will automatically expire. The getUriForFile() provided by FileProvider is used to generate the content of the file.
In all cases, the only secure way for your application to provide a file to another application is to send the content URI of the file to the receiving application and grant temporary access permission to that URI. Content URIs with temporary URI access permission are secure because they only apply to the application receiving the URI and they will automatically expire. The Android FileProvider component provides the getUriForFile() method to generate content URIs for files.
Here, we will also mention an exception that often occurs in Android 7.0 and higher versions: FileUriExposedException. This exception can be resolved by using FileProvider, which is also the result of continuous improvement in security by the Android system.
- Specify FileProvider
- Specify file sharing path
Specify FileProvider#
Specify the Provider in the AndroidManifest file, as shown below:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<!--android:authorities="${applicationId}.yourname"-->
<provider
android:name="android.support.v4.content.FileProvider"
<!--The authorities attribute specifies the URI permission to be used for the content URI generated by FileProvider, which is generally composed of applicationId.yourname"-->
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
</manifest>
Specify file sharing path#
In the above code, the file directory to be shared is specified in the meta-data directory, and the file directory is defined in filepathd.xml. The paths that can be defined in the corresponding xml are as follows, please refer to the following:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<!--Represents the root directory of the device (new File("/"))-->
<root-path name="root" path="" />
<!--Represents context.getFileDir()-->
<files-path name="files" path="" />
<!--Represents context.getCacheDir()-->
<cache-path name="cache" path="" />
<!--Represents Environment.getExternalStorageDirectory()-->
<external-path name="external" path="" />
<!--Represents context.getExternalFilesDirs()-->
<external-files-path name="name" path="path" />
<!--Represents getExternalCacheDirs()-->
<external-cache-path name="name" path="path" />
</paths>
</resources>
In the xml, a certain path is represented by two attributes. The path attribute represents the subdirectory of the current specified directory. If not specified, it represents the root directory and subdirectories of the current specified directory. The name attribute represents the URL that will be added after name as the access path for the file. Please refer to the following:
//Represents that the file to be shared will be searched in the images subdirectory under the context.getFileDir() directory
<paths>
<files-path path="images/" name="myImage" />
</paths>
//Represents the final generated shared file URL
content://com.example.myapp.fileprovider/myImage/image.jpg
Get Uri#
Finally, after the configuration is complete, when using file-related operations, the URL should be obtained in the following way, as shown below:
public Uri getUri(File file) {
Uri uri = null;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".youName", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
This way, you can easily share files above Android 7.0.