Android TV上MANAGE_EXTERNAL_STORAGE权限无法使用的问题排查
核心结论
MANAGE_EXTERNAL_STORAGE权限在Android TV平台上没有官方支持,因为Android TV的系统设置中没有对应的权限管理Activity,所以调用Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION Intent会直接抛出ActivityNotFoundException,这就是你遇到崩溃的原因。
针对你的场景的可行解决方案
结合你需要支持Android 5到12的需求,以及访问用户创建的文本文件的目标,推荐以下几种更适配的方案:
1. 基于Storage Access Framework(SAF)的目录授权
使用ACTION_OPEN_DOCUMENT_TREE引导用户选择存放文本文件的目录,获取该目录的持久化访问权限,后续即可通过SAF API读取目录下的所有文本文件:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); startActivityForResult(intent, REQUEST_CODE_PICK_DIR);
在onActivityResult中保存返回的Uri,之后就可以通过ContentResolver遍历目录下的文件。这种方式符合Android存储政策,且不需要特殊权限,唯一需要注意的是引导用户选择正确的目录,部分Android TV可能需要第三方文件管理器支持该Intent,你可以在应用中提示用户安装适配TV的文件管理器(比如ES文件浏览器TV版)。
2. 利用MediaStore访问Downloads目录下的文本文件
Android 10及以上,MediaStore.Downloads允许访问Downloads目录下的非媒体文件,无需修改文件扩展名。你可以通过以下代码查询Downloads目录下的.txt文件:
Uri uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI; String[] projection = { MediaStore.Downloads._ID, MediaStore.Downloads.DISPLAY_NAME }; String selection = MediaStore.Downloads.MIME_TYPE + " = ? OR " + MediaStore.Downloads.DISPLAY_NAME + " LIKE ?"; String[] selectionArgs = {"text/plain", "%.txt"}; Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, null);
这种方式只需READ_EXTERNAL_STORAGE权限,但只能访问Downloads目录下的文件,需要引导用户将文本文件放在该目录。
3. 临时兼容方案:降低targetSdk到29
如果短期需要兼容Android 11+的TV设备,可以将targetSdkVersion设为29并在Manifest中添加:
<application ... android:requestLegacyExternalStorage="true"> </application>
这样在Android 10及以下可以正常使用传统文件访问方式,Android 11+设备上虽然requestLegacyExternalStorage会被忽略,但部分品牌的TV可能仍允许访问外部存储(不保证全机型支持)。不过这只是临时方案,不符合Google的长期存储政策,未来升级targetSdk到30+后会失效。
4. 应用专属存储的变通
引导用户通过SAF选择文本文件后,将文件复制到你的应用专属外部存储目录(getExternalFilesDir(null)),之后就可以直接读取这些文件,不需要任何权限。这种方式适合需要离线访问文件的场景,但会占用应用的存储配额。
内容的提问来源于stack exchange,提问作者anenasa

