使用iOS SDK上传文件

更新时间:
复制 MD 格式

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

前提条件

项目

要求

最低 iOS 版本

iOS 12.0

开发语言

Objective-C(Swift 工程通过 Bridging Header 桥接)

阿里云账号

已开通视频点播服务

鉴权服务

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

集成SDK

集成方式

在 Podfile 中加入:

platform :ios, '12.0'
target 'YourApp' do
  pod 'VODUpload', '~> 2.0'
end

执行:

pod repo update
pod install

SDK 会自动拉取底层 AliyunOSSiOS 依赖。

项目配置

podspec 已声明以下系统库,使用 CocoaPods 集成时自动链接:

SystemConfiguration.framework
MobileCoreServices.framework
CoreMedia.framework
AVFoundation.framework
CoreTelephony.framework
libresolv.tbd

SDK 自带 PrivacyInfo.xcprivacy 隐私清单,随 Pod 集成自动注入到 VODUpload.bundle/PrivacyInfo.xcprivacy,无需额外配置。

按需引入头文件:

#import <VODUpload/VODUploadV2Client.h>
#import <VODUpload/VODUploadConfig.h>
#import <VODUpload/VODAuthContext.h>
#import <VODUpload/VODGetAuthCallback.h>
#import <VODUpload/VODUploadOptions.h>
#import <VODUpload/VODUploadResult.h>
#import <VODUpload/VODUploadError.h>
#import <VODUpload/VODVideoMeta.h>
#import <VODUpload/VODImageMeta.h>
#import <VODUpload/VODUploadTask.h>

基础设置

初始化上传实例

VODUploadConfig 使用 property 直接设置,调用 +uploaderWithConfig: 工厂方法创建实例:

VODUploadConfig *config = [[VODUploadConfig alloc] init];
config.getAuth = getAuth;                  // 必填:鉴权回调,详见"回调处理"

VODUploadV2Client *uploader = [VODUploadV2Client uploaderWithConfig:config];

uploader 实例应作为属性持有(不能是局部变量,否则会被 ARC 释放导致回调丢失)。可复用同一实例并发上传多个文件,生命周期结束时调用 [uploader dispose] 释放资源。

上传控制

调用 uploadFile:options:callback: 启动一次上传,返回 VODUploadTask 句柄用于取消:

VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"我的视频";
meta.tags = @"demo";
meta.cateId = @(1000);

VODUploadOptions *options = [[VODUploadOptions alloc] init];
options.videoMeta = meta;
options.onProgress = ^(float percent, int64_t uploaded, int64_t total) {
    NSLog(@"%.1f%%", percent * 100);
};

VODUploadTask *task = [uploader uploadFile:filePath
                                   options:options
                                  callback:^(VODUploadResult *r, VODUploadError *e) {
    if (e) {
        NSLog(@"%@: %@", e.errorCode, e.errorMessage);
        return;
    }
    NSLog(@"videoId=%@ uploadTaskId=%@ etag=%@ requestId=%@ durationMs=%lld",
          r.videoId, r.uploadTaskId, r.etag, r.requestId, r.durationMs);
}];

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

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

VODImageMeta *imgMeta = [[VODImageMeta alloc] init];
imgMeta.imageType = @"cover";
imgMeta.title = @"封面";

VODUploadOptions *opts = [[VODUploadOptions alloc] init];
opts.imageMeta = imgMeta;

[uploader uploadFile:imagePath options:opts callback:cb];
说明

VODVideoMeta 的描述字段为 desc(非 description,避免与 Objective-C 保留方法冲突)。

回调处理

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

Kind

触发时机

业务方应调用的 OpenAPI

VODAuthKindCreateVideo

首次上传一个视频文件

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

VODAuthKindRefreshVideo

续传 / 凭证刷新

刷新视频上传凭证

VODAuthKindCreateImage

上传图片

获取图片上传地址和凭证

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

Kind

必须包含的字段

VODAuthKindCreateVideo / VODAuthKindRefreshVideo

UploadAuthUploadAddressVideoId

VODAuthKindCreateImage

UploadAuthUploadAddressImageIdImageURL(透传到 result.imageUrl

说明

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

VODGetAuthCallback getAuth = ^(VODAuthContext *ctx,
                               void (^completion)(NSDictionary *result, NSError *error)) {
    switch (ctx.kind) {
        case VODAuthKindCreateVideo:
            [YourBackend createUploadVideo:ctx.fileName
                                  fileSize:ctx.fileSize
                                completion:^(NSDictionary *json, NSError *err) {
                completion(json, err);
            }];
            break;
        case VODAuthKindRefreshVideo:
            [YourBackend refreshUploadVideo:ctx.videoId
                                 completion:^(NSDictionary *json, NSError *err) {
                completion(json, err);
            }];
            break;
        case VODAuthKindCreateImage:
            [YourBackend createUploadImage:ctx.fileName
                                completion:^(NSDictionary *json, NSError *err) {
                completion(json, err);
            }];
            break;
    }
};

高级设置

上传加速

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

VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"我的视频";
meta.userData = @"{\"Type\":\"oss\",\"Domain\":\"oss-accelerate.aliyuncs.com\"}";
说明

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

上传转码

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

VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"我的视频";
meta.desc = @"视频描述";                     // 注意:是 desc,不是 description
meta.coverUrl = @"https://example.com/cover.jpg";
meta.cateId = @(1000);
meta.tags = @"tag1,tag2";
meta.storageLocation = @"<可选:自定义存储区域>";
meta.templateGroupId = @"<你的模板组 ID>";    // 转码模板组
meta.workflowId = @"<你的工作流 ID>";          // 工作流(可选)
meta.appId = @"<可选:应用 ID>";

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

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

超时重试

VODUploadConfig *config = [[VODUploadConfig alloc] init];
config.getAuth = getAuth;
config.timeout = 60;            // 单位:秒,默认 60
config.maxRetryCount = 2;       // 默认 2 次

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

说明

Android timeout 单位是毫秒,iOS 单位是秒,跨端集成时注意区分。

签名版本

1config.signature = @"v4";        // 默认 @"v4",可选 @"v1"

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

断点续传

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

场景

SDK 行为

上传途中调用 [task cancel]

保留续传记录,下次同文件 uploadFile: 自动续传

App 崩溃 / 后台被杀

保留续传记录,下次冷启同文件 uploadFile: 自动续传

文件指纹任一变化

视为新文件,全新上传

OSS uploadId 过期

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

如需关闭:

config.checkpoint = NO;

分片上传

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

// 全局配置
config.partSize = 1024 * 1024;     // 默认 1MB
config.parallel = 4;               // 默认 4

// 单次任务覆盖
VODUploadOptions *options = [[VODUploadOptions alloc] init];
options.videoMeta = meta;
options.partSize = 2 * 1024 * 1024;
options.parallel = 6;

设置点播服务地域

1config.region = @"cn-shanghai";    // 默认 cn-shanghai

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

数据上报

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

config.reportEnabled = NO;       // 默认 YES

错误处理

VODUploadError 继承自 NSError,错误码采用 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

配置非法

公开属性:

  • NSString *errorCode — 错误码

  • NSString *errorMessage — 错误信息

  • NSError *cause — 底层 OSS 异常

  • NSString *uploadTaskId — 上传任务 ID

  • NSString *suggestion — SDK 内置的修复建议

if ([error.errorCode hasPrefix:@"UPLOAD.AUTH."]) {
    // 提醒用户检查后端鉴权
} else if ([error.errorCode isEqualToString:VODErrorCodeOssUploadFailed]) {
    // 重试或提示用户检查网络
}
NSLog(@"%@ : %@ (cause=%@, suggestion=%@)",
      error.errorCode, error.errorMessage, error.cause, error.suggestion);

常见问题

能否同时发起多个 uploadFile

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

取消后再次 uploadFile 没有续传

请按以下步骤排查:

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

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

  3. 确认config.checkpoint 是否为 YES

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

App Store Connect 审核被拒,提示 Missing Privacy Manifest

SDK 已自带 PrivacyInfo.xcprivacy 并随 Pod 自动注入。同时 App 自身也需声明所使用的 Required Reason API。

uploader 创建后回调不触发

确认 uploader 不是局部变量。VODUploadV2Client 实例需要作为 self 的属性持有,否则会被 ARC 提前释放。