Много хороших вопросов, давайте углубимся. :)
Как Вы этим пользуетесь?
Вот отличный учебник по взаимодействию с Storage Access Framework в KitKat:
https://developer.android.com/guide/topics/providers/document-provider.html#client
Взаимодействие с новыми API в Lollipop очень похоже. Чтобы предложить пользователю выбрать дерево каталогов, вы можете запустить такое намерение:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
Затем в своем onActivityResult () вы можете передать выбранный пользователем Uri новому вспомогательному классу DocumentFile. Вот краткий пример, в котором перечислены файлы в выбранном каталоге, а затем создается новый файл:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
// List all existing files inside picked directory
for (DocumentFile file : pickedDir.listFiles()) {
Log.d(TAG, "Found file " + file.getName() + " with size " + file.length());
}
// Create a new file and write into it
DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");
OutputStream out = getContentResolver().openOutputStream(newFile.getUri());
out.write("A long time ago...".getBytes());
out.close();
}
}
Возвращаемый Uri DocumentFile.getUri()
достаточно гибкий для использования с API различных платформ. Например, вы можете поделиться им с Intent.setData()
помощью Intent.FLAG_GRANT_READ_URI_PERMISSION
.
Если вы хотите получить доступ к этому Uri из собственного кода, вы можете вызвать, ContentResolver.openFileDescriptor()
а затем использовать ParcelFileDescriptor.getFd()
или detachFd()
для получения традиционного целого числа файлового дескриптора POSIX.
Как проверить, есть ли у вас доступ к файлам / папкам?
По умолчанию Uris, возвращаемый через намерения Storage Access Framework, не сохраняется при перезагрузке. Платформа «предлагает» возможность сохранить разрешение, но вам все равно нужно «взять» разрешение, если вы этого хотите. В нашем примере выше вы бы позвонили:
getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Вы всегда можете выяснить, к каким постоянным грантам ваше приложение имеет доступ через 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