Я создаю локальный видеоплеер, используя Capacitor 6 и специальный плагин Java для управления доступом к файловой системе на Android 11+ (API 30+). Я использую Storage Access Framework (SAF) через DocumentFile для рекурсивного сканирования выбранного пользователем каталога.
Проблема
Когда я пытаюсь составить список содержимого подпапки, используя ее URI content://, я часто получаю 0 результатов или ошибку, даже если подпапка определенно содержит файлы.
Я пытался использовать DocumentsContract.buildDocumentUriUsingTree для создания URI, «связанного» с корневым деревом, для которого пользователь предоставил разрешение. Однако моя реализация по-прежнему приводит к пустому массиву при вызове listFiles() для вложенных папок.
Моя реализация
Java (плагин пользовательского конденсатора):
Код: Выделить всё
private DocumentFile getTreeBoundDocument(Uri treeUri, Uri childUri) {
String docId;
try {
// childUri comes from parent.listFiles() -> file.getUri()
docId = DocumentsContract.getDocumentId(childUri);
} catch (IllegalArgumentException e) {
return null;
}
// Explicitly rebuild the URI using the original treeUri and child's docId
Uri treeBoundUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, docId);
return DocumentFile.fromTreeUri(getContext(), treeBoundUri);
}
@PluginMethod
public void listContents(PluginCall call) {
String uriString = call.getString("uri");
String treeUriString = call.getString("treeUri"); // The root folder picked by the user
try {
Uri currentUri = Uri.parse(uriString);
DocumentFile dir = null;
if (treeUriString != null) {
Uri treeUri = Uri.parse(treeUriString);
if (uriString.equals(treeUriString)) {
dir = DocumentFile.fromTreeUri(getContext(), treeUri);
} else {
dir = getTreeBoundDocument(treeUri, currentUri);
}
} else {
dir = DocumentFile.fromTreeUri(getContext(), currentUri);
}
if (dir == null || !dir.exists() || !dir.isDirectory()) {
call.reject("Not a directory or cannot access.");
return;
}
DocumentFile[] children = dir.listFiles();
// PROBLEM: children is always empty [] for subfolders, but works for the root.
// ... build response and resolve ...
} catch (Exception e) {
call.reject(e.getMessage());
}
}
Код: Выделить всё
const scan = async (path: string): Promise => {
// treeUri is the original root URI string stored globally
const res = await StoragePermission.listContents({ uri: path, treeUri: rootTreeUri });
const items = [];
for (const file of res.files) {
if (file.type === 'directory') {
const children = await scan(file.uri);
items.push({ name: file.name, type: 'directory', children });
} else {
items.push({ name: file.name, type: 'video' });
}
}
return items;
};
- Постоянные разрешения: я вызываю takePersistableUriPermission для корневого URI.
- формат[/b]: идентификатор документа, извлеченный из дочернего URI, выглядит правильно (например, основной:Documents/Folder/Subfolder).
Код: Выделить всё
docId - Версия для Android: протестировано на Android 14.
Подробнее здесь: https://stackoverflow.com/questions/798 ... menturiusi
Мобильная версия