Android DownloadManager报java.lang.SecurityException:Unsupported path错误求助
问题根因
这个报错是Android 10(API 29)及以上版本的分区存储机制限制导致的,和DownloadManager的路径访问规则直接相关:
- 你自定义的
/storage/emulated/0/MyAppName/属于外部存储根目录下的自定义目录,Android 10开始引入分区存储后,普通应用即使申请了WRITE_EXTERNAL_STORAGE权限,也不能直接在外部存储根目录创建、读写自定义文件夹。 - DownloadManager作为系统服务,本身没有权限访问你应用自定义的外部存储根目录路径,所以当你调用
setDestinationUri传入自定义根目录路径时,就会抛出SecurityException。 - 之前运行正常、模拟器正常是因为对应设备的系统版本低于API 29,没有开启分区存储限制;保存到Downloads公共目录不报错,是因为DownloadManager本身被授权可以访问标准公共目录。
解决方案
方案1:使用应用专属外部存储目录(推荐,无需申请存储权限)
直接将文件保存到应用专属的外部存储目录,该目录由系统分配给你的应用,不需要申请任何存储权限即可读写,DownloadManager也能正常访问,示例代码:
// 获得应用专属下载目录,路径示例:/storage/emulated/0/Android/data/你的应用包名/files/Download File appDownloadDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); String downloadDir = appDownloadDir.getAbsolutePath() + "/zip/" + productId; // 后续创建目录、设置路径的逻辑保持不变
缺点是应用卸载时,该目录下的文件会被系统同步删除。
方案2:保存到公共标准目录
如果需要文件在应用卸载后保留,可以使用DownloadManager提供的公共目录写入方法,不要自己拼接根目录路径:
// 直接将文件保存到公共Downloads目录下的自定义子路径 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "MyAppName/zip/"+productId+"/"+fileName);
如果你的targetSdk >= 33,只需要申请POST_NOTIFICATIONS权限即可正常使用DownloadManager,不需要申请存储权限。
方案3:临时适配方案(仅targetSdk 29可用)
如果暂时不想调整存储逻辑,可以在AndroidManifest.xml的application标签中添加过渡配置,关闭分区存储限制:
<application android:requestLegacyExternalStorage="true" ...> </application>
注意:该配置仅在targetSdk为29时生效,targetSdk升到30及以上后会自动失效,且申请所有文件访问权限(MANAGE_EXTERNAL_STORAGE)在谷歌商店审核时要求极严,非文件管理类应用很难过审,不建议长期使用。
内容的提问来源于stack exchange,提问作者Bagusflyer
相关产品推荐
相关产品推荐

