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

Android端实现S3分片上传的可行方案咨询

可行方案与问题解答

一、基于TransferUtility的实现方案

你提到的TransferUtility确实是Android端处理S3分片上传的官方可行方案,以下是适配你需求的配置方式:

1. 创建S3Client(适配临时凭证)

BasicSessionCredentials正是用来承载临时凭证的类,你可以从后端安全API获取临时AccessKeyId、SecretAccessKey、SessionToken,用它构建S3Client:

val tempCredentials = BasicSessionCredentials(
    "后端返回的临时AccessKeyId",
    "后端返回的临时SecretAccessKey",
    "后端返回的临时SessionToken"
)

val s3Client = AmazonS3Client(tempCredentials)
s3Client.setRegion(Region.getRegion(Regions.US_EAST_1)) // 替换为你的S3存储桶所在区域

注:后端生成临时凭证时,要限定其操作权限(比如仅允许上传指定存储桶的特定文件),避免安全风险。

2. 构建AWSConfiguration

不需要复杂配置,直接用上下文初始化即可,因为核心逻辑依赖你自定义的S3Client:

val awsConfiguration = AWSConfiguration(context)

3. 初始化TransferUtility并启动上传

val transferUtility = TransferUtility.builder()
    .context(context)
    .awsConfiguration(awsConfiguration)
    .s3Client(s3Client)
    .build()

// 启动分片上传
val uploadObserver = transferUtility.upload(
    "你的存储桶名称",
    "文件在S3中的对象键",
    File("本地大文件路径")
)

// 监听上传状态与进度
uploadObserver.setTransferListener(object : TransferListener {
    override fun onStateChanged(id: Int, state: TransferState) {
        when(state) {
            TransferState.COMPLETED -> // 上传完成逻辑
            TransferState.FAILED -> // 上传失败逻辑
            else -> {}
        }
    }

    override fun onProgressChanged(id: Int, bytesCurrent: Long, bytesTotal: Long) {
        // 计算进度:(bytesCurrent * 100) / bytesTotal
    }

    override fun onError(id: Int, ex: Exception) {
        // 错误处理
    }
})

二、手动分片上传方案

如果TransferUtility的凭证方式不符合你的预签名URL流程,也可以手动实现分片上传,步骤如下:

  1. 初始化上传:调用后端API,请求S3分片上传的UploadId
  2. 拆分文件:将大文件按S3要求拆分(最小5MB,最后一片可更小)
  3. 获取分片预签名URL:对每个分片,调用后端API获取对应PartNumber的预签名URL
  4. 上传分片:用Retrofit/OkHttp上传每个分片到预签名URL,记录每个分片的ETag
  5. 完成上传:所有分片上传后,调用后端API提交PartNumber和ETag列表,由后端触发S3的合并操作

文件拆分示例代码:

fun splitLargeFile(file: File, chunkSize: Long = 5 * 1024 * 1024): List<File> {
    val chunks = mutableListOf<File>()
    val inputStream = FileInputStream(file)
    val buffer = ByteArray(chunkSize.toInt())
    var bytesRead: Int
    var partNum = 1

    while (inputStream.read(buffer).also { bytesRead = it } != -1) {
        val chunkFile = File(file.parent, "${file.name}.part$partNum")
        FileOutputStream(chunkFile).use { it.write(buffer, 0, bytesRead) }
        chunks.add(chunkFile)
        partNum++
    }
    inputStream.close()
    return chunks
}

三、关于Android端无Uppy替代工具的原因

  1. 生态碎片化:Android设备、系统版本差异大,第三方库需要兼容更多场景,维护成本高
  2. 官方方案覆盖:AWS提供的TransferUtility已经满足大部分分片上传需求,第三方库缺乏足够的开发动力
  3. 需求场景差异:Web端大文件上传场景更普遍(如文件管理平台),Android端以小文件上传为主,大文件需求相对小众

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:45:22