Задний план
На Android 4.4 (KitKat) Google сделал доступ к SD-карте весьма ограниченным.
Начиная с Android Lollipop (5.0), разработчики могут использовать новый API, который запрашивает у пользователя подтверждение разрешения доступа к определенным папкам, как написано в этом сообщении групп Google. .
Эта проблема
Сообщение предлагает вам посетить два веб-сайта:
Это похоже на внутренний пример (возможно, будет показан позже в демонстрациях API), но понять, что происходит, довольно сложно.
Это официальная документация нового API, но в ней недостаточно подробностей о том, как его использовать.
Вот что он вам говорит:
Если вам действительно нужен полный доступ ко всему поддереву документов, начните с запуска ACTION_OPEN_DOCUMENT_TREE, чтобы пользователь мог выбрать каталог. Затем передайте полученный getData () в fromTreeUri (Context, Uri), чтобы начать работу с выбранным пользователем деревом.
Когда вы перемещаетесь по дереву экземпляров DocumentFile, вы всегда можете использовать getUri () для получения Uri, представляющего базовый документ для этого объекта, для использования с openInputStream (Uri) и т. Д.
Чтобы упростить код на устройствах с KITKAT или более ранней версией, вы можете использовать fromFile (File), который имитирует поведение DocumentsProvider.
Вопросы
У меня есть несколько вопросов о новом API:
- Как вы на самом деле это используете?
- Согласно сообщению, ОС будет помнить, что приложению было предоставлено разрешение на доступ к файлам / папкам. Как проверить, есть ли у вас доступ к файлам / папкам? Есть ли функция, которая возвращает мне список файлов / папок, к которым я могу получить доступ?
- Как вы справляетесь с этой проблемой на Kitkat? Это часть библиотеки поддержки?
- Есть ли в ОС экран настроек, показывающий, какие приложения имеют доступ к каким файлам / папкам?
- Что произойдет, если приложение установлено для нескольких пользователей на одном устройстве?
- Есть ли еще какая-либо документация / руководство по этому новому API?
- Можно ли отозвать разрешения? Если да, то отправляется ли в приложение намерение?
- Будет ли запрос разрешения работать рекурсивно для выбранной папки?
- Может ли использование разрешения дать пользователю возможность множественного выбора по выбору пользователя? Или приложению нужно специально указывать намерение, какие файлы / папки разрешить?
- Есть ли способ на эмуляторе попробовать новый API? Я имею в виду, что у него есть раздел SD-карты, но он работает как основное внешнее хранилище, поэтому весь доступ к нему уже предоставлен (с использованием простого разрешения).
- Что происходит, когда пользователь заменяет SD-карту другой?
источник
Ответы:
Много хороших вопросов, давайте углубимся. :)
Как Вы этим пользуетесь?
Вот отличный учебник по взаимодействию с Storage Access Framework в KitKat:
https://developer.android.com/guide/topics/providers/document-provider.html#client
Взаимодействие с новыми API в Lollipop очень похоже. Чтобы предложить пользователю выбрать дерево каталогов, вы можете запустить такое намерение:
Затем в своем onActivityResult () вы можете передать выбранный пользователем Uri новому вспомогательному классу DocumentFile. Вот краткий пример, в котором перечислены файлы в выбранном каталоге, а затем создается новый файл:
Возвращаемый Uri
DocumentFile.getUri()
достаточно гибкий для использования с API различных платформ. Например, вы можете поделиться им сIntent.setData()
помощьюIntent.FLAG_GRANT_READ_URI_PERMISSION
.Если вы хотите получить доступ к этому Uri из собственного кода, вы можете вызвать,
ContentResolver.openFileDescriptor()
а затем использоватьParcelFileDescriptor.getFd()
илиdetachFd()
для получения традиционного целого числа файлового дескриптора POSIX.Как проверить, есть ли у вас доступ к файлам / папкам?
По умолчанию Uris, возвращаемый через намерения Storage Access Framework, не сохраняется при перезагрузке. Платформа «предлагает» возможность сохранить разрешение, но вам все равно нужно «взять» разрешение, если вы этого хотите. В нашем примере выше вы бы позвонили:
Вы всегда можете выяснить, к каким постоянным грантам ваше приложение имеет доступ через
ContentResolver.getPersistedUriPermissions()
API. Если вам больше не нужен доступ к постоянному URI, вы можете освободить его с помощьюContentResolver.releasePersistableUriPermission()
.Это доступно на KitKat?
Нет, мы не можем задним числом добавлять новые функции в старые версии платформы.
Могу ли я узнать, какие приложения имеют доступ к файлам / папкам?
В настоящее время нет пользовательского интерфейса, показывающего это, но вы можете найти подробности в разделе
adb shell dumpsys activity providers
вывода «Предоставленные разрешения Uri» .Что произойдет, если приложение установлено для нескольких пользователей на одном устройстве?
Предоставления разрешений Uri изолированы для каждого пользователя, как и все другие функции многопользовательской платформы. То есть одно и то же приложение, работающее под двумя разными пользователями, не имеет перекрывающихся или общих разрешений Uri.
Можно ли отозвать разрешения?
Поддерживающий DocumentProvider может отозвать разрешение в любое время, например, при удалении облачного документа. Самый распространенный способ обнаружить эти отозванные разрешения - это когда они исчезают из
ContentResolver.getPersistedUriPermissions()
упомянутого выше.Разрешения также аннулируются всякий раз, когда данные приложения удаляются для любого приложения, участвующего в гранте.
Будет ли запрос разрешения работать рекурсивно для выбранной папки?
Да,
ACTION_OPEN_DOCUMENT_TREE
намерение дает вам рекурсивный доступ как к существующим, так и к вновь созданным файлам и каталогам.Разрешает ли это множественный выбор?
Да, множественный выбор поддерживается начиная с KitKat, и вы можете разрешить его, установив
EXTRA_ALLOW_MULTIPLE
при запуске вашегоACTION_OPEN_DOCUMENT
намерения. Вы можете использоватьIntent.setType()
или,EXTRA_MIME_TYPES
чтобы сузить типы файлов, которые можно выбрать:http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT
Есть ли способ на эмуляторе попробовать новый API?
Да, основное общее запоминающее устройство должно появиться в средстве выбора даже в эмуляторе. Если ваше приложение использует только Storage Access Framework для доступа к общему хранилищу, вам больше не нужны
READ/WRITE_EXTERNAL_STORAGE
разрешения вообще, и вы можете удалить их или использовать этуandroid:maxSdkVersion
функцию, чтобы запрашивать их только в более старых версиях платформы.Что происходит, когда пользователь заменяет SD-карту на другую?
Когда задействован физический носитель, UUID (например, серийный номер FAT) основного носителя всегда записывается в возвращаемый Uri. Система использует это для подключения вас к носителю, изначально выбранному пользователем, даже если пользователь переключает носитель между несколькими слотами.
Если пользователь меняет вторую карту, вам нужно будет запросить доступ к новой карте. Поскольку система запоминает гранты для каждого UUID, вы по-прежнему будете иметь ранее предоставленный доступ к исходной карте, если пользователь повторно вставит ее позже.
http://en.wikipedia.org/wiki/Volume_serial_number
источник
В моем проекте Android в Github, ссылка на который приведена ниже, вы можете найти рабочий код, который позволяет писать на extSdCard в Android 5. Он предполагает, что пользователь дает доступ ко всей SD-карте, а затем позволяет вам писать везде на этой карте. (Если вы хотите иметь доступ только к отдельным файлам, все станет проще.)
Фрагменты основного кода
Запуск инфраструктуры доступа к хранилищу:
Обработка ответа от Storage Access Framework:
Получение outputStream для файла через Storage Access Framework (с использованием сохраненного URL-адреса, предполагая, что это URL-адрес корневой папки внешней SD-карты)
При этом используются следующие вспомогательные методы:
Ссылка на полный код
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/fragments/SettingsFragment.java#L521
и
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java
источник
File
254 раза. Вы можете себе представить, как это исправить ?? Android становится кошмаром для разработчиков из-за полного отсутствия обратной совместимости. Я до сих пор не нашел места, где бы объяснили, почему Google принял все эти глупые решения относительно внешнего хранилища. Некоторые заявляют о «безопасности», но это, конечно, ерунда, поскольку любое приложение может испортить внутреннюю память. Я предполагаю, что попытаться заставить нас использовать их облачные сервисы. К счастью, рутирование решает проблемы ... по крайней мере, для Android <6 ....Это просто дополнительный ответ.
После создания нового файла вам может потребоваться сохранить его местоположение в базе данных и прочитать его завтра. Вы можете прочитать и получить его снова, используя этот метод:
источник