Фон
Существуют различные ограничения на объем хранилища в Android 10 и 11, которое также включает новое разрешение (MANAGE_EXTERNAL_STORAGE) для доступа все файлы (но это не позволяет получить доступ ко всем файлам), в то время как предыдущее разрешение на хранение было уменьшено, чтобы предоставить доступ только к медиафайлам:
- Приложения могут свободно обращаться к подпапке мультимедиа.
- Приложения никогда не смогут получить доступ к подпапке данных и особенно к содержимому.
- Для папки obb, если приложению разрешено устанавливать приложения, оно может получить доступ к ней (чтобы скопировать туда файлы). Иначе нельзя.
- Используя USB или root, вы все равно можете получить к ним доступ, а как конечный пользователь вы можете получить к ним доступ через встроенное приложение файлового менеджера Files.
Проблема
Я заметил приложение, которое каким-то образом преодолевает это ограничение (здесь) называется X-plore: как только вы входите в папку Android/data, вам будет предложено предоставить к ней доступ (непосредственно с помощью SAF , каким-то образом), и когда вы предоставите его, вы сможете получить доступ ко всему во всех папках папки Android.
Это означает, что все еще может быть способ добраться до него, но проблема в том, что по какой-то причине я не смог сделать образец, который делает то же самое.
Что я нашел и попробовал
Похоже, что это приложение нацелено на API 29 (Android 10), оно еще не использует новое разрешение и имеет флаг requestLegacyExternalStorage. Я не знаю, сработает ли тот же трюк, который они используют, при нацеливании на API 30, но я могу сказать, что в моем случае, работающем на Pixel 4 с Android 11, он работает нормально.
Поэтому я попытался сделать то же самое:
Я сделал образец POC, ориентированный на Android API 29, с предоставленными разрешениями на хранение (всех видов), включая устаревший флаг.
Я попытался запросить доступ непосредственно к папке Android (на основе здесь), который, к сожалению, не сработал, так как по какой-то причине (продолжал переходить в папку DCIM, не знаю почему):
val androidFolderDocumentFile = DocumentFile.fromFile(File(primaryVolume.directory!!, "Android"))
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
.putExtra(DocumentsContract.EXTRA_INITIAL_URI, androidFolderDocumentFile.uri)
startActivityForResult(intent, 1)
Пробовал разные комбинации флагов.
При запуске приложения, когда я сам добираюсь до папки Android вручную, так как это не сработало, и я предоставил доступ к этой папке, как и в другом приложении.
При получении результата я пытаюсь получить файлы и папки по пути, но не могу их получить:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d("AppLog", "resultCode:$resultCode")
val uri = data?.data ?: return
if (!DocumentFile.isDocumentUri(this, uri))
return
grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
val fullPathFromTreeUri = FileUtilEx.getFullPathFromTreeUri(this, uri) // code for this here: https://stackoverflow.com/q/56657639/878126
val documentFile = DocumentFile.fromTreeUri(this, uri)
val listFiles: Array<DocumentFile> = documentFile!!.listFiles() // this returns just an array of a single folder ("media")
val androidFolder = File(fullPathFromTreeUri)
androidFolder.listFiles()?.forEach {
Log.d("AppLog", "${it.absoluteFile} children:${it.listFiles()?.joinToString()}") //this does find the folders, but can't reach their contents
}
Log.d("AppLog", "granted uri:$uri $fullPathFromTreeUri")
}
Таким образом, используя DocumentFile.fromTreeUri, я все еще мог получить только медиа-папку, которая бесполезна, и с помощью класса File я мог видеть только папки с данными и obb, но все еще не мог получить доступ к их содержимому...
Так что это совсем не сработало.
Позже я обнаружил другое приложение, использующее этот прием, под названием MiXplorer. В этом приложении ему не удалось напрямую запросить папку Android (возможно, он даже не пытался), но он предоставляет вам полный доступ к нему и его подпапкам, как только вы это разрешите. И он нацелен на API 30, поэтому это означает, что он не работает только потому, что вы ориентируетесь на API 29.
Я заметил (мне кто-то писал), что при некоторых изменениях в коде я мог запросить доступ к каждой из подпапок отдельно (имеется в виду запрос данных и новый запрос обб), но это не то, что я вижу здесь, что приложения делают.
Это означает, что для доступа к папке Android я использую этот Uri в качестве параметра для Intent.EXTRA_INITIAL_URI :
val androidUri=Uri.Builder().scheme("content").authority("com.android.externalstorage.documents")
.appendEncodedPath("tree").appendPath("primary:").appendPath("document").appendPath("primary:Android").build()
Однако получив к нему доступ, вы не сможете получить из него список файлов, ни через File, ни через SAF.
Но, как я уже писал, странно то, что если вы попробуете что-то подобное, вместо этого получить доступ к Android/data, вы сможете получить его содержимое:
val androidDataUri=Uri.Builder().scheme("content").authority("com.android.externalstorage.documents")
.appendEncodedPath("tree").appendPath("primary:").appendPath("document").appendPath("primary:Android/data").build()
Вопросы
- Как я могу запросить Intent непосредственно в папку Android, которая фактически позволит мне получить к ней доступ и позволит мне получить подпапки и их содержимое?
- Есть ли другая альтернатива этому? Может быть, используя adb и/или root, я мог бы предоставить SAF доступ к этой конкретной папке?
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION...
Это не имеет смысла. Вы не можете ничего грандиозного. Вместо этого вы должны быть рады, что вам что-то предоставлено в onActivityResult. Лучше удалите этот код. - person blackapps   schedule 30.01.2021I could grant SAF access to this specific folder ?
Неправильно. Вы ничего не можете сделать. Вместо этого радуйтесь, что у вас есть доступ к saf grands. - person blackapps   schedule 30.01.2021// Provide read access to files and sub-directories in the user-selected // directory. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
. Ну, это ошибка в этом документе. Убери его и увидишь. И подумайте об этом: как тогда можно было обойтись без флага WRITE? - person blackapps   schedule 30.01.2021How can I request an Intent directly to "Android" folder?
Полная награда? - person blackapps   schedule 25.02.2021looking for an answer from a reputable source.
Что ты имеешь в виду? - person blackapps   schedule 25.02.2021