Android 11中复制文件夹至其他应用Android/data目录权限问题求助
解决方案:Android 11+ 复制文件到其他应用的Android/data目录
首先纠正你代码里的一个路径错误:目标路径应该是/storage/emulated/0/Android/data/com.android.chrome/files,你写的路径少了data节点,但这不是核心权限问题的根源。
核心原因
Android 11及以上的分区存储机制严格限制了普通APP直接访问其他应用的Android/data子目录,哪怕你申请了所有运行时权限也无法突破这个限制。那些能操作该目录的现代文件管理器,要么是使用了系统级特殊权限,要么是基于官方提供的**存储访问框架(SAF)**实现的。
正确实现方式:使用SAF
通过SAF让用户手动选择Chrome的files目录,APP获得合法访问权限后,再通过DocumentFile而非File类完成复制操作。
步骤1:注册目录选择器
使用Activity Result API注册目录选择回调:
private val pickChromeFilesDirLauncher = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { treeUri -> treeUri?.let { uri -> // 申请持久化访问权限,避免下次操作重复让用户选择 requireContext().contentResolver.takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) // 执行复制操作 val sourceFolder = requireContext().getExternalFilesDir("test") ?: return@registerForActivityResult val targetDir = DocumentFile.fromTreeUri(requireContext(), uri) ?: return@registerForActivityResult copyFolderToSafDir(sourceFolder, targetDir) } }
步骤2:启动目录选择器
在需要执行复制的地方调用:
pickChromeFilesDirLauncher.launch(null)
用户需要在系统文件选择器中找到并选择/Android/data/com.android.chrome/files目录。
步骤3:实现递归复制逻辑
编写函数递归复制文件夹和文件:
private fun copyFolderToSafDir(sourceFile: File, targetParentDir: DocumentFile) { if (sourceFile.isDirectory) { // 创建目标子文件夹 val targetSubDir = targetParentDir.createDirectory(sourceFile.name) ?: return // 遍历子文件/文件夹继续复制 sourceFile.listFiles()?.forEach { child -> copyFolderToSafDir(child, targetSubDir) } } else { // 创建目标文件并复制内容 targetParentDir.createFile("*/*", sourceFile.name)?.let { targetFile -> requireContext().contentResolver.openOutputStream(targetFile.uri).use { outputStream -> sourceFile.inputStream().use { inputStream -> inputStream.copyTo(outputStream!!) } } } } }
关键说明
- SAF是Android官方推荐的访问受限目录的唯一合法方式,使用该方案的APP可以正常上架Google Play。
- 持久化权限只需用户授权一次,后续APP可直接访问该目录。
- 不要尝试使用
File类直接操作其他应用的Android/data目录,在Android 11+环境下完全无效,且不符合Google的权限规范。
内容的提问来源于stack exchange,提问作者Zgoly
相关产品推荐
相关产品推荐

