如何用DownloadManager将文件下载到Android用户授权目录?
解决DownloadManager下载到用户授权目录的问题
问题原因
你遇到的IllegalStateException是因为setDestinationInExternalPublicDir()方法的第一个参数必须是Environment类定义的系统标准目录常量(比如Environment.DIRECTORY_DOWNLOADS、Environment.DIRECTORY_DOCUMENTS),不能传入自定义路径字符串,直接用用户选择的目录路径会触发报错。
解决方案
DownloadManager支持通过Content URI指定下载目标,结合你已获取的用户授权目录Tree Uri,按以下步骤实现:
从保存的Tree Uri还原并创建目标文件的DocumentFile
将之前保存的Tree Uri字符串转换为Uri对象,通过DocumentFile.fromTreeUri()获取目录的DocumentFile实例,再在该目录下创建要下载的目标文件。用目标文件的Uri设置DownloadManager的下载路径
使用setDestinationUri()方法替代setDestinationInExternalPublicDir(),传入目标文件的Content URI。
完整代码示例
// 从ViewModel获取之前保存的用户授权目录Tree Uri字符串 val savedTreeUriStr = playerViewModel.getAppFolderPath() val treeUri = Uri.parse(savedTreeUriStr) // 获取用户授权目录的DocumentFile val targetDir = DocumentFile.fromTreeUri(applicationContext, treeUri) ?: run { Toast.makeText(applicationContext, "无法访问授权目录", Toast.LENGTH_SHORT).show() return@yourFunction } // 创建目标文件的DocumentFile,替换MIME类型为你下载文件的实际类型 val mimeType = "application/octet-stream" // 通用二进制类型,可调整为image/jpeg、text/plain等 val targetFile = targetDir.createFile(mimeType, fileName) ?: run { Toast.makeText(applicationContext, "无法创建目标文件", Toast.LENGTH_SHORT).show() return@yourFunction } // 构建DownloadManager请求 val request = DownloadManager.Request(Uri.parse(url)) .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE) .setTitle(fileName) .setDescription(desc) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) .setDestinationUri(targetFile.uri) // 关键:使用目标文件的Content URI .setAllowedOverMetered(true) .setAllowedOverRoaming(true) // 执行下载 val downloadManager = applicationContext.getSystemService(DOWNLOAD_SERVICE) as DownloadManager val downloadID = downloadManager.enqueue(request)
注意事项
- MIME类型适配:根据下载文件的实际类型调整
mimeType参数,比如PDF用application/pdf、音频用audio/mpeg,确保文件能被系统正确识别。 - 空安全处理:
DocumentFile.fromTreeUri()和createFile()可能返回null,必须做非空判断,避免空指针异常。 - 权限验证:确保已通过
takePersistableUriPermission()获取持久化的Uri读写权限(你之前的代码已处理此部分,无需额外操作)。
内容的提问来源于stack exchange,提问作者Артемий Величко
相关产品推荐
相关产品推荐

