You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Retrofit与DownloadManager实现高效文件下载?

如何将Retrofit/REST API与DownloadManager结合使用

DownloadManager是Android系统提供的高效下载工具,但它仅支持直接访问资源URL。要和你的REST后端搭配,核心是让DownloadManager能获取到合法的文件访问路径,下面分场景给出具体实现方案:

方案1:后端返回临时可下载URL(最优解)

如果你的后端支持,优先让下载接口返回一个带签名/时效的临时直链(比如CDN生成的一次性URL)。这种方式不需要额外处理,直接把URL传给DownloadManager即可,同时保留原有Retrofit的鉴权、参数校验逻辑。

实现步骤

  1. 用Retrofit调用原有的业务接口(比如带文件ID、用户鉴权的POST请求)
  2. 接口返回临时下载URL
  3. 拿到URL后配置并启动DownloadManager

代码示例

// Retrofit业务接口定义
interface FileApi {
    @POST("api/v1/file/get-download-url")
    suspend fun requestDownloadUrl(@Body req: DownloadReq): Response<DownloadResp>
}

data class DownloadReq(val fileId: String)
data class DownloadResp(val tempUrl: String)

// 获取临时URL后启动DownloadManager
val api = Retrofit.Builder().baseUrl("https://your-server.com/").build().create(FileApi::class.java)
val resp = api.requestDownloadUrl(DownloadReq("file_12345"))
resp.body()?.tempUrl?.let { url ->
    val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    val request = DownloadManager.Request(Uri.parse(url))
        .setTitle("XX文档")
        .setDescription("正在下载")
        .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "document.pdf")
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
    
    downloadManager.enqueue(request)
}

方案2:给DownloadManager添加请求头(适配需要鉴权的直链)

如果你的文件直链需要鉴权(比如Header带Token),或者需要自定义请求头,DownloadManager支持通过addRequestHeader()方法添加这些参数,无需依赖Retrofit即可完成鉴权请求。

代码示例

val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(Uri.parse("https://your-server.com/files/123.pdf"))
    .setTitle("XX文档")
    .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, "document.pdf")
    // 添加Bearer Token鉴权
    .addRequestHeader("Authorization", "Bearer ${yourUserToken}")
    // 添加自定义业务Header
    .addRequestHeader("X-App-Version", BuildConfig.VERSION_NAME)

downloadManager.enqueue(request)

方案3:将Retrofit的复杂请求转为DownloadManager可识别的URL

如果你的下载必须依赖Retrofit的复杂请求逻辑(比如POST带复杂参数、多步骤鉴权),可以让后端提供对应的GET接口,将POST参数转为GET查询参数,然后用DownloadManager请求该GET URL,同时添加必要的请求头。

比如原POST请求体:

{"fileId":"123","type":"pdf","expire":3600}

转为GET URL:https://your-server.com/api/download?fileId=123&type=pdf&expire=3600,再用方案2的方式添加鉴权头即可。

方案4:监听DownloadManager的下载进度

替换Retrofit拦截器后,要获取下载进度可以通过ContentObserver监听DownloadManager的下载状态:

代码示例

class DownloadProgressObserver(
    private val context: Context,
    private val downloadId: Long,
    private val onProgress: (Int) -> Unit
) : ContentObserver(Handler(Looper.getMainLooper())) {

    override fun onChange(selfChange: Boolean) {
        super.onChange(selfChange)
        queryProgress()
    }

    private fun queryProgress() {
        val cursor = context.contentResolver.query(
            DownloadManager.getUriForDownloadedFile(downloadId),
            arrayOf(
                DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR,
                DownloadManager.COLUMN_TOTAL_SIZE_BYTES
            ),
            null,
            null,
            null
        )
        cursor?.use {
            if (it.moveToFirst()) {
                val downloaded = it.getLong(0)
                val total = it.getLong(1)
                if (total > 0) {
                    val progress = ((downloaded * 100) / total).toInt()
                    onProgress(progress)
                }
            }
        }
    }
}

// 使用方式
val downloadId = downloadManager.enqueue(request)
val observer = DownloadProgressObserver(context, downloadId) { progress ->
    // 更新UI进度条
    binding.progressBar.progress = progress
}
// 注册观察者
context.contentResolver.registerContentObserver(
    DownloadManager.getUriForDownloadedFile(downloadId),
    true,
    observer
)

// 记得在页面销毁时注销
override fun onDestroy() {
    super.onDestroy()
    context.contentResolver.unregisterContentObserver(observer)
}

内容的提问来源于stack exchange,提问作者SoulReaver313

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 16:39:21