Android 10及以上版本PDF下载的存储权限适配问题
仅靠你当前的权限检查代码,不一定能保证PDF下载正常完成,核心取决于你要将PDF保存到哪个存储位置,具体分析如下:
1. 存储路径决定是否需要额外操作
情况一:保存到APP私有目录
如果PDF是下载到APP的私有存储目录(比如context.filesDir或context.getExternalFilesDir(null)),那你的权限检查代码完全够用,不需要额外操作。因为Android 10及以上版本,APP对自己的私有存储拥有完全的读写权限,无需申请任何存储相关权限,卸载APP时这些文件也会被一并删除。
情况二:保存到公共目录(如Downloads、Documents)
如果要将PDF保存到系统公共存储目录,仅跳过WRITE_EXTERNAL_STORAGE权限申请是不够的,因为Android 10(API 29)引入了分区存储(Scoped Storage),直接通过文件路径写入公共目录的方式被限制,必须通过以下两种方式实现:
- 使用MediaStore API:通过插入媒体记录获取Uri,再通过Uri写入文件(适合无需用户手动选择位置的场景)
- 使用存储访问框架(SAF):唤起系统文件选择器,让用户指定保存位置,拿到对应的Uri后进行写入
2. Android 13的特殊注意事项
Android 13(API 33)新增了READ_MEDIA_IMAGES/READ_MEDIA_VIDEO/READ_MEDIA_AUDIO这几个细分权限,但PDF属于文档类,读取公共目录的PDF无需申请这些权限;写入公共目录依然需要依赖MediaStore或SAF,和Android 10/11/12的逻辑一致。
3. 代码优化与补充建议
权限检查代码优化
当前的Build.VERSION.SDK_INT > Build.VERSION_CODES.P可以改成Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q(Q对应Android 10),语义更清晰:
private fun checkStoragePermissions(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { true } else { ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } }
公共目录写入示例(MediaStore方式)
如果需要将PDF保存到公共Downloads目录,可以参考以下代码:
private fun savePdfToPublicDownloads(context: Context, pdfContent: ByteArray) { val contentValues = ContentValues().apply { put(MediaStore.Downloads.DISPLAY_NAME, "my_download.pdf") put(MediaStore.Downloads.MIME_TYPE, "application/pdf") put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) } context.contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)?.let { uri -> context.contentResolver.openOutputStream(uri)?.use { outputStream -> outputStream.write(pdfContent) } } }
总结
- 若PDF保存到私有目录:当前权限代码足够,无需额外操作;
- 若PDF保存到公共目录:必须改用MediaStore或SAF实现写入逻辑,否则会出现写入失败的情况。
内容的提问来源于stack exchange,提问作者alexC

