You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

无Root权限下,Android 11中部分应用如何访问".../Android/..."子文件夹内容?

How to Access Android Folder via SAF & Bypass Scoped Storage Restrictions

Great question—this is a common pain point with Android's scoped storage, especially since apps like X-plore and MiXplorer seem to pull off this access seamlessly. Let's break down what's happening and how to replicate this behavior properly.

1. Requesting Access to the Full Android Folder (The X-plore/MiXplorer Trick)

The key issue with your initial attempt is that directly requesting the root Android folder via SAF triggers scoped storage restrictions, which block access to data and obb. Instead, you need to target a subfolder like Android/data first. Once the user grants access to that subfolder, the system implicitly grants permission to the entire parent Android directory.

Here's the corrected Kotlin code to implement this:

Step 1: Launch SAF Intent Targeting Android/data

private const val REQUEST_CODE_SAF = 1

// Build the tree URI for Android/data
val androidDataTreeUri = DocumentsContract.buildTreeDocumentUri(
    "com.android.externalstorage.documents",
    "primary:Android/data"
)

val safIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    .setFlags(
        Intent.FLAG_GRANT_READ_URI_PERMISSION or
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
        Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
        Intent.FLAG_GRANT_PREFIX_URI_PERMISSION // Critical for parent directory access
    )
    .putExtra(DocumentsContract.EXTRA_INITIAL_URI, androidDataTreeUri)

startActivityForResult(safIntent, REQUEST_CODE_SAF)

Step 2: Handle the Permission & Access the Full Android Folder

Once the user grants access, you can now access the entire Android directory, including data and obb:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE_SAF && resultCode == RESULT_OK) {
        data?.data?.let { grantedTreeUri ->
            // Persist the permission so it survives app restarts
            contentResolver.takePersistableUriPermission(
                grantedTreeUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            )

            // Now access the full Android folder
            val androidTreeUri = DocumentsContract.buildTreeDocumentUri(
                "com.android.externalstorage.documents",
                "primary:Android"
            )
            val androidFolder = DocumentFile.fromTreeUri(this, androidTreeUri)

            // List all subfolders (media, data, obb will all be accessible)
            androidFolder?.listFiles()?.forEach { folder ->
                Log.d("SAF Access", "Folder: ${folder.name}")
                // Access contents of each subfolder
                folder.listFiles()?.forEach { file ->
                    Log.d("SAF Access", "File/Subfolder: ${file.name}")
                }
            }
        }
    }
}

Why This Works

When you grant access to Android/data, the SAF system treats this as permission to access the entire tree rooted at Android (thanks to the FLAG_GRANT_PREFIX_URI_PERMISSION flag). This bypasses the scoped storage restrictions that block direct access to data/obb when requesting the root Android folder.

2. Alternative Solutions (ADB/Root)

If you need to automate access or work outside user interaction, here are your options:

ADB Method (No Root, User Interaction Required)

You can launch the SAF intent directly to Android/data via ADB to skip manual navigation:

adb shell am start -a android.intent.action.OPEN_DOCUMENT_TREE -e android.intent.extra.INITIAL_URI content://com.android.externalstorage.documents/tree/primary%3AAndroid/data

The user just needs to tap "Allow" to grant persistent access to your app.

Root Method (Full Automation)

With root access, you can directly grant SAF permissions without user input by modifying the system's permission database:

adb shell su -c "content insert --uri content://com.android.externalstorage.documents/tree/primary%3AAndroid/data --bind flags:i:3 --bind grant_uri:text:\"content://com.android.externalstorage.documents/tree/primary%3AAndroid\" --bind package_name:text:\"com.your.package.name\""

Replace com.your.package.name with your app's package ID. This inserts a persistent permission grant for the full Android directory.

Alternatively, with root, you can bypass SAF entirely and access files directly using the File class (since scoped storage restrictions don't apply to root processes).

Key Notes

  • Target API 30+: The requestLegacyExternalStorage flag is ignored, but this SAF method still works because it relies on user-granted permissions.
  • ROM Compatibility: Most mainstream ROMs support this behavior, but some custom ROMs may have stricter SAF rules.
  • Avoid Direct Android Folder Requests: As you saw, requesting the root Android folder directly will block data/obb access—always target a subfolder first.

内容的提问来源于stack exchange,提问作者android developer

火山引擎 最新活动