Android 13(API 33)文档/PDF细粒度权限:卸载重装后文件访问问题
解决方案与说明
核心原因
Android 10及以上的分区存储机制下,应用卸载后新安装的实例会被视为完全独立的主体,失去对旧实例在公共目录中创建文件的直接访问权。图片能通过READ_MEDIA_IMAGES访问,是因为该权限针对媒体库中的图片资源,系统会自动将公共目录下的图片纳入媒体库管理;但PDF等文档类文件不在这个权限的覆盖范围内,因此无法直接读取。
一、文档类文件的访问处理方案
针对卸载重装后访问旧存PDF的需求,有三种可行方向:
- 方案1:使用SAF持久化目录权限(推荐)
这是Android官方针对分区存储下跨生命周期访问公共目录文件的标准方案。引导用户通过SAF选择Documents/MyAppName目录,调用getContentResolver().takePersistableUriPermission()将访问权限持久化。重装后,只要用户再次授权(或系统保留权限记录),就能通过保存的Uri直接访问该目录下的所有文件,无需遍历整个公共目录。 - 方案2:利用MediaStore索引文档
Android 13及以上可申请READ_MEDIA_DOCUMENTS权限,通过MediaStore查询公共目录下的PDF文件。但该权限是全局的(允许访问所有媒体库中的文档),且旧实例创建的PDF需被系统媒体库索引才能被查到——你可以在旧版本应用中添加代码,将创建的PDF插入MediaStore;不过此方案无法精准限制到MyAppName目录,权限范围较宽。 - 方案3:存储到应用专属外部目录(补充说明)
若不需要卸载后保留文件,可使用getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)存储,但该目录会随应用卸载被删除,不符合你的场景。
二、是否必须实现SAF?
不是强制,但如果要精准、可靠地访问你之前创建的MyAppName目录下的文件,SAF是最优选择。其他方案要么权限范围过大,要么无法保证文件的可访问性(比如MediaStore索引失败的情况)。
三、验证指定文件夹的权限
1. 基于持久化Uri的权限检查
用户通过SAF授权后,将授权Uri保存到SharedPreferences中。重装后,通过以下代码检查权限:
Uri savedUri = Uri.parse(sharedPreferences.getString("MY_APP_DIR_URI", "")); int permissionCheck = getContentResolver().checkUriPermission( savedUri, android.os.Process.myPid(), android.os.Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION ); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { // 拥有该目录的读取权限 } else { // 需要重新引导用户授权 }
2. 实际访问验证
直接尝试读取目录下的文件或列出目录内容,若抛出SecurityException则说明无权限:
DocumentFile dir = DocumentFile.fromTreeUri(this, savedUri); if (dir != null && dir.exists() && dir.canRead()) { // 有权限 } else { // 无权限 }
内容的提问来源于stack exchange,提问作者akLab
相关产品推荐
相关产品推荐

