Starting with Android 10, Google has changed the way storage is handled. This became mandatory for all apps targeting Android 11 and above. The changes were implemented with privacy in mind, not forcing users to grant access to every file on their device. This scoped storage tutorial will tell you what to know.
Scoped storage tutorial: the cliff notes version
With scoped storage, users have to grant permission every time an app tries to access a file that hasn’t been created. Developers are also encouraged to put files in specific folders, reducing the amount of clutter and clutter. Any files outside of those folders will be deleted once an app is deleted.
Also see: A guide to Android app development in 5 easy steps
Scoped storage is provided by default and is based on the type of file being saved (these are organized as “collections”). Apps can only access the types of storage they actually use.
In practice, this means that developers no longer need to use the WRITE_EXTERNAL_STORAGE permission, as it has no effect on an app’s access to storage. Certain things get easier, others become much more complicated. Read the rest of this scoped storage tutorial to find out what you need to know.
Access to app-specific storage
Apps don’t need any special permissions to access scoped storage and there are no changes to the way you save to the internal storage. However, there are a few things to keep in mind when using app-specific storage, which we’ll cover in this scoped storage tutorial.
Credit: Edgar Cervantes / Android Authority
There are two app-specific locations in external storage that should mainly be used when the internal storage is insufficient. These are for the persistent files and the app’s cache files respectively.
To access these locations, the app must first check if the storage is available (availability is guaranteed for internal storage). Get the status of the volume with Environment.getExternalStorageStage (). If MEDIA_MOUNTED is returned, you can read and write files to external storage.
Next, you need to choose a physical storage location. This may mean, for example, that you have to choose between internal memory or an SD card. Call ContextCompat.getExternalFilesDir (). The first element in the returned array is considered the “primary” external storage option and should be used in most cases.
To access app-specific files from external storage, call getExternalFilesDir ().
There are a number of ready-made folders that are intended to aid in the logical storage of files. Among which:
Use this or pass “null” if you want to access the root domain for the app-specific directory.
Use externalCacheDir to add app-specific files to the cache in external storage. Use delete () to delete them.
Access to other files
Finally, to wrap up this scoped storage tutorial we need to consider how to access and write to files shared on the system.
Apps must choose between ‘app-specific storage’ or ‘shared storage’. You use the latter if you want to share files with other apps, such as images or documents. Developers who want to access files outside of their app-specific directory must use the MANGE_EXTERNAL_STORAGE permission. You can also use the intent action ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION to send users the settings page where they can enable access for your app.
MANAGE_EXTERNAL_STORAGE grants access to the contents of the MediaStore.Files table, the root directory of the USB OTG drive and SD card, and all internal folders (except sdcard / Android and its subfolders). This restriction includes the app-specific folders of other apps as they are located in sdcard / Android / data.
We can no longer use file APIs to access files directly. Instead, we need to use the Storage Access Framework for selecting files and folders, and URIs for media files. For example, to access a photo we now need to use URIs instead of MediaStore.Images.Media.DATA. This was already the recommended practice, but is now mandatory.
Also see: Introduction to the Google Play Console for Developers
To access simple files with the Storage Access Framework, there are three main actions:
These speak for themselves. For displaying images, we would first get the ID of the image with MediaStore.Images.Media._ID and then build the Uri with ContentUris.withAppendedID. This is a significantly longer process than it used to be and certainly increases the learning curve for what could be a relatively straightforward process.
That concludes this scoped storage guide! What do you think of scoped storage? Is it a necessary security update or a frustrating hurdle for developers?
For more developer news, features and tutorials from Android Authority, sign up for the monthly newsletter below!