Android TV 11及以上读取公共目录player.json权限解决方案咨询
Android TV 跨版本读取公共存储JSON文件的权限适配方案
针对读取/storage/emulated/0/Movies/app_name/db/player.json文件的需求,分版本给出适配方案,解决EACCES(Permission denied)异常:
Android 11+(含Android 13+)适配
Android 11+强制启用分区存储,禁止直接通过File类访问公共媒体目录,推荐两种方案:
方案1:通过MediaStore访问(无需特殊权限)
目标路径属于公共Movies目录,可通过MediaStore框架查询并读取文件,无需申请READ_EXTERNAL_STORAGE或MANAGE_EXTERNAL_STORAGE:
// 构建查询条件,匹配相对路径 val relativePath = "Movies/app_name/db/player.json" val projection = arrayOf(MediaStore.Files.FileColumns._ID) val selection = "${MediaStore.Files.FileColumns.RELATIVE_PATH} = ?" val selectionArgs = arrayOf(relativePath) contentResolver.query( MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val fileId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)) val fileUri = ContentUris.withAppendedId(MediaStore.Files.getContentUri("external"), fileId) // 获取输入流读取JSON contentResolver.openInputStream(fileUri)?.use { inputStream -> val jsonContent = inputStream.bufferedReader().readText() // 处理JSON逻辑 } } }
方案2:迁移到应用专属存储(最优解)
如果该JSON文件是你的应用写入的,建议迁移到应用专属的Movies目录:
// 获取应用专属Movies目录路径 val appMoviesDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES) val targetFile = File(appMoviesDir, "app_name/db/player.json") // 直接读取,无需任何权限 val jsonContent = targetFile.bufferedReader().readText()
此路径属于应用私有区域,系统自动授权访问,符合Android隐私规范。
Android 10 替代权限方案
Android 10默认启用分区存储,无需申请MANAGE_EXTERNAL_STORAGE(该权限仅用于特殊场景),推荐兼容模式:
- 在
AndroidManifest.xml中添加兼容标记:
<application ... android:requestLegacyExternalStorage="true"> </application>
- 动态申请
READ_EXTERNAL_STORAGE权限,授权后即可通过File类直接访问目标路径,和Android 9及以下逻辑一致。
异常排查要点
- 确认路径拼写:Android文件系统区分大小写,确保是
Movies而非movies - 权限申请:运行时必须动态申请对应权限,且用户已授权
- Android 11+禁止
File类直接访问公共目录,必须用MediaStore或SAF(存储访问框架) - 若文件由其他应用写入,需确保文件权限为全局可读,或通过SAF让用户手动选择文件
内容的提问来源于stack exchange,提问作者Vishal Bhimporwala




