Зовнішнє сховище на мобільних пристроях — це змінний носій даних, доступ до якого може отримати будь-який додаток із відповідними дозволами. За даними Android Open Source Project, 2026, починаючи з Android 10 Google впровадив Scoped Storage — модель, яка обмежує прямий доступ до файлової системи та вимагає використання MediaStore API для роботи зі спільними медіафайлами. Такий підхід підвищує безпеку користувацьких даних і запобігає витоку інформації між додатками.
Головне
READ_EXTERNAL_STORAGE та WRITE_EXTERNAL_STORAGE обов’язкові для Android 9 і нижчеЗовнішнє сховище — це область пам’яті, яка не входить до захищеної пісочниці додатка та доступна іншим програмам. На Android під цим терміном зазвичай розуміють SD-карту, але до зовнішнього сховища також належать USB-накопичувачі, підключені через OTG-адаптер, і хмарні диски, інтегровані на рівні файлової системи. Головна відмінність від Internal Storage — відсутність ізоляції: файли у зовнішньому сховищі може читати та змінювати будь-який додаток, який отримав відповідні дозволи.
На Android зовнішнє сховище представлене двома основними режимами: переносним (portable) і внутрішнім (adoptable). При форматуванні SD-карти як переносного сховища вона залишається з’ємною і форматується у FAT32 або exFAT. У режимі adoptable storage карта форматується в ext4 і шифрується з використанням AES-128, після чого система сприймає її як розширення внутрішньої пам’яті. Режим adoptable доступний починаючи з Android 6.0 Marshmallow, але виробники пристроїв часто відключають цю можливість у своїх прошивках. Згідно зі статистикою Google Play Console, лише близько 12% Android-пристроїв підтримують adoptable storage, тому покладатися на розширення внутрішньої пам’яті через SD-карту як єдиний варіант не рекомендується.
На iOS традиційних SD-карт немає. Apple використовує закриту архітектуру, де все зберігання будується на внутрішній флеш-пам’яті та iCloud. Зовнішні накопичувачі підтримуються через Lightning або USB-C порт, але доступ до них обмежений системним файловим менеджером Files і додатками, які інтегруються з Document Picker. Користувач сам вирішує, які файли відкривати із зовнішнього джерела — додаток не може сканувати підключений накопичувач без явної згоди.
Вибір зовнішнього носія залежить від вимог до швидкості, об’єму та портативності. Різні типи носіїв мають різні швидкісні характеристики, файлові системи та сценарії використання в мобільних додатках.
| Тип носія | Макс. об’єм | Швидкість читання | Файлова система |
|---|---|---|---|
| SD UHS-I | 2 ТБ | до 104 МБ/с | exFAT / FAT32 |
| SD UHS-II | 2 ТБ | до 312 МБ/с | exFAT / FAT32 |
| USB 3.0 OTG | 2 ТБ | до 400 МБ/с | exFAT / NTFS / FAT32 |
| USB-C SSD | 4 ТБ | до 1000 МБ/с | exFAT / APFS / NTFS |
SD-карти класифікуються за швидкістю запису: Class 10 (10 МБ/с), U1 (10 МБ/с), U3 (30 МБ/с), V30 (30 МБ/с) та V90 (90 МБ/с). Для запису відео 4K потрібна карта не нижче U3 або V30. Для мобільних додатків, які працюють з великими медіафайлами (обробка фото, відеомонтаж), рекомендується використовувати карти класу U3 і вище. Швидкість карти безпосередньо впливає на продуктивність додатка: запис 4K-відео на карту Class 10 може викликати пропуск кадрів через недостатню пропускну здатність. При виборі SD-карти для додатка звертайте увагу не лише на клас швидкості, а й на рейтинг Application Performance Class: A1 та A2 вказують на мінімальну продуктивність випадкового читання та запису, критичну для роботи баз даних і кешу додатків.
USB-OTG (On-The-Go) дозволяє підключати до мобільного пристрою зовнішні USB-накопичувачі через перехідник. Android підтримує OTG починаючи з версії 3.1, але для монтування накопичувача потрібне ядро з підтримкою файлової системи. FAT32 і exFAT підтримуються з коробки, NTFS — лише на пристроях з кастомним ядром або через бібліотеку Paragon. На iOS підтримка USB-накопичувачів з’явилася в iOS 13 разом із додатком Files. Для роботи з накопичувачем додаток повинен використовувати UIDocumentPickerViewController, який відкриває доступ лише до вибраних користувачем файлів — повний доступ до файлової системи накопичувача iOS не надає.
Хмарні сервіси — iCloud, Google Drive, Dropbox — можуть інтегруватися у файлову систему пристрою через системних провайдерів. На iOS iCloud Drive є частиною Sandbox-контейнера додатка, і файли автоматично синхронізуються між пристроями користувача. На Android Google Drive надає API для читання та запису файлів, але прямого монтування у файлову систему не відбувається. Для мобільних додатків, які працюють з великими обсягами даних, хмарне сховище може служити альтернативою SD-карті, особливо на пристроях без слота розширення.
Робота із зовнішнім сховищем на Android залежить від версії операційної системи та моделі Scoped Storage. Процес доступу до файлів різниться для Android 9 і нижче, Android 10–12 та Android 13+.
Починаючи з Android 10, основний спосіб доступу до спільних медіафайлів — MediaStore API. Цей API надає уніфікований інтерфейс для читання та запису зображень, відео та аудіофайлів у спільному сховищі. Додаток не вимагає дозволу READ_EXTERNAL_STORAGE для доступу до власних файлів, але для читання файлів інших додатків, як і раніше, потрібен явний дозвіл користувача. MediaStore автоматично індексує медіафайли та надає ContentResolver для їх запиту.
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)
Після виконання запиту ви отримуєте Cursor, що містить URI файлів. Для читання файлу відкрийте InputStream через contentResolver.openInputStream(uri). Запис виконується аналогічно через contentResolver.openOutputStream(uri). MediaStore автоматично обробляє конфлікти імен і надає можливість вставки нових файлів через contentResolver.insert(uri, values), який повертає URI створеного файлу.
Storage Access Framework (SAF) — рекомендований спосіб доступу до довільних файлів на Android 10+. SAF надає системний діалог вибору файлів, через який користувач дає додатку доступ до конкретного файлу або директорії. Додаток отримує URI доступу, який діє до перезавантаження пристрою або до явного відкликання дозволу через налаштування. SAF не вимагає дозволів READ_EXTERNAL_STORAGE або WRITE_EXTERNAL_STORAGE, що спрощує публікацію в Google Play і знижує кількість запитів дозволів.
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)
На iOS робота із зовнішніми файлами будується через UIDocumentPickerViewController, який користувач відкриває для вибору конкретних файлів або директорій. Додаток не має прямого доступу до файлової системи зовнішнього накопичувача — лише до тих файлів, які користувач явно вибрав. Після вибору файлу додаток отримує тимчасовий URL-адресу в Sandbox-контейнері та може працювати з файлом через FileManager.
UIDocumentPickerViewController дозволяє користувачеві вибрати один або кілька файлів із будь-якого доступного джерела: iCloud Drive, підключеного USB-накопичувача, стороннього хмарного сервісу. Після вибору контролер повертає масив URL-адрес, які додаток може прочитати протягом сесії. Для збереження доступу після закриття додатка необхідно викликати startAccessingSecurityScopedResource() і зберегти security-scoped bookmark у 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)
}
Параметр asCopy: true означає, що iOS скопіює файл у Sandbox-контейнер додатка, і додаток отримає власну копію, незалежну від вихідного файлу. Якщо вказати asCopy: false, додаток отримує посилання на оригінальний файл, але для доступу до нього необхідно викликати url.startAccessingSecurityScopedResource(). Без цього виклику читання файлу викличе виняток. Після завершення роботи з файлом обов’язково викличте url.stopAccessingSecurityScopedResource(), щоб закрити ресурс і запобігти витоку дескрипторів.
Безпека зовнішнього сховища нижча, ніж у Internal Storage, оскільки файли доступні іншим додаткам. Будь-який додаток із дозволом READ_EXTERNAL_STORAGE може прочитати всі файли на SD-карті, включаючи ті, які ваш додаток створив для тимчасового зберігання конфіденційних даних. Зловмисний додаток може просканувати SD-карту та витягти користувацькі дані, якщо вони не зашифровані. Тому категорично не рекомендується зберігати токени аутентифікації, паролі або персональні дані користувача у зовнішньому сховищі у відкритому вигляді.
На Android 10+ Scoped Storage суттєво обмежує можливості додатків щодо доступу до спільної файлової системи. Додаток може без дозволу читати лише файли, створені ним самим, а для доступу до файлів інших додатків потрібна явна згода користувача через SAF-діалог. Однак це обмеження не поширюється на додатки з цільовою версією SDK нижче 29 — вони продовжують працювати за старою моделлю, що створює ризик для користувачів, які не оновили додатки. Google Play з 2021 року вимагає targetSdkVersion 29+ для всіх нових і оновлюваних додатків.
Форматування та шифрування — ще один важливий аспект безпеки. SD-карта, відформатована як переносне сховище, не шифрується системою за замовчуванням. Навіть при використанні adoptable storage шифрування активується лише якщо виробник пристрою включив цю можливість у прошивці. Для захисту конфіденційних даних, що зберігаються на зовнішньому сховищі, використовуйте бібліотеку EncryptedFile з AndroidX Security, яка шифрує кожен файл окремо з використанням AES256-GCM, незалежно від системного шифрування.
Ефективне використання зовнішнього сховища вимагає балансу між доступністю даних та безпекою. Дотримуйтесь наступних правил для забезпечення надійного зберігання користувацьких файлів.
Environment.getExternalStorageState() для перевірки стану SD-карти. Карта може бути витягнута, пошкоджена або недоступна для записуВажливо пам’ятати, що зовнішнє сховище не гарантує збереження даних при збоях. SD-карти мають обмежений ресурс циклів перезапису, особливо бюджетні моделі класу Class 4 та Class 6. При інтенсивному записі (наприклад, логування або кешування потокових даних) карта може вийти з ладу протягом кількох місяців. Для таких сценаріїв використовуйте внутрішню пам’ять або хмарне сховище, а на зовнішньому сховищі зберігайте лише файли, втрату яких користувач вважатиме прийнятною. Регулярно перевіряйте стан SD-карти через StatFs та повідомляйте користувача про критичні помилки файлової системи.
Часті запитання
На Android 13+ дозвіл READ_EXTERNAL_STORAGE замінено на більш гранулярні: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO та READ_MEDIA_AUDIO. Для доступу до інших типів файлів використовуйте SAF.
Так, функція adoptable storage доступна на Android 6.0+. Карта форматується в ext4 з шифруванням AES-128. Однак багато виробників відключають цю опцію, і близько 88% пристроїв не підтримують adoptable storage.
Використовуйте метод Environment.getExternalStorageState(), який повертає рядок стану. Значення MEDIA_MOUNTED означає, що карта доступна для читання та запису. Інші значення вказують на помилки або відсутність карти.
Scoped Storage обмежує додаток його власним контейнером та спільними медіатеками MediaStore. Повний доступ дозволяє читання будь-яких файлів на пристрої. Scoped Storage підвищує безпеку користувацьких даних і обов’язковий для нових додатків.
Запустіть Intent з дією ACTION_OPEN_DOCUMENT_TREE, який відкриє системний діалог вибору директорії. Після вибору ви отримаєте URI-дозвіл, що діє до перезавантаження. Збережіть цей URI в SharedPreferences для подальшого використання.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також