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.
Quick Navigation
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.
<manifest>
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="np.com.naveenniraula.fileproviderexample"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
Code language: HTML, XML (xml)
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 <meta-data />
code.
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
Code language: HTML, XML (xml)
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.
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="my_images"
path="images/" />
<files-path
name="my_docs"
path="docs/" />
<external-files-path
name="external_files_dir"
path="/" />
<cache-path
name="cache_dir"
path="/" />
<external-cache-path
name="external_cache_dir"
path="/" />
<external-media-path
name="external_media_dir"
path="/" />
<external-media-path
name="external_media_dir"
path="/" />
</paths>
Code language: HTML, XML (xml)
Confused about what the code above means ? Don’t be because I will break everything down.
Also Read: How to get current GPS location in Android
TECHENUM
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 <paths> </paths>
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.
<files-path name="" path="/" />
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.
<external-files-path name="" path="/" />
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)
.
<cache-path name="" path="/"
/>
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()
.
<external-cache-path name="" path="/" />
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().
<external-media-path name="" path="/" >
This path also defines the media directory located on the external storage area of your device. Which returns the path provided by
. But this method is deprecated and Context.getExternalMediaDirs()MediaStore
must be used.
<external-path name="" path="/" />
This path is relative to the external root of your device. And you can get this file by
. As you normally would, this method is marked deprecated and must not be used normally. Always use file providers for any file reading.Environment.getExternalStorageDirectory()
Also Read: Learn How To Create Tabs With ViewPager2
TECHENUM
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
val file = File(cacheDir.absolutePath, "test_file.txt")
// create the parent files if necessary
if (file.parentFile?.exists() == false)
file.parentFile?.mkdirs()
Code language: Kotlin (kotlin)
Now that will create a file named test_file.txt
in our cache directory, remember <cache-dir />
?
Next we will update the URI into our TextView just to make sure it worked.
// get the URI for your file
// do whatever you want with the URI
val uri = FileProvider.getUriForFile(this, FILE_AUTHORITY, file)
// show the uri in the UI
val textView: TextView = findViewById(R.id.hello_world)
textView.text = uri.toString()
Code language: Kotlin (kotlin)
Look at the FILE_AUTHORITY
which we have declared in the companion object
block. The full code for MainActivity is provided below:
class MainActivity : AppCompatActivity() {
companion object {
// same as the one defined in android:authorities in AndroidManifest.xml
const val FILE_AUTHORITY = "np.com.naveenniraula.fileproviderexample"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val file = File(cacheDir.absolutePath, "test_file.txt")
// create the parent files if necessary
if (file.parentFile?.exists() == false)
file.parentFile?.mkdirs()
// get the URI for your file
// do whatever you want with the URI
val uri = FileProvider.getUriForFile(this, FILE_AUTHORITY, file)
// show the uri in the UI
val textView: TextView = findViewById(R.id.hello_world)
textView.text = uri.toString()
Log.i("MainActivity", "we have uri : $uri")
}
}
Code language: Kotlin (kotlin)
Sharing the URI using ShareCompat.IntentBuilder
Let us explore how we can share the URI using the ShareCompat.IntentBuilder here.
Intent intent = ShareCompat.IntentBuilder.from(getContext())
.setType("image/jpg") // change the file mime type here
.setStream(uri) // URI from above
.setChooserTitle("Select your application")
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
Code language: Java (java)
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.
Also Read: 3 Essential Datastructures in Object Oriented Programming
TECHENUM