Introduction to the

Prior to Android 7.0, the Uri of a file was provided to other apps as file:///.

After Android 7.0, the Uri for sharing files has changed. For security reasons, uris of the form file:/// cannot be accessed properly. FileProvider is officially provided, and the Uri generated by the FileProvider is shared with other apps as content://.

A Uri in the form of content can give other apps temporary Read and Write permissions, as long as we add permissions with intent.setFlags () when creating an Intent. As long as the app receiving the Uri is active in the receiving Activity task stack, the added permissions remain in effect until the app is removed from the task stack.

purpose

Prior to 7.0, in order to access a Uri of the form file:///, we had to change the file permissions. The modified permissions are valid for all apps. This behavior is not secure. The Uri in the form of Content :// makes the Android file system more secure. For shared files, the receiving app only has temporary permissions, which reduces the behaviors of files inside the app being maliciously manipulated by other apps.

use

Create FileProvider

Add the pvodier tag to the manifest file

tag as follows.

<manifest>.<application>
        <activity>.</activity>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.app.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
            		android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>
Copy the code

Android: Name Specifies the location of the Provider. The official built-in FileProvider is quite complete, so we don’t need to customize it like Service and Broadcast. We can use the built-in FileProvider directly. If you type privoder directly, a message will be displayed automatically.

Android :authorities is equivalent to a password for authentication and uses its value to generate urIs when sharing files. The value is a domain name in the format of < package name >.fileProvider.

Android: Exported is set to false, and the FileProvider does not need to be exposed.

Android: grantUriPermissions is set to true so that I can authorize temporary access to the app at the receiving end.

Setting a Shared Directory

Create a resource file in RES/XML (create first if the XML directory does not exist) with any name (usually file_paths.xml).


      
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_logs" path="logs/"/>.</paths>
Copy the code

< Paths > There must be one or more child tags, each representing the private file directory to request. Different sublabels represent different directory types.

Add a

child tag to the tag.

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.example.app.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
Copy the code

Set the

property android:name to android.support.FILE_PROVIDER_PATHS and the property Android :resouce to the path file name we just created.

Configure paths

Each child tag of < Paths > must have a path attribute that represents the path of the Content Uris. Name does not need to be the same as path, just a name.

There are several types of sub-tags.

files-path

<files-path name="my_files" path="path" />
Copy the code

Represents the files directory of internal storage, corresponding to the path obtained by context.getFilesdir ().

The resulting Uri format for: authorities/pathname/filename

Example:

content://com.example.app.fileprovider/my_files/filexxx.jpg
Copy the code

cache-path

<cache-path name="name" path="path" />
Copy the code

Represents the cache directory for internal storage, corresponding to the path obtained by context.getcachedir ().

external-path

<external-path name="name" path="path" />
Copy the code

On behalf of the external storage (sdcard) cache directory, and the Environment. The external.getexternalstoragedirectory () to obtain the path of the corresponding.

external-files-path

<external-files-path name="name" path="path" />
Copy the code

On behalf of the app external storage root directory, and Context# getExternalFilesDir (String) Context. GetExternalFilesDir (null) access to the path of the corresponding.

external-cache-path

<external-cache-path name="name" path="path" />
Copy the code

On behalf of the root directory of the app external cache area, and the Context. GetExternalCacheDir () to obtain the path of the corresponding.

external-media-path

<external-media-path name="name" path="path" />
Copy the code

On behalf of the root directory of the app external storage media area, and the Context. GetExternalMediaDirs () to obtain the path of the corresponding.

Note: This directory only exists on systems with API 21 (aka Android 5.0) and above.

Generate the Content Uri file

In order for other apps to use Content URIs, our app must generate urIs in advance.

File filePath = new File(Context.getFilesDir(), "my_log");
File newFile = new File(filePath, "my_log.log");
/ / generated uris
Uri contentUri = FileProvider.getUriForFile(getContext(), "com.example.app.fileprovider", newFile);
Copy the code

When you configure Paths, the child tags of paths must correspond to the code that gets the directory. Here we use context.getFilesdir (), so the paths file must contain the files-path subtag, otherwise other apps will fail to get urIs.

The resulting Uri is used FileProvider getUriForFile (). The first parameter is the value of the authorities property set in the provider.

Grant temporary authority

Shareware generally has only read and write permissions, which are passed in intent.addFlags () as required.

// Send a file.
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Copy the code

Uri the incoming Intent

There are several ways to pass in, depending on the scenario.

Share attachment files for your email app

intent.putExtra(Intent.EXTRA_STREAM, contentUri);
Copy the code

Other share

Use intent.setdate or intent.setclipdata ().

inetnt.setClipDataClipData.newRawUri("", contentUri)
Copy the code

Finally, startActivity(intent) is used to start the sharing operation.