У нас есть приложение, которое использует внешнее хранилище для хранения некоторых временных файлов: изображений, двоичных данных. Код для этого работал несколько лет без больших изменений до недавнего времени. На Android Q это не работает:
File f = new File(Environment.getExternalStorageDirectory().toString() + File.separator + MainActivity.APP_DIR)
f.mkdirs();
// do sth with f
mkdirs теперь возвращает просто false.
Требуемое разрешение указано в манифесте:
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
Код отлично работает на предыдущих версиях Android. Есть ли какие-либо изменения на системном уровне для этого типа доступа? Если да, то каков обходной путь?
В Android Q были внесены огромные изменения в конфиденциальность, когда был введен Хранилище с заданным объемом.
Начиная с Q beta 4, можно сделать уклоняться этой функции следующим образом:
requestLegacyExternalStorage (при нацеливании на API 29):<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage = "true" ... >
...
</application>
</manifest>
редактировать:, как упоминалось в другом ответе, не работает, если приложение нацелено на API 30 — устройства Android 11 будут игнорировать устаревший флаг хранилища.
редактировать 2: предупреждает всех, кто планирует публиковать в магазине игр — скоро использование этого флага будет ограничено (новые и обновленные приложения не будут приниматься), если только это не требуется для основных функций (например, файлового менеджера).
Разве он не просит Android Pie? Но я думаю, что вы решаете проблемы, связанные с Android Q.
@Toaster, ты прав, я ответил поздно ночью. По какой-то странной причине я думал, что 9 уже Q.
Ха-ха, это нормально. Просто обновите ответ в свободное время.
@Pawel Похоже, не только ты был сонным, я не обратил внимания - изображение, которое я проверял, действительно было Q (эмулятор 9+). Проверил на 9 - все нормально, так что перефразируй вопрос и принимай
@khusrav вот что я думал, не видел причин, по которым этот код не работал бы на P, но знал, что в Q возникнут проблемы.
@khusrav Ну, это была катастрофа. :-D
Я обновил свою версию SDK до 29 и добавил этот атрибут, но все еще сталкиваюсь с той же проблемой. Есть ли что-то еще, что мне не хватает? моя версия андроида "10QP1A"
Да, у меня это работает, я только что добавил android:requestLegacyExternalStorage = "true" в API 29 или выше.
Обновлено: Начиная с Android 11 ограниченное хранилище принудительно. Приложения, предназначенные для Android 10 (уровень API 29), по-прежнему могут запрашивать атрибут requestLegacyExternalStorage. Этот флаг позволяет приложениям временно отказаться от изменений, связанных с хранилищем с заданной областью, таких как предоставление доступа к различным каталогам и различным типам медиафайлов. После того, как вы обновите свое приложение до Android 11, система игнорирует флаг requestLegacyExternalStorage.
В уровне API 29 прямой доступ к общим/внешним устройствам хранения не рекомендуется. Когда приложение нацелено на Build.VERSION_CODES.Q, путь, возвращаемый из метода getExternalStorageDirectory(), больше не доступен приложениям напрямую.
Приложения могут продолжать получать доступ к содержимому, хранящемуся в общем/внешнем хранилище, путем перехода на такие альтернативы, как Контекст # getExternalFilesDir (строка), Медиасторе или Намерение#ACTION_OPEN_DOCUMENT.
Рекомендуется использовать хранилище с ограниченной областью действия, если только вашему приложению не требуется доступ к файлу, который не находится в каталоге конкретного приложения.
Те, кто сталкивается с проблемой управления файлами в Android-Q, могут прочитать статью это, чтобы узнать больше.
@RonTLV Обновлен ответ с предварительным просмотром 3 изменений конфиденциальности для разработчиков Android11.
В новом обновлении Android API 30 писать можно только в app-specific files
File directory = new File(context.getFilesDir(), "YOUR_DIR");
directory.mkdirs();
или во внешнем хранилище вашего приложения Android/data
File directory = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
ОБНОВИТЬ
этот ответ предоставил другое решение https://stackoverflow.com/a/65744517/8195076
ОБНОВИТЬ
другой способ - предоставить это разрешение в manifest
<uses-permission android:name = "android.permission.MANAGE_EXTERNAL_STORAGE" />
нравится этот ответ https://stackoverflow.com/a/66968986/8195076
См. следующий ответ ниже: stackoverflow.com/a/50571167/3736063