本文介绍如何使用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 |
| 首次上传一个视频文件 | |
| 续传 / 凭证刷新 | |
| 上传图片 |
业务方只需把后端 OpenAPI 返回的原始 JSON 原样回传给 SDK。SDK 按 OpenAPI 原始字段名(大小写敏感)读取以下键:
Kind | 必须包含的字段 |
|
|
|
|
字段名大小写敏感,请直接转发 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 行为 |
上传途中调用 | 保留续传记录,下次同文件 |
App 崩溃 / 进程被杀 | 保留续传记录,下次冷启同文件 |
文件指纹任一变化 | 视为新文件,全新上传 |
OSS uploadId 过期 | SDK 自动清除旧记录,重新走 |
如需关闭:
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 |
| getAuth 回调失败 |
AUTH |
| UploadAuth 解码失败 |
AUTH |
| 凭证过期 |
OSS |
| OSS 拒绝访问(权限/签名) |
OSS |
| Bucket 不存在 |
OSS |
| uploadId 过期(SDK 自动 fallback) |
OSS |
| OSS 上传失败 |
OSS |
| OSS 分片合并失败 |
NETWORK |
| 网络超时 |
NETWORK |
| 网络不可达 |
FILE |
| 文件不存在 |
FILE |
| 文件为空 |
CANCEL |
| 用户取消 |
INTERNAL |
| 实例已 dispose |
INTERNAL |
| 配置非法 |
公开方法:
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没有续传
请按以下步骤排查:
确认是否同一文件路径;
确认文件 lastModified / size 是否变化;
确认
config.checkpoint是否为true;确认uploadId 是否过期(响应
NoSuchUpload时 SDK 自动 fallback 全新上传,属预期行为)。
上传content://Uri时fileName/fileSize拿到的是什么
SDK 通过 ContentResolver.query(...) 读取 OpenableColumns.DISPLAY_NAME 与 OpenableColumns.SIZE。读不到 size 直接返回 UPLOAD.FILE.EMPTY。
getCause()返回什么
继承自 Exception,保留底层 OSS ServerException / ClientException / IOException 等,便于深度排查。