全部產品
Search
文件中心

ApsaraVideo VOD:使用Android SDK上傳檔案

更新時間:Jul 10, 2026

本文介紹如何使用Android SDK將媒體檔案從本地上傳至點播儲存。

前提條件

專案

要求

最低 Android 版本

API 14(Android 4.0)

編譯版本

compileSdkVersion 30

阿里雲帳號

開通ApsaraVideo for VOD

鑒權服務

已準備好可簽發上傳憑證(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://Uri時fileName/fileSize拿到的是什麼

SDK 通過 ContentResolver.query(...) 讀取 OpenableColumns.DISPLAY_NAME 與 OpenableColumns.SIZE。讀不到 size 直接返回 UPLOAD.FILE.EMPTY

getCause()返回什麼

繼承自 Exception,保留底層 OSS ServerException / ClientException / IOException 等,便於深度排查。