Permissions¶
modernstorage-permissions
is a library simplifying checking storage permissions. It works on Android 21+.
Add dependency to project¶
modernstorage-permissions
is available on mavenCentral()
.
// build.gradle
implementation("me.saket.modernstorage:modernstorage-permissions:1.0.0-alpha07")
API reference¶
modernstorage-permissions
API reference is available here.
Storage Permissions usage¶
Android provides two types of storage to save files:
- App-specific (internal folder, external app folder)
- Shared (visible using the system file manager)
With the introduction of Scoped Storage in Android 10 (API 29), the storage access has deeply changed:
- You can add media & document files without any permission, reading and editing media files
created by other apps require
READ_EXTERNAL_STORAGE
- Document files created by other apps are readable only using the Storage Access Framework
To help you navigate common use cases, check out the below table:
Actions | API 29- | API 29+ |
---|---|---|
Read media files (created by self) | READ_EXTERNAL_STORAGE |
No permission needed |
Read media files (created by all apps) | READ_EXTERNAL_STORAGE |
READ_EXTERNAL_STORAGE |
Add file (media, document) | WRITE_EXTERNAL_STORAGE |
No permission needed |
Edit & Delete media files (created by self) | WRITE_EXTERNAL_STORAGE |
No permission needed |
Edit & Delete media files (created by all apps) | WRITE_EXTERNAL_STORAGE |
READ_EXTERNAL_STORAGE 1️⃣ |
Edit & Delete document files (created by self) | WRITE_EXTERNAL_STORAGE |
No permission needed |
Edit & Delete document files (created by all apps) | WRITE_EXTERNAL_STORAGE |
Storage Access Framework |
1️⃣ When editing or deleting media files created by other apps on API 29+ (Android 10), you have to request explicitly user's consent. Read more here.
Check if app can access files¶
// Check if the app can read image & document files created by itself
val storagePermissions = StoragePermissions(context)
storagePermissions.hasAccess(
action = Action.READ,
types = listOf(FileType.Image, FileType.Document),
createdBy = StoragePermissions.CreatedBy.Self
)
// Check if the app can read video & audio files created by all apps
storagePermissions.hasAccess(
action = Action.READ,
types = listOf(FileType.Video, FileType.Audio),
createdBy = StoragePermissions.CreatedBy.AllApps
)
// Check if the app can read & write image & document files created by itself
val storagePermissions = StoragePermissions(context)
storagePermissions.hasAccess(
action = Action.READ_AND_WRITE,
types = listOf(FileType.Image, FileType.Video),
createdBy = StoragePermissions.CreatedBy.Self
)
// Check if the app can read & write video & audio files created by all apps
storagePermissions.hasAccess(
action = Action.READ_AND_WRITE,
types = listOf(FileType.Audio, FileType.Document),
createdBy = StoragePermissions.CreatedBy.AllApps
)
Get storage permissions¶
If the method returns an empty list, it means your app on the current device, given the defined usage, doesn't need any permissions.
// Get required permissions to read & write video & audio files created by all apps
StoragePermissions.getPermissions(
action = Action.READ,
types = listOf(FileType.Video, FileType.Audio),
createdBy = StoragePermissions.CreatedBy.AllApps
)
// Get required permissions to read & write image & document files created by the app itself
StoragePermissions.getPermissions(
action = Action.READ_AND_WRITE,
types = listOf(FileType.Image, FileType.Document),
createdBy = StoragePermissions.CreatedBy.Self
)
Request storage permissions¶
While you can use the ActivityResultContracts.RequestPermission
provided by default with the
Jetpack Activity or Fragment library to request storage permissions with input from
StoragePermissions.getPermissions
, modernstorage-permissions
bundles a custom ActivityResultContract named
RequestAccess
to request the right storage permissions to simplify the logic for you.
@Composable
fun RequestAccessExample() {
// Register a callback for the Activity Result
val requestAccess = rememberLauncherForActivityResult(RequestAccess()) { hasAccess ->
if (hasAccess) {
// write logic here
}
}
Column {
Button(onClick = {
// Request permission to read video & audio files created by all apps
requestAccess.launch(
RequestAccess.Args(
action = Action.READ,
types = listOf(
StoragePermissions.FileType.Video,
StoragePermissions.FileType.Audio
),
createdBy = StoragePermissions.CreatedBy.AllApps
),
)
}) {
Text("I want to read all video & audio files")
}
Button(onClick = {
// Request permission to read & write image & document files created by the app itself
requestAccess.launch(
RequestAccess.Args(
action = Action.READ_AND_WRITE,
types = listOf(
StoragePermissions.FileType.Image,
StoragePermissions.FileType.Document
),
createdBy = StoragePermissions.CreatedBy.Self
)
)
}) {
Text("I want to read & write the app's image & document files")
}
}
}
// Register a callback for the Activity Result
val requestAccess = registerForActivityResult(RequestAccess()) { hasAccess ->
if (hasAccess) {
// write logic here
}
}
// Request permission to read video & audio files created by all apps
requestAccess.launch(
RequestAccess.Args(
action = Action.READ,
types = listOf(StoragePermissions.FileType.Video, StoragePermissions.FileType.Audio),
createdBy = StoragePermissions.CreatedBy.AllApps
)
)
// Request permission to read & write image & document files created by the app itself
requestAccess.launch(
RequestAccess.Args(
action = Action.READ_AND_WRITE,
types = listOf(StoragePermissions.FileType.Image, StoragePermissions.FileType.Document),
createdBy = StoragePermissions.CreatedBy.Self
)
)