File provider android studio

Share Files Using FileProvider on Android

Several weeks ago I was given a task to open an internal PDF file in any PDF reader application on an Android phone. I thought it would be straightforward, but things turned out to be complicated. Google’s documentation on FileProvider proved to be confusing and lacking concrete examples. Nevertheless, I knew I had to use ContentProvider to tackle the issue.

What is FileProvider

ContentProvider is an Android component which encapsulates data and provides it to other applications. It is required only if you need to share data between multiple applications. For example, the contacts data is shared with other applications using ContactsProvider which is a subclass of ContentProvider.

FileProvider is a subclass of ContentProvider. While ContentProvider is a component that enables you to securely share any kind of data, FileProvider is used specifically for sharing the app’s internal files. The FileProvider class is part of the v4 Support Library so make sure to include it in your project.

To make FileProvider work follow these three steps:

  • Define the FileProvider in your AndroidManifest file
  • Create an XML file that contains all paths that the FileProvider will share with other applications
  • Bundle a valid URI in the Intent and activate it

Defining a FileProvider

To define a FileProvider inside your AndroidManifest you need to be familiar with these attributes and elements:

  • android:authorities
  • android:exported
  • android:grantUriPermissions
  • android:name
  • subelement

If all of these seem extremely familiar, you’ll find your way around FileProvider a bit easier, otherwise I’ve prepared a detailed description of each attribute and its purpose.

android:authorities

You must define at least one unique authority. Android System keeps a list of all providers and it distinguishes them by authority. Authority defines the FileProvider just like the application ID defines an Android application.

In general, the Android System uses a specific URI scheme for ContentProviders. The scheme is defined as content:///

so the system will know which ContentProvider is requested by matching the URI’s authority with the ContentProvider’s authority.

android:exported

This attribute can easily be misused because its name is misleading. To understand this attribute, think of your FileProvider as a room with locked doors. If you set the value to true, you’ve basically opened your doors to everyone. Everything will work from your point of view, but you’ve just created a huge security issue as every other app will be able to use your FileProvider without being given permission.

This can teach you to never program by coincidence and always be aware of the side-effects of your code. Also, always define this attribute because the default value on SDK 16 and lower is true.

android:grantUriPermissions

If we continue thinking of a FileProvider as a locked room, then this attribute is used to give a temporary one-time key to an external app. This attribute allows you to securely share your app’s internal storage. All you have to do is add either FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION to the Intent that activates the component to open your app’s internal file. To use these flags set their value to true.

element can also have subelements. The only difference being that by using the attribute you can share anything inside your app’s internal storage, while subelements allow you to choose a specific data subset for sharing. To use subelements instead, set the value to false.

subelement

This subelement must be defined when using the FileProvider. You have to define a path to the XML file which contains all data paths your FileProvider can share with external apps.

The XML file must have the

element as its root. The

element must have at least one subelement which can be one of the following:

  • — internal app storage, Context#getFilesDir()
  • — internal app cache storage, Context#getCacheDir()
  • — public external storage, Environment.getExternalStorageDirectory()
  • — external app storage, Context#getExternalFilesDir(null)
  • — external app cache storage, Context#getExternalCacheDir()
Читайте также:  Сборник историй для андроид

You might have noticed that they vary according to the app’s directory which they define.

Each element must have a path and a name attribute. The path attribute defines the subdirectory you want to share and it does not support wildcards. The name attribute is used for security reasons and it will replace your subdirectory name with its value.

android:name

We set this value to android.support.v4.content.FileProvider.

Once you have defined a FileProvider in your AndroidManifest file, you are finally ready to use it. To share a file you have to create an Intent and give it a valid URI. The URI is generated using the FileProvider class.

Code implementation

AndroidManifest.xml

Notice that I’m using the app’s ID for authority. That’s because I have multiple flavors in the project and they can be installed on the device at the same time. Android System won’t let you install multiple applications with the same FileProvider so each flavor needs an unique authority.

file_provider_paths.xml

By defining paths like this, I allow the FileProvider to share all files that are inside the app’s internal cache and files directory.

Use your FileProvider

Once you understand how it works, implementing your own FileProvider is truly simple.

The complexity of the problem is not the code itself, but the documentation and understanding of how everything is interconnected. I hope this article will help you implement the FileProvider for your own use case and make the official documentation easier to read.

Источник

FileProvider

java.lang.Object
android.content.ContentProvider
android.support.v4.content.FileProvider

Class Overview

FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri .

A content URI allows you to grant read and write access using temporary access permissions. When you create an Intent containing a content URI, in order to send the content URI to a client app, you can also call Intent.setFlags() to add permissions. These permissions are available to the client app for as long as the stack for a receiving Activity is active. For an Intent going to a Service , the permissions are available as long as the Service is running.

In comparison, to control access to a file:/// Uri you have to modify the file system permissions of the underlying file. The permissions you provide become available to any app, and remain in effect until you change them. This level of access is fundamentally insecure.

The increased level of file access security offered by a content URI makes FileProvider a key part of Android’s security infrastructure.

This overview of FileProvider includes the following topics:

Defining a FileProvider

Since the default functionality of FileProvider includes content URI generation for files, you don’t need to define a subclass in code. Instead, you can include a FileProvider in your app by specifying it entirely in XML. To specify the FileProvider component itself, add a

element to your app manifest. Set the android:name attribute to android.support.v4.content.FileProvider . Set the android:authorities attribute to a URI authority based on a domain you control; for example, if you control the domain mydomain.com you should use the authority com.mydomain.fileprovider . Set the android:exported attribute to false ; the FileProvider does not need to be public. Set the android:grantUriPermissions attribute to true , to allow you to grant temporary access to files. For example:

If you want to override any of the default behavior of FileProvider methods, extend the FileProvider class and use the fully-qualified class name in the android:name attribute of the

Specifying Available Files

element. For example, the following paths element tells FileProvider that you intend to request content URIs for the images/ subdirectory of your private file area.

element must contain one or more of the following child elements:

Represents files in the files/ subdirectory of your app’s internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir() . Represents files in the root of your app’s external storage area. The path Context.getExternalFilesDir() returns the files/ subdirectory of this this root. Represents files in the cache subdirectory of your app’s internal storage area. The root path of this subdirectory is the same as the value returned by getCacheDir() .

These child elements all use the same attributes:

name=»name» A URI path segment. To enforce security, this value hides the name of the subdirectory you’re sharing. The subdirectory name for this value is contained in the path attribute. path=»path» The subdirectory you’re sharing. While the name attribute is a URI path segment, the path value is an actual subdirectory name. Notice that the value refers to a subdirectory, not an individual file or files. You can’t share a single file by its file name, nor can you specify a subset of files using wildcards.

Читайте также:  Browsec для андроида как пользоваться

You must specify a child element of

for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories:

element and its children in an XML file in your project. For example, you can add them to a new file called res/xml/file_paths.xml . To link this file to the FileProvider, add a element as a child of the

element that defines the FileProvider. Set the element’s «android:name» attribute to android.support.FILE_PROVIDER_PATHS . Set the element’s «android:resource» attribute to @xml/file_paths (notice that you don’t specify the .xml extension). For example:

Generating the Content URI for a File

To share a file with another app using a content URI, your app has to generate the content URI. To generate the content URI, create a new File for the file, then pass the File to getUriForFile() . You can send the content URI returned by getUriForFile() to another app in an Intent . The client app that receives the content URI can open the file and access its contents by calling ContentResolver.openFileDescriptor to get a ParcelFileDescriptor .

For example, suppose your app is offering files to other apps with a FileProvider that has the authority com.mydomain.fileprovider . To get a content URI for the file default_image.jpg in the images/ subdirectory of your internal storage add the following code: As a result of the previous snippet, getUriForFile() returns the content URI content://com.mydomain.fileprovider/my_images/default_image.jpg .

Granting Temporary Permissions to a URI

Permissions granted in an Intent remain in effect while the stack of the receiving Activity is active. When the stack finishes, the permissions are automatically removed. Permissions granted to one Activity in a client app are automatically extended to other components of that app.

Serving a Content URI to Another App

There are a variety of ways to serve the content URI for a file to a client app. One common way is for the client app to start your app by calling startActivityResult() , which sends an Intent to your app to start an Activity in your app. In response, your app can immediately return a content URI to the client app or present a user interface that allows the user to pick a file. In the latter case, once the user picks the file your app can return its content URI. In both cases, your app returns the content URI in an Intent sent via setResult() .

You can also put the content URI in a ClipData object and then add the object to an Intent you send to a client app. To do this, call Intent.setClipData() . When you use this approach, you can add multiple ClipData objects to the Intent , each with its own content URI. When you call Intent.setFlags() on the Intent to set temporary access permissions, the same permissions are applied to all of the content URIs.

Note: The Intent.setClipData() method is only available in platform version 16 (Android 4.1) and later. If you want to maintain compatibility with previous versions, you should send one content URI at a time in the Intent . Set the action to ACTION_SEND and put the URI in data by calling setData() .

More Information

To learn more about FileProvider, see the Android training class Sharing Files Securely with URIs.

Источник

Learn how to use fileprovider in Android with example

Today we will be looking at the one of the confusing topic in android i.e. FileProvider. It is confusing for beginners as they do not understand, how to use it and why to use it. So let us learn how to use FileProvider in Android with an example project.

If you just want to get file path from internal document picker check out this article: here.

What is a FileProvider in Android ?

How long have you been exploring this concept of file provider in android ? I think it’s been quite a while but you have not found a easier explanation about it. Here I will simply explain what a fileprovider is and why even bother with it in the first place ?

Читайте также:  Как отключить семейный фильтр яндекс андроид

FileProvider is simply a special subclass of ContentProvider which allows manipulating user data on storage more secure and easy ( not really at first ). It simply creates a content:/// URI instead of file:/// which makes secure.

How does it make the files accessing more secure ? To answer that question we must understand that using the FileProvider only a content:/// is exposed meaning the actual file location is hidden, and adds security.

But adding security means some headaches for developers especially for someone who is just starting with the Android Development. I will break down BITS of FileProvider below so let us continue.

Using FileProvider in Android application

Let us see how we can use the FileProvider in our application step by step.

Setting up FileProvider in manifest

Let us see how we can add the FileProvider definition in out manifest file. Add the code below in your AndroidManifest.xml file.

Creating file_paths.xml file to add our file paths

Now that we have added the FileProvider definition in our AndroidManifest.xml let us look at the code.

You will receive an error at the code above because we have to mention the path for the FileProvider to access. Which we will do below but first lets create an Android resource directory.

Go to projects side bar and navigate to app > res . Right click there and click Android Resource Directory . name the directory xml and select xml from drop down.

After that create the file_paths.xml in the xml directory and add the contents below.

Confused about what the code above means ? Don’t be because I will break everything down.

Understanding what each file path actually mean

Now we have to understand something before proceeding. Everything is scoped with file paths. Meaning accessing anything outside defined file paths will cause a runtime exception.

Each type of paths you see between

serve a purpose. And we are going to learn what that is with this fileprovider Android example.

Note: name and path is same for each. where name is the pointer and path is the actual location.

This is the path will will be accessible by invoking this method Context.getFilesDir() . We will get a file instance pointing to the files dir. This directory is located in the internal storage area on your device.

Same as above the only difference is it resides in the external removable storage area of the device. The root path is returned by Context.getExternalFilesDir(null) .

/>

This is same as files-path but it provides the root directory for internal area cache. Which is what you get when you invoke Context.getCacheDir() .

Same as the the local cache but the difference is the cache directory is located in external storage area. Which you will get once you use Context.getExternalCacheDir().

This path also defines the media directory located on the external storage area of your device. Which returns the path provided by Context.getExternalMediaDirs() . But this method is deprecated and MediaStore must be used.

This path is relative to the external root of your device. And you can get this file by Environment.getExternalStorageDirectory() . As you normally would, this method is marked deprecated and must not be used normally. Always use file providers for any file reading.

Getting the content URI

Now that we have understood what each means. Let us move forward and retrieve out URI, as it was our main goal.

We have set everything up let us create a temporary file in our cache directory. Let us write the code in out MainActivity as

Now that will create a file named test_file.txt in our cache directory, remember ?

Next we will update the URI into our TextView just to make sure it worked.

Look at the FILE_AUTHORITY which we have declared in the companion object block. The full code for MainActivity is provided below:

Sharing the URI using ShareCompat.IntentBuilder

Let us explore how we can share the URI using the ShareCompat.IntentBuilder here.

This will open up the possible applications for image/jpg , you can change that as per your need.

Now we are done. What you do with the URI is up to you. Next time we will learn how to get the actual file from URI. Till then, keep learning.

For reference you can checkout official documentation, here.

Источник

Оцените статью