使用Android SDK上传文件

更新时间:
复制 MD 格式

本文介绍如何使用Android SDK将媒体文件从本地上传至点播存储。

前提条件

项目

要求

最低 Android 版本

API 14(Android 4.0)

编译版本

compileSdkVersion 30

阿里云账号

开通视频点播

鉴权服务

已准备好可签发上传凭证(UploadAuth)的后端服务

使用限制

  • 目前Android SDK 只支持上传音、视频,不支持上传辅助媒资。

集成SDK

集成方式

在工程根 build.gradle 中加入阿里云 Maven 仓库:

allprojects {
    repositories {
        maven { url "https://maven.aliyun.com/nexus/content/repositories/releases" }
    }
}

在模块 build.gradle 中加入 SDK 依赖:

dependencies {
    implementation 'com.aliyun.video.android:upload:<sdk_version>'
}

底层 OSS Android SDK 已由 VODUpload 通过 api 依赖传递,无需重复声明。

项目配置

在 AndroidManifest.xml 中声明权限:

<uses-permission android:name="android.permission.INTERNET" />2<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />3<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />4<!-- Android 13+ 媒体细分权限按需声明 -->5<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />6<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

如开启了代码混淆,在 proguard-rules.pro 中追加:

-keep class com.alibaba.sdk.android.vod.upload.v2.** { *; }
-keep interface com.alibaba.sdk.android.vod.upload.v2.** { *; }

底层 OSS Android SDK 自带 ProGuard 规则,无需重复声明。

基础设置

初始化上传实例

通过 VODUploadConfig.Builder 构造配置并调用 VODUploadClient.create(...) 创建上传实例:

import com.alibaba.sdk.android.vod.upload.v2.*;23VODUploadConfig config = new VODUploadConfig.Builder()4        .setGetAuth(getAuth)               // 必填:鉴权回调,详见"回调处理"5        .build();67VODUploadClient uploader = VODUploadClient.create(context, config);

uploader 实例可复用,并发上传多个文件时复用同一实例即可。生命周期结束时调用 uploader.dispose() 释放资源。

上传控制

调用 upload(...) 启动一次上传,返回 VODUploadTask 句柄用于取消:

VODVideoMeta meta = new VODVideoMeta.Builder()
        .setTitle("我的视频")
        .setTags("demo")
        .setCateId(1000)
        .build();

VODUploadOptions options = new VODUploadOptions.Builder()
        .setVideoMeta(meta)
        .setOnProgress((percent, uploaded, total) ->
                Log.d("Upload", String.format("%.1f%%", percent * 100)))
        .build();

VODUploadTask task = uploader.upload(filePath, options, new VODUploadResultCallback() {
    @Override public void onSuccess(VODUploadResult r) {
        Log.i("Upload",
                "videoId=" + r.getVideoId()
                + " uploadTaskId=" + r.getUploadTaskId()
                + " etag=" + r.getEtag()
                + " requestId=" + r.getRequestId()
                + " durationMs=" + r.getDurationMs());
    }
    @Override public void onFailure(VODUploadError e) {
        Log.e("Upload", e.getErrorCode() + " : " + e.getErrorMessage(), e.getCause());
    }
});

// 中途取消(默认开启断点续传,下次同文件 upload 自动续传)
task.cancel();
// task.getUploadTaskId() 可用于关联日志、对接埋点

upload(...) 提供两种重载,支持文件路径和 content:// Uri(适配 Android 10+ Scoped Storage):

uploader.upload(String filePath, VODUploadOptions options, VODUploadResultCallback callback);
uploader.upload(Uri fileUri, VODUploadOptions options, VODUploadResultCallback callback);

图片上传:SDK 根据文件扩展名(jpg / jpeg / png / gif / bmp / webp / heic)或 options.imageMeta != null 自动走图片链路,成功回调中 result.getImageId() 与 result.getImageUrl() 有值:

VODImageMeta imgMeta = new VODImageMeta.Builder()
        .setImageType("cover")
        .setTitle("封面")
        .build();
uploader.upload("/sdcard/cover.jpg",
        new VODUploadOptions.Builder().setImageMeta(imgMeta).build(),
        callback);

回调处理

v2 通过统一的 VODGetAuthCallback 异步回调向业务方索取上传凭证。SDK 在以下时机调用 getAuth,并通过 VODAuthContext.getKind() 告知所需凭证类型:

Kind

触发时机

业务方应调用的 OpenAPI

CREATE_VIDEO

首次上传一个视频文件

获取音视频上传地址和凭证

REFRESH_VIDEO

续传 / 凭证刷新

刷新视频上传凭证

CREATE_IMAGE

上传图片

获取图片上传地址和凭证

业务方只需把后端 OpenAPI 返回的原始 JSON 原样回传给 SDK。SDK 按 OpenAPI 原始字段名(大小写敏感)读取以下键:

Kind

必须包含的字段

CREATE_VIDEO / REFRESH_VIDEO

UploadAuthUploadAddressVideoId

CREATE_IMAGE

UploadAuthUploadAddressImageIdImageURL(透传到 result.getImageUrl()

说明

字段名大小写敏感,请直接转发 OpenAPI 响应;自行重命名为 videoId / imageUrl / image_url 会导致 SDK 解析为 null

VODGetAuthCallback getAuth = (ctx, completion) -> {
    switch (ctx.getKind()) {
        case CREATE_VIDEO:
            yourBackend.createUploadVideo(ctx.getFileName(), ctx.getFileSize(),
                json -> completion.onSuccess(json),
                err -> completion.onFailure("BIZ.CREATE_VIDEO", err.getMessage()));
            break;
        case REFRESH_VIDEO:
            yourBackend.refreshUploadVideo(ctx.getVideoId(),
                json -> completion.onSuccess(json),
                err -> completion.onFailure("BIZ.REFRESH_VIDEO", err.getMessage()));
            break;
        case CREATE_IMAGE:
            yourBackend.createUploadImage(ctx.getFileName(),
                json -> completion.onSuccess(json),
                err -> completion.onFailure("BIZ.CREATE_IMAGE", err.getMessage()));
            break;
    }
};

高级设置

上传加速

将 VODVideoMeta.userData 设置为下面的 JSON,VOD 服务端在签发 UploadAddress 时会自动返回 OSS 全球传输加速节点(oss-accelerate.aliyuncs.com),SDK 直传到加速节点完成上传:

VODVideoMeta meta = new VODVideoMeta.Builder()
        .setTitle("我的视频")
        .setUserData("{\"Type\":\"oss\",\"Domain\":\"oss-accelerate.aliyuncs.com\"}")
        .build();
说明

上传加速能力依赖 OSS 全球传输加速,需在 OSS 控制台对 Bucket 开启传输加速。详情请参见通过传输加速访问OSS

上传转码

通过 VODVideoMeta 指定转码模板组或工作流:

VODVideoMeta meta = new VODVideoMeta.Builder()
        .setTitle("我的视频")
        .setDescription("视频描述")
        .setCoverUrl("https://example.com/cover.jpg")
        .setCateId(1000)
        .setTags("tag1,tag2")
        .setStorageLocation("<可选:自定义存储区域>")
        .setTemplateGroupId("<你的模板组 ID>")    // 转码模板组
        .setWorkflowId("<你的工作流 ID>")          // 工作流(可选)
        .setAppId("<可选:应用 ID>")
        .build();

VODVideoMeta 支持的字段:title / description / coverUrl / cateId / tags / userData / storageLocation / templateGroupId / workflowId / appId。所有字段均可选,最终透传到 CreateUploadVideo

上传完成后 VOD 服务端根据模板组对源视频转码。若不希望触发转码,业务后端在 CreateUploadVideo 时传入"无转码"模板组即可。

超时重试

VODUploadConfig config = new VODUploadConfig.Builder()
        .setGetAuth(getAuth)
        .setTimeout(60 * 1000)        // 单位:毫秒,默认 60s
        .setMaxRetryCount(2)          // 默认 2 次
        .build();

timeout 控制单次 OSS 请求的连接 / 读写超时(单位毫秒);maxRetryCount 控制 OSS 请求在网络异常时的重试次数。

签名版本

VODUploadConfig config = new VODUploadConfig.Builder()
        .setGetAuth(getAuth)
        .setSignature("v4")          // 默认 "v4",可选 "v1"
        .build();

OSS V4 签名是当前推荐版本,自 2025-09-01 起新建 Bucket 强制使用 V4 签名,存量客户也建议尽快迁移。仅当业务方依赖的 Bucket 仍只支持 V1 签名时才需显式设置 "v1"

断点续传

默认开启。SDK 使用 (lastModified, fileName, fileSize) 三元组作为续传 key,自动持久化到 SharedPreferences:

场景

SDK 行为

上传途中调用 task.cancel()

保留续传记录,下次同文件 upload(...) 自动续传

App 崩溃 / 进程被杀

保留续传记录,下次冷启同文件 upload(...) 自动续传

文件指纹任一变化

视为新文件,全新上传

OSS uploadId 过期

SDK 自动清除旧记录,重新走 CREATE_VIDEO 全新上传

如需关闭:

new VODUploadConfig.Builder().setGetAuth(getAuth).setCheckpoint(false).build();

分片上传

通过 partSize 控制分片大小、parallel 控制并发分片数:

// 全局配置
VODUploadConfig config = new VODUploadConfig.Builder()
        .setGetAuth(getAuth)
        .setPartSize(1024 * 1024)     // 默认 1MB
        .setParallel(4)               // 默认 4
        .build();

// 单次任务覆盖
VODUploadOptions options = new VODUploadOptions.Builder()
        .setVideoMeta(meta)
        .setPartSize(2 * 1024 * 1024)
        .setParallel(6)
        .build();

设置点播服务地域

new VODUploadConfig.Builder()
        .setGetAuth(getAuth)
        .setRegion("cn-shanghai")     // 默认 cn-shanghai
        .build();

支持的 region 列表见点播地域标识

数据上报

SDK 默认开启上传链路埋点用于产品质量监控,仅采集上传过程的运行指标,不包含文件内容。如需关闭:

VODUploadConfig config = new VODUploadConfig.Builder()
        .setGetAuth(getAuth)
        .setReportEnabled(false)     // 默认 true
        .build();

错误处理

VODUploadError 继承自 java.lang.Exception,错误码采用 UPLOAD.{LAYER}.{TYPE} 三段式:

LAYER

错误码

含义

AUTH

UPLOAD.AUTH.GET_AUTH_FAILED

getAuth 回调失败

AUTH

UPLOAD.AUTH.DECODE_FAILED

UploadAuth 解码失败

AUTH

UPLOAD.AUTH.EXPIRED

凭证过期

OSS

UPLOAD.OSS.ACCESS_DENIED

OSS 拒绝访问(权限/签名)

OSS

UPLOAD.OSS.NO_SUCH_BUCKET

Bucket 不存在

OSS

UPLOAD.OSS.NO_SUCH_UPLOAD

uploadId 过期(SDK 自动 fallback)

OSS

UPLOAD.OSS.UPLOAD_FAILED

OSS 上传失败

OSS

UPLOAD.OSS.MERGE_FAILED

OSS 分片合并失败

NETWORK

UPLOAD.NETWORK.TIMEOUT

网络超时

NETWORK

UPLOAD.NETWORK.UNREACHABLE

网络不可达

FILE

UPLOAD.FILE.NOT_FOUND

文件不存在

FILE

UPLOAD.FILE.EMPTY

文件为空

CANCEL

UPLOAD.CANCEL.USER_CANCELLED

用户取消

INTERNAL

UPLOAD.INTERNAL.DISPOSED

实例已 dispose

INTERNAL

UPLOAD.INTERNAL.INVALID_CONFIG

配置非法

公开方法:

  • String getErrorCode() — 错误码。

  • String getErrorMessage() — 错误信息。

  • String getUploadTaskId() — 上传任务 ID。

  • String getSuggestion() — SDK 内置的修复建议。

  • Throwable getCause() — 底层 OSS 异常(继承自 Exception)。

@Override public void onFailure(VODUploadError e) {
    if (e.getErrorCode().startsWith("UPLOAD.AUTH.")) {
        // 提醒用户检查后端鉴权
    } else if (VODUploadError.OSS_UPLOAD_FAILED.equals(e.getErrorCode())) {
        // 重试或提示用户检查网络
    }
    Log.e(TAG, e.getErrorCode() + ": " + e.getErrorMessage()
            + " (suggestion=" + e.getSuggestion() + ")", e.getCause());
}

常见问题

能否同时发起多个upload

可以,每个 task 独立。建议根据网络情况控制并发数,避免与 parallel 叠加放大上行带宽压力。

取消后再次upload没有续传

请按以下步骤排查:

  1. 确认是否同一文件路径;

  2. 确认文件 lastModified / size 是否变化;

  3. 确认config.checkpoint 是否为 true

  4. 确认uploadId 是否过期(响应 NoSuchUpload 时 SDK 自动 fallback 全新上传,属预期行为)。

上传content://UrifileName/fileSize拿到的是什么

SDK 通过 ContentResolver.query(...) 读取 OpenableColumns.DISPLAY_NAME 与 OpenableColumns.SIZE。读不到 size 直接返回 UPLOAD.FILE.EMPTY

getCause()返回什么

继承自 Exception,保留底层 OSS ServerException / ClientException / IOException 等,便于深度排查。