External storage on mobile devices is a removable data medium that any application with the appropriate permissions can access. According to the Android Open Source Project, 2026, starting with Android 10, Google introduced Scoped Storage — a model that restricts direct access to the file system and requires the use of MediaStore API for working with shared media files. This approach enhances the security of user data and prevents information leakage between applications.
Key Takeaways
READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are required for Android 9 and belowExternal storage is a memory area that is not part of the application’s protected sandbox and is accessible to other programs. On Android, this term typically refers to the SD card, but external storage also includes USB drives connected via an OTG adapter and cloud drives integrated at the file system level. The main difference from Internal Storage is the lack of isolation: any application with the appropriate permissions can read and modify files in external storage.
On Android, external storage comes in two main modes: portable and adoptable. When an SD card is formatted as portable storage, it remains removable and is formatted in FAT32 or exFAT. In adoptable storage mode, the card is formatted in ext4 and encrypted using AES-128, after which the system treats it as an extension of internal memory. Adoptable mode has been available since Android 6.0 Marshmallow, but device manufacturers often disable this feature in their firmware. According to Google Play Console statistics, only about 12% of Android devices support adoptable storage, so relying on expanding internal memory via SD card as the sole option is not recommended.
On iOS, traditional SD cards are not available. Apple uses a closed architecture where all storage is built on internal flash memory and iCloud. External drives are supported via the Lightning or USB-C port, but access to them is limited to the system file manager Files and applications that integrate with Document Picker. The user decides which files to open from an external source — the application cannot scan a connected drive without explicit consent.
The choice of external media depends on requirements for speed, capacity, and portability. Different types of media have varying speed characteristics, file systems, and use cases in mobile applications.
| Media Type | Max Capacity | Read Speed | File System |
|---|---|---|---|
| SD UHS-I | 2 TB | up to 104 MB/s | exFAT / FAT32 |
| SD UHS-II | 2 TB | up to 312 MB/s | exFAT / FAT32 |
| USB 3.0 OTG | 2 TB | up to 400 MB/s | exFAT / NTFS / FAT32 |
| USB-C SSD | 4 TB | up to 1000 MB/s | exFAT / APFS / NTFS |
SD cards are classified by write speed: Class 10 (10 MB/s), U1 (10 MB/s), U3 (30 MB/s), V30 (30 MB/s), and V90 (90 MB/s). Recording 4K video requires a card of at least U3 or V30. For mobile applications working with large media files (photo processing, video editing), it is recommended to use U3 class cards and above. The card speed directly affects application performance: recording 4K video on a Class 10 card can cause frame drops due to insufficient bandwidth. When choosing an SD card for an application, pay attention not only to the speed class but also to the Application Performance Class rating: A1 and A2 indicate the minimum random read and write performance critical for database and application cache operations.
USB-OTG (On-The-Go) allows connecting external USB drives to a mobile device via an adapter. Android has supported OTG since version 3.1, but mounting the drive requires a kernel with file system support. FAT32 and exFAT are supported out of the box, NTFS — only on devices with a custom kernel or through the Paragon library. On iOS, USB drive support appeared in iOS 13 with the Files application. To work with a drive, an application must use UIDocumentPickerViewController, which provides access only to files selected by the user — iOS does not grant full access to the drive’s file system.
Cloud services — iCloud, Google Drive, Dropbox — can integrate into the device’s file system through system providers. On iOS, iCloud Drive is part of the application’s Sandbox container, and files are automatically synchronized between the user’s devices. On Android, Google Drive provides an API for reading and writing files, but direct mounting into the file system does not occur. For mobile applications working with large amounts of data, cloud storage can serve as an alternative to an SD card, especially on devices without an expansion slot.
Working with external storage on Android depends on the operating system version and the Scoped Storage model. The file access process differs for Android 9 and below, Android 10–12, and Android 13+.
Starting with Android 10, the primary way to access shared media files is the MediaStore API. This API provides a unified interface for reading and writing images, videos, and audio files in shared storage. An application does not require READ_EXTERNAL_STORAGE permission to access its own files, but reading files from other applications still requires explicit user permission. MediaStore automatically indexes media files and provides a ContentResolver for querying them.
val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME
)
val cursor = contentResolver.query(collection, projection, null, null, null)
After executing the query, you receive a Cursor containing the URIs of the files. To read a file, open an InputStream via contentResolver.openInputStream(uri). Writing is done similarly through contentResolver.openOutputStream(uri). MediaStore automatically handles name conflicts and provides the ability to insert new files via contentResolver.insert(uri, values), which returns the URI of the created file.
Storage Access Framework (SAF) is the recommended way to access arbitrary files on Android 10+. SAF provides a system file picker dialog through which the user grants the application access to a specific file or directory. The application receives an access URI that remains valid until the device is rebooted or until the permission is explicitly revoked in settings. SAF does not require READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE permissions, which simplifies publishing on Google Play and reduces the number of permission requests.
val requestCode = 42
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
startActivityForResult(intent, requestCode)
On iOS, working with external files is built around UIDocumentPickerViewController, which the user opens to select specific files or directories. The application does not have direct access to the external drive’s file system — only to the files that the user explicitly selected. After file selection, the application receives a temporary URL in the Sandbox container and can work with the file through FileManager.
UIDocumentPickerViewController allows the user to select one or more files from any available source: iCloud Drive, a connected USB drive, or a third-party cloud service. After selection, the controller returns an array of URLs that the application can read during the session. To retain access after the application closes, you must call startAccessingSecurityScopedResource() and save a security-scoped bookmark in UserDefaults.
let picker = UIDocumentPickerViewController(
forOpeningContentTypes: [.data, .image],
asCopy: true
)
picker.delegate = self
func documentPicker(
controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]
) {
guard let url = urls.first else { return }
let data = try Data(contentsOf: url)
}
The parameter asCopy: true means that iOS will copy the file into the application’s Sandbox container, and the application will get its own copy independent of the original file. If asCopy: false is specified, the application receives a reference to the original file, but to access it, url.startAccessingSecurityScopedResource() must be called. Without this call, reading the file will throw an exception. After finishing work with the file, always call url.stopAccessingSecurityScopedResource() to release the resource and prevent descriptor leaks.
The security of external storage is lower than that of Internal Storage because files are accessible to other applications. Any application with READ_EXTERNAL_STORAGE permission can read all files on the SD card, including those your application created for temporarily storing sensitive data. A malicious application could scan the SD card and extract user data if it is not encrypted. Therefore, it is strongly recommended not to store authentication tokens, passwords, or personal user data in external storage in plain text.
On Android 10+, Scoped Storage significantly limits applications’ ability to access the shared file system. An application can only read files it created itself without permission, and accessing files from other applications requires explicit user consent through the SAF dialog. However, this restriction does not apply to applications with a target SDK version below 29 — they continue to work under the old model, creating a risk for users who have not updated their applications. Google Play has required targetSdkVersion 29+ for all new and updated applications since 2021.
Formatting and encryption are another important security aspect. An SD card formatted as portable storage is not encrypted by the system by default. Even when using adoptable storage, encryption is only activated if the device manufacturer has enabled this feature in the firmware. To protect sensitive data saved on external storage, use the EncryptedFile library from AndroidX Security, which encrypts each file separately using AES256-GCM, regardless of system encryption.
Effective use of external storage requires a balance between data availability and security. Follow these rules to ensure reliable storage of user files.
Environment.getExternalStorageState() to check the SD card status. The card may be removed, damaged, or unavailable for writingIt is important to remember that external storage does not guarantee data integrity during failures. SD cards have a limited number of rewrite cycles, especially budget models of Class 4 and Class 6. With intensive writing (for example, logging or caching streaming data), a card may fail within a few months. For such scenarios, use internal memory or cloud storage, and save only files on external storage whose loss the user would consider acceptable. Regularly check the SD card status via StatFs and notify the user about critical file system errors.
Frequently Asked Questions
On Android 13+, the READ_EXTERNAL_STORAGE permission has been replaced with more granular ones: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, and READ_MEDIA_AUDIO. For other file types, use SAF.
Yes, the adoptable storage feature is available on Android 6.0+. The card is formatted in ext4 with AES-128 encryption. However, many manufacturers disable this option, and about 88% of devices do not support adoptable storage.
Use the Environment.getExternalStorageState() method, which returns a status string. The value MEDIA_MOUNTED means the card is available for reading and writing. Other values indicate errors or the absence of a card.
Scoped Storage restricts the application to its own container and shared MediaStore media galleries. Full access allows reading any files on the device. Scoped Storage enhances user data security and is mandatory for new applications.
Launch an Intent with the ACTION_OPEN_DOCUMENT_TREE action, which opens a system directory picker dialog. After selection, you receive a URI permission valid until reboot. Save this URI in SharedPreferences for later use.
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