SoFunction
Updated on 2025-03-04

Detailed explanation of the properties of FileProvider based on Android and the problem of FileProvider multi-node

As we all know, in Android 7.0, the restrictions on private storage have been modified, resulting in the fact that when obtaining resources, we cannot obtain the uri through the models that need to be adapted to 7.0+. We need to write this way:

1: Code adaptation

 if (.SDK_INT > 23) {//
        (Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Uri contentUri = (context,  + ".fileProvider", outputFile);
        (contentUri, "application/-archive");
      } else {
        ((outputFile), "application/-archive");
      }

2: Create provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:andro>
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
  <external-path name="beta_external_path" path="Download/"/>
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
  <external-path name="beta_external_files_path" path="Android/data/"/>
 
</paths>

The provider_path attribute is explained in detail

name and path

name: uri path fragment. For security, this value hides the subdirectory name you share. The subdirectory name of this value is contained in the path property.

path: The subdirectory you share. Although the name attribute is a URI path fragment, path is a real subdirectory name. Note that path is a subdirectory, not a single file or multiple files.

-path

Represents the same file path as ()

-path

<cache-path name="name" path="path" />

Represents the same file path as getCacheDir()

-path

<external-path name="name" path="path" />

Represents the same file path as ()

-files-path

<external-files-path name="name" path="path" />

Represents the same file path as Context#getExternalFilesDir(String) and (null)

-cache-path

<external-cache-path name="name" path="path" />

Represents the same file path as ()

6: Configuration

android:authorities used in FileProvider

<provider 
  android:name="." 
  android:authorities="" 
  android:exported="false" 
  android:grantUriPermissions="true"> 
  <meta-data 
    android:name=".FILE_PROVIDER_PATHS" 
    android:resource="@xml/file_paths" /> 
</provider> 

7: Use FileProvider

*** returnURI:content:///my_images/default_image.jpg.

File imagePath = new File((), "images"); 
File newFile = new File(imagePath, "default_image.jpg"); 
Uri contentUri = getUriForFile(getContext(), "", newFile); 

8. Customize FileProvider


class MyFileProvider extends FileProvider {}

Just configure android:authorities

3: In our project, some other third-party SDKs may be used to take photos. They also added this node to adapt to Android 7.0. At this time, some people may not know how to start. In fact, it is very simple. We just need to rewrite a class and inherit it from FileProvider, and then add a node according to the above method:

<provider
  android:name=""
  android:authorities="${applicationId}.provider"
  android:grantUriPermissions="true"
  android:exported="false">
  <meta-data
    android:name=".FILE_PROVIDER_PATHS"
    android:resource="@xml/cust_file_paths" />
</provider>

If you don't want to customize FileProvider, there is another way, which is to copy the path in the third-party SDK to provider_paths.xml.

As shown below:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:andro>
  <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
  <external-path name="beta_external_path" path="Download/"/>
  <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
  <external-path name="beta_external_files_path" path="Android/data/"/>
 
  <external-path name="external_storage_root" path="."/>
  <files-path name="files" path="."/>
 
</paths>

Note⚠️: When using the provider, configure the path path="." represents all paths

Generate Content URI

Before Android 7.0, we usually used the () method to generate a File URI. Here, we need to use the public static method getUriForFile provided by the FileProvider class to generate the Content URI.

for example:

Uri contentUri = (this,
BuildConfig.APPLICATION_ID + ".fileProvider", myFile);


Three parameters need to be passed. The second parameter is the authorities property value set when registering FileProvider in the Manifest file. The third parameter is the file to be shared, and this file must be in the subdirectory we added in the path file in the second step.

For example:

String filePath = () + "/images/"+()+".jpg";
File outputFile = new File(filePath);
if (!().exists()) {
  ().mkdir();
}
Uri contentUri = (this,
    BuildConfig.APPLICATION_ID + ".fileProvider", outputFile);

The generated Content URI is like this:

content:///my_images/

Among them, the host part that constitutes the URI is the authorities attribute value (applicationId + customname) of the <provider> element, and the path fragment my_images is the subdirectory alias specified in the res/xml file (the real directory name is: images).

Step 4,Grant Content URI access

After generating a Content URI object, you need to authorize access to it. There are two ways to authorize:

The first method is to authorize access to the URI object to other applications using the grantUriPermission(package, Uri, mode_flags) method provided by Context. The three parameters represent other application package names that authorize access to the URI object, the Uri object that authorizes access, and the authorization type. Among them, the authorization type is the read and write type constant provided by the Intent class:

FLAG_GRANT_READ_URI_PERMISSION

FLAG_GRANT_WRITE_URI_PERMISSION

Or both are authorized at the same time. In this form of authorization, the authority is valid until the device restarts or the revokeUriPermission() method is manually called to revoke the authorization.

The second method is to use it in conjunction with Intent. Add a Content URI to the intent object via the setData() method. Then use the setFlags() or addFlags() method to set read and write permissions, and the optional constant value is the same as above. In this form of authorization, the authority is valid until the stack destruction of other applications, and once authorized to a certain component, other components of the application have the same access rights.

Step 5,Provide Content URI to other applications

Once you have a content URI granted, you can start other applications through the startActivity() or setResult() method and pass the authorized Content URI data. Of course, there are other ways to provide services.

If you need to pass multiple URI objects at once, you can use the setClipData() method provided by the intent object, and the permissions set by the setFlags() method apply to all Content URIs.

Common usage scenarios

The content introduced above is all theoretical part, and is introduced in the developer's official FileProvider part. Next, let’s take a look at what FileProvider usage scenarios will be encountered frequently during the actual development of an application.

Automatically install files

Opening the new version of the apk file when the version update is completed to achieve automatic installation function. It should be the most common usage scenario and one of the essential functions of each application. The common operation is that the notification bar shows that the download of the new version is completed, and the user clicks or listens to the download process and automatically opens the new version apk file. Before adapting to Android 7.0, our code might look like this:

File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
(Intent.FLAG_ACTIVITY_NEW_TASK);
((apkFile), "application/-archive");
startActivity(installIntent)

Now, in order to adapt to systems with version 7.0 and above, the Content URI must be used instead of the File URI.

Create a new file_provider_paths.xml file (file name is freely defined) in the res/xml directory and add subdirectory path information:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:andro>
 
  <external-files-path name="my_download" path="Download"/>
 
</paths>

Then register the FileProvider object in the Manifest file and link the path file above:

<provider
  android:name="."
  android:authorities=""
  android:exported="false"
  android:grantUriPermissions="true">
 
  <meta-data
    android:name=".FILE_PROVIDER_PATHS"
    android:resource="@xml/file_provider_paths"/>
 
</provider>

Modify the java code, generate a Content URI object based on the File object, and authorize access:

File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
Uri apkUri = (this,
    BuildConfig.APPLICATION_ID+".fileProvider", apkFile);
 
Intent installIntent = new Intent(Intent.ACTION_VIEW);
(Intent.FLAG_ACTIVITY_NEW_TASK);
(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(apkUri, "application/-archive");
startActivity(installIntent);

OK If you don't understand, contact me in time

The above detailed explanation of the attribute configuration of Android FileProvider and the multi-node problem of FileProvider are all the content I have shared with you. I hope you can give you a reference and I hope you can support me more.