Резюме
Ви можете надати доступ для читання / запису на зовнішню SD-карту на різних рівнях API ( API23 + під час роботи ).
Починаючи з KitKat, дозволи не потрібні, якщо ви використовуєте конкретні додатки, що вимагається в іншому випадку.
Універсальний спосіб:
Історія говорить , що не існує універсального способу для запису зовнішньої SD - карти , але по- , як і раніше ...
Цей факт демонструється цими прикладами конфігурацій зовнішнього сховища для пристроїв .
Шлях на основі API:
До KitKat спробуйте використовувати метод Doomsknight 1, метод 2 інакше.
Запит дозволів у маніфесті (Api <23) та під час виконання (Api> = 23).
Рекомендований спосіб:
ContextCompat.getExternalFilesDirs вирішує помилку доступу, коли не потрібно надавати спільний доступ до файлів.
Безпечний спосіб спільного використання - це використання постачальника вмісту або нової системи доступу до сховищ .
Конфіденційність:
Починаючи з Android Q Beta 4 , програми, націлені на Android 9 (рівень API 28) або нижче, за замовчуванням не бачать змін.
Програми, націлені на Android Q за замовчуванням (або ввімкнути його), отримують відфільтрований вигляд у зовнішню пам’ять.
1. Початкова відповідь.
Універсальний спосіб запису на зовнішню SD-карту на Android
Там немає універсального способу , щоб написати на зовнішню SD - карту на Android з - за постійні зміни :
Pre-KitKat: офіційна платформа Android взагалі не підтримує SD-карти, крім винятків.
KitKat: представив API, які дозволяють програмам отримувати доступ до файлів у відповідних каталогах програм на SD-картах.
Lollipop: додані API, що дозволяють програмам запитувати доступ до папок, що належать іншим провайдерам.
Нуга: забезпечив спрощений API для доступу до загальних каталогів зовнішнього сховища.
... Зміна конфіденційності Android Q: сховище з додатками та медіа
Який найкращий спосіб надати доступ для читання / запису до зовнішньої SD-карти на різних рівнях API
На основі відповіді Doomsknight і моєї , а також повідомлень у Дейві Сміті та Марку Мерфі: 1 , 2 , 3 :
2. Оновлена відповідь.
Оновлення 1 . Я спробував метод 1 із відповіді Doomknight, безрезультатно:
Як бачите, я перевіряю наявність дозволів під час виконання перед спробою писати на SD ...
Я б використовував специфічні для програми каталоги, щоб уникнути проблеми з вашим оновленим запитанням та ContextCompat.getExternalFilesDirs()
використовувати документацію getExternalFilesDir як посилання.
Покращити евристику, щоб визначити, що являє собою знімні носії на основі різних рівнів APIandroid.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
... Але я отримую помилку доступу, яку пробували на двох різних пристроях: HTC10 і Shield K1.
Пам'ятайте, що Android 6.0 підтримує портативні пристрої зберігання даних, а сторонні програми повинні проходити через Storage Access Framework . Ваші пристрої HTC10 і Shield K1 , ймовірно, є API 23.
У вашому журналі відображається дозвіл на відмову у доступі до винятків/mnt/media_rw
, як це виправлення для API 19+:
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_r" />
<group gid="sdcard_rw" />
<group gid="media_rw" />
</permission>
Я ніколи не пробував, тому я не можу ділитися кодом, але я б уникав for
спроб писати у всіх повернутих каталогах і шукав найкращий доступний каталог зберігання для запису на основі залишку місця .
Можливо , альтернатива Gizm0 вашому getStorageDirectories()
методу - це хороша відправна точка.
ContextCompat.getExternalFilesDirs
вирішує проблему, якщо вам не потрібен доступ до інших папок .
3. Android 1.0 .. Pre-KitKat.
До KitKat спробуйте скористатися методом Doomsknight 1 або прочитайте цю відповідь від Gnathonic.
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
}
Додайте наступний код до свого AndroidManifest.xml
і прочитайте Отримання доступу до зовнішнього сховища
Доступ до зовнішнього сховища захищений різними дозволами Android.
Починаючи з Android 1.0, доступ до запису захищений з WRITE_EXTERNAL_STORAGE
дозволу .
Починаючи з Android 4.1, доступ для читання захищений з READ_EXTERNAL_STORAGE
дозволу.
Для того, щоб ... писати файли на зовнішній пам'яті, ваш додаток повинен отримати ... системні дозволи:
<manifest ...>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Якщо вам потрібно обидва ..., вам потрібно попросити лише WRITE_EXTERNAL_STORAGE
дозволу.
Прочитайте пояснення Марка Мерфі і рекомендує Дайан Hackborn і Dave Smith повідомлень
- До Android 4.4 офіційна підтримка знімних носіїв в Android не існувала. Починаючи з KitKat, в API FMW з’являється концепція „первинного” та „вторинного” зовнішнього сховища.
- Попередні програми просто покладаються на індексацію MediaStore, постачають разом із апаратним забезпеченням або вивчають точки монтування та застосовують деякі евристики для визначення того, що представляє собою знімний носій.
Ігноруйте наступну примітку через помилки, але спробуйте використати ContextCompat.getExternalFilesDirs()
:
- Починаючи з Android 4.2, від Google надійшов запит виробників пристроїв заблокувати знімні носії для безпеки (підтримка кількох користувачів), а нові тести були додані в 4.4.
- З KitKat
getExternalFilesDirs()
та інші методи були додані для повернення корисного шляху на всіх доступних томах сховища (Перший повернутий елемент - це основний том).
- У таблиці нижче вказано, що може спробувати зробити розробник, і як відповість KitKat:
Примітка. Починаючи з Android 4.4, ці дозволи не потрібні, якщо ви читаєте або пишете лише файли, приватні для вашої програми. Для отримання додаткової інформації ... див. Збереження файлів, які є приватними для програми .
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
</manifest>
Також прочитайте пояснення Паоло Ровеллі та спробуйте використати рішення Джеффа Шаркі починаючи з KitKat:
Зараз у KitKat є загальнодоступний API для взаємодії з цими вторинними спільними пристроями зберігання.
Новий Context.getExternalFilesDirs()
і
Context.getExternalCacheDirs()
методи можуть повертати кілька шляхів, включаючи як основні, так і вторинні пристрої.
Потім ви можете переглядати їх і перевіряти Environment.getStorageState()
і
File.getFreeSpace()
визначати найкраще місце для зберігання ваших файлів.
Ці методи також доступні на ContextCompat
в бібліотеці support-v4.
Починаючи з Android 4.4, власник, група та режими файлів на зовнішніх пристроях зберігання даних синтезуються на основі структури каталогів. Це дає змогу програмам керувати своїми каталогами для конкретних пакетів на зовнішньому сховищі, не вимагаючи широкого
WRITE_EXTERNAL_STORAGE
дозволу. Наприклад, програма з назвою пакета com.example.foo
тепер може вільно отримувати доступ
Android/data/com.example.foo/
до зовнішніх пристроїв зберігання даних без дозволів. Ці синтезовані дозволи виконуються шляхом загортання необроблених пристроїв зберігання в демон FUSE.
З KitKat ваші шанси на "повне рішення" без укорінення майже нульові:
Проект Android тут точно зіпсувався. Жоден додаток не отримує повного доступу до зовнішніх карт SD:
- файлові менеджери: ви не можете використовувати їх для управління зовнішньою SD-картою. У більшості областей вони вміють лише читати, але не писати.
- мультимедійні програми: ви більше не можете повторно позначати / реорганізовувати свою колекцію медіа, оскільки ці програми не можуть писати на неї.
- офісні програми: майже те саме
Єдине місце, де додатки третьої сторони дозволяють писати на зовнішній картці - це "власні каталоги" (тобто
/sdcard/Android/data/<package_name_of_the_app>
).
Єдині способи по-справжньому виправити, що вимагає або виробник (деякі з них виправили це, наприклад, Huawei з оновленням Kitkat для P6) - або root ... (пояснення Іззі продовжується тут)
5. Android 5.0 представив зміни та допоміжний клас DocumentFile .
getStorageState
Додано в API 19, застаріле в API 21,
використанняgetExternalStorageState(File)
Ось чудовий підручник для взаємодії з Framework Storage Access у KitKat.
Взаємодія з новими API в Lollipop дуже схожа (пояснення Джеффа Шаркі) .
6. Android 6.0 Marshmallow представляє нову модель дозволів на виконання .
Запитуйте дозволи під час виконання, якщо рівень API 23+, і читайте Запит дозволів під час виконання
Починаючи з Android 6.0 (рівень API 23), користувачі надають дозволи програмам під час запуску програми, а не тоді, коли вони встановлюють програму ... або оновлюють програму ... користувач може скасувати дозволи.
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
Android 6.0 представляє нову модель дозволів на виконання, коли програми вимагають можливості за потреби під час виконання. Оскільки нова модель включає READ/WRITE_EXTERNAL_STORAGE
дозволи, платформа повинна динамічно надавати доступ до сховища, не вбиваючи та не перезапускаючи вже запущені програми. Це робиться завдяки підтримці трьох різних видів усіх змонтованих пристроїв зберігання даних:
- / mnt / runtime / default відображається програмам без спеціальних дозволів на зберігання ...
- / mnt / runtime / read відображається програмам із READ_EXTERNAL_STORAGE
- / mnt / runtime / write відображається у програмах із WRITE_EXTERNAL_STORAGE
7. Android 7.0 надає спрощений API для доступу до зовнішніх папок сховища.
Обмежений доступ до каталогів
У Android 7.0 програми можуть використовувати нові API для запиту доступу до певного
зовнішнього сховища каталогів , включаючи каталоги на знімних носіях, таких як SD-карти ...
Для отримання додаткової інформації дивіться навчальний посібник Scoped Directory Access .
Прочитайте публікації Марка Мерфі: Будьте обережні з обмеженим доступом до каталогів . Це застаріло в Android Q :
Зверніть увагу, що доданий у 7.0 доступ до каталогів із обмеженими можливостями застарілий в Android Q.
Зокрема, createAccessIntent()
метод StorageVolume застарілий.
Вони додали, createOpenDocumentTreeIntent()
що можна використовувати як альтернативу.
8. Android 8.0 Oreo .. Зміни бета-версії Android Q.
Починаючи з Android O , Storage Access Framework дозволяє постачальникам користувацьких документів
створювати доступні дескриптори файлів для файлів, що перебувають у віддаленому джерелі даних ...
Права доступу ,
до Android O , якщо додаток запросив дозвіл під час виконання і дозвіл було отримано, система також неправильно надав АРР , інші дозволи, які належали до тієї ж групи дозволів, і які були зареєстровані в маніфесті.
Для програм, націлених на Android O , цю поведінку виправлено. Додаток отримує лише ті дозволи, які він прямо просив. Однак, як тільки користувач надає дозвіл додатку, усі подальші запити на отримання дозволів у цій групі дозволів автоматично надаються.
Наприклад, READ_EXTERNAL_STORAGE
і WRITE_EXTERNAL_STORAGE
...
Оновлення: Android Q раніше бета - версія тимчасово замінила READ_EXTERNAL_STORAGE
і WRITE_EXTERNAL_STORAGE
дозвіл з більш дрібнозернистими, медіа-конкретних дозволами.
Примітка: Google представив ролі в Beta 1 і вилучив їх із документації до Beta 2 ...
Примітка: права доступу до конкретних медіаколекції , які були введені в попередніх бета releases- READ_MEDIA_IMAGES
, READ_MEDIA_AUDIO
і READ_MEDIA_VIDEO
- в даний час застаріло . Більше інформації:
Q Beta 4 (останні API) огляд Марка Мерфі: Смерть зовнішнього сховища: Кінець саги (?)
"Смерть є універсальнішою за життя. Всі вмирають, але не всі живуть". - Ендрю Сакс
9. Пов’язані запитання та рекомендовані відповіді.
Як отримати зовнішній шлях до SD-карти для Android 4.0+?
mkdir () працює всередині внутрішньої флеш-пам'яті, але не SD-карти?
Різниця між getExternalFilesDir і getExternalStorageDirectory ()
Чому getExternalFilesDirs () не працює на деяких пристроях?
Як користуватися новим API доступу до SD-карти, представленим для Android 5.0 (Lollipop)
Запис на зовнішню SD-карту в Android 5.0 та новіших версіях
Дозвіл на запис на SD-карту Android за допомогою SAF (Framework Access Framework)
SAFFAQ: Поширені запитання про Framework Access Framework
10. Пов’язані помилки та проблеми.
Помилка: На Android 6 під час використання getExternalFilesDirs це не дозволить створювати нові файли в його результатах
Запис у каталог, повернутий getExternalCacheDir () на Lollipop, неможливий без дозволу на запис