Storage Access Framework is an Android framework for secure access to files and documents through a system selection dialog. Instead of requesting broad storage read permissions, the app receives a URI link to the file chosen by the user. According to Android Developers (2026), SAF supports local storage, cloud services Google Drive, and Dropbox through DocumentProvider. The framework was introduced in Android 4.4 and became the standard for working with documents starting from Android 10.
Key Takeaways
Storage Access Framework is a part of the Android SDK that provides a unified interface for selecting and creating documents through a system dialog. SAF abstracts the physical location of files: the app does not know where the file is being read from — local disk, Google Drive, or Dropbox.
The SAF architecture includes three components: the client app that initiates the request, the system picker — a standard file selection dialog, and the DocumentProvider — a content provider that implements access to files of a specific storage. The user sees a unified interface regardless of the data source.
SAF has been available since Android 4.4 (API 19). Initially, the framework supported only documents, but Android 5.0 added support for directories via ACTION_OPEN_DOCUMENT_TREE. Since Android 10, SAF became the recommended way to access any file outside app-specific storage.
SAF launches a system file selection dialog via an Intent with the ACTION_OPEN_DOCUMENT action. The user sees a list of available sources: internal storage, Google Drive, Dropbox, and other registered providers. After selecting a file, the system returns a content URI with temporary access rights.
The content URI has the format content://com.android.externalstorage.documents/document/primary/Download/file.pdf. Unlike a file:// URI, the content URI does not reveal the actual file path and works through DocumentProvider. The app reads the file via ContentResolver.openInputStream using the obtained URI.
The system picker automatically supports search, sorting, and filtering of files by MIME types. The developer specifies the needed types via Intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("application/pdf", "image/*")), and the picker shows only relevant files.
By default, the URI is valid until the app restarts or the device reboots. For long-term access, the app requests takePersistableUriPermission — this allows reading the file on subsequent launches without re-selecting via the dialog.
SAF provides three main actions for working with files: open, create, and select folder tree. ACTION_OPEN_DOCUMENT opens the system picker to select an existing file. ACTION_CREATE_DOCUMENT creates a new file — the user enters a name in the dialog, and the app receives a URI for writing.
ACTION_OPEN_DOCUMENT_TREE allows selecting an entire directory and gaining access to all files within it. This is used in file managers, backup applications, and synchronization tools. The app receives a directory URI and can recursively enumerate contents via DocumentFile.
| Action | Purpose | Flag |
|---|---|---|
| ACTION_OPEN_DOCUMENT | Select an existing file | READ_FLAG |
| ACTION_CREATE_DOCUMENT | Create a new file | WRITE_FLAG |
| ACTION_OPEN_DOCUMENT_TREE | Select a directory | READ + WRITE |
For each action, MIME types are specified via EXTRA_MIME_TYPES. Multiple types can be specified: "application/pdf", "image/*", "text/plain". If no types are specified, the picker shows all files.
Persistent URI permissions is an SAF mechanism that allows preserving access to a file after the current session ends. Without this flag, the URI is only valid until the app restarts. The app requests the FLAG_GRANT_PERSISTABLE_URI_PERMISSION flag along with the READ and WRITE flags.
To save permissions, the ContentResolver.takePersistableUriPermission method is used. The system saves the URI in a special registry and restores access on the next app launch. To check whether the app has persistent access to a URI, use ContentResolver.persistedUriPermissions.
The user can revoke saved permissions via Settings → Apps → Permissions. The app should handle the scenario where access to a file is unexpectedly lost. It is recommended to check access via ContentResolver.openInputStream before starting work and properly handle SecurityException.
SAF is launched through a standard Intent. The code is minimal: create an Intent with ACTION_OPEN_DOCUMENT, specify MIME types, and launch it via ActivityResultContracts.StartActivityForResult. After selecting a file, the callback receives the URI in data.data, which is then used for reading.
val pickFile = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
result.data?.data?.let { uri ->
val inputStream = contentResolver?.openInputStream(uri)
// read from inputStream
}
}
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
setType("application/pdf")
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
pickFile.launch(intent)
To write a new file, use ACTION_CREATE_DOCUMENT. The Intent accepts the MIME type and file name via EXTRA_TITLE. After selecting a folder and confirming, the user returns a URI into which the app writes data via ContentResolver.openOutputStream. The system automatically creates the file in the chosen location.
SAF differs from the traditional READ_EXTERNAL_STORAGE in a fundamentally different approach to security. Instead of requesting access to the entire storage at once, SAF requests access only to a specific file. This minimizes the attack surface and increases user trust.
READ_EXTERNAL_STORAGE grants access to all files on the device, including photos and documents from other apps. On Android 10+, this approach is restricted. SAF, in contrast, provides access only to the file selected by the user and requires explicit confirmation for each file. For batch media operations, use MediaStore; for individual documents, use SAF.
The main disadvantage of SAF is the need to select each file individually. For bulk operations (backup, folder synchronization), ACTION_OPEN_DOCUMENT_TREE is used, which grants access to all files in the selected directory. The solution depends on the scenario: SAF is optimal for user selection, MediaStore is for programmatic media access.
Frequently Asked Questions
Storage Access Framework is an Android framework for secure file access through a system selection dialog. The app receives a content URI for the selected file without requesting broad storage read permissions.
Create an Intent with ACTION_OPEN_DOCUMENT, specify the MIME type via setType, and launch it through ActivityResultContracts. In the callback, get the URI from data.data and read via ContentResolver.openInputStream.
Persistent URI permissions is a mechanism for preserving access to a URI after the app restarts. It is requested via the FLAG_GRANT_PERSISTABLE_URI_PERMISSION flag and the takePersistableUriPermission method.
SAF supports any MIME types: application/pdf, image/*, text/plain, application/zip, and others. Types are specified via Intent.putExtra with an EXTRA_MIME_TYPES array.
SAF is designed for selecting individual files by the user through a system dialog. MediaStore provides programmatic access to all media files on the device through a media database without user interaction.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also