O SDK de upload para iOS do ApsaraVideo VOD permite que seu aplicativo envie arquivos de vídeo e imagem diretamente para o armazenamento do VOD. O aplicativo obtém credenciais de upload por meio de um service de autorização no backend, e o SDK utiliza essas credenciais para enviar os arquivos ao OSS sem rotear a mídia pelo seu servidor.
Como funciona
O processo de upload envolve três partes: seu aplicativo iOS, seu service de backend e o ApsaraVideo VOD (que armazena os arquivos no OSS). O fluxo de trabalho é o seguinte:
Seu aplicativo chama o SDK para iniciar um upload. O SDK aciona o callback
getAuth.No callback, seu aplicativo solicita credenciais de upload ao seu service de backend. Esse service chama uma operação da OpenAPI do VOD (como
CreateUploadVideo) e retorna a resposta.Seu aplicativo passa a resposta da OpenAPI para o SDK. O SDK extrai
UploadAutheUploadAddressda resposta e envia o arquivo diretamente para o OSS.Caso as credenciais expirem durante um upload grande, o SDK aciona novamente o callback
getAuthcom um tipo de atualização para obter novas credenciais.
Pré-requisitos
|
Item |
Requisito |
|
Versão mínima do iOS |
iOS 12.0 |
|
Linguagem de desenvolvimento |
Objective-C (projetos Swift usam um Bridging Header para integração) |
|
Conta Alibaba Cloud |
ApsaraVideo VOD ativado |
|
Service de autorização |
Um service de backend preparado para emitir credenciais de upload (UploadAuth) |
Integrar o SDK
Método de integração
Opção 1: Integração via Pod
Adicione o seguinte conteúdo ao seu Podfile:
platform :ios, '12.0'
target 'YourApp' do
pod 'VODUpload', '~> 2.0'
end
Execute os seguintes comandos:
pod repo update
pod install
O SDK baixa automaticamente a dependência subjacente AliyunOSSiOS.
Opção 2: Integração via Swift Package Manager (SPM)
No menu File do Xcode, selecione Add Package Dependencies e insira o endereço do repositório: https://github.com/aliyunvideo/VODUpload.git.
Selecione Up to Next Major Version como regra de versão e defina 2.0.1 como versão inicial.
Adicione o product VODUpload ao target do seu App.
Ou declare-o no Package.swift:
1.package(url: "https://github.com/aliyunvideo/VODUpload.git", from: "2.0.1")
As dependências subjacentes do OSS são analisadas automaticamente junto com o pacote principal. Não é necessário adicioná-las ou configurá-las manualmente. Após concluir a integração, basta importar o VODUpload. O uso da API é idêntico ao da integração via CocoaPods.
Configuração do projeto
O podspec declara as seguintes bibliotecas de sistema, vinculadas automaticamente quando você usa o CocoaPods para integração:
SystemConfiguration.framework
MobileCoreServices.framework
CoreMedia.framework
AVFoundation.framework
CoreTelephony.framework
libresolv.tbd
O SDK inclui um manifesto de privacidade PrivacyInfo.xcprivacy que é injetado automaticamente em VODUpload.bundle/PrivacyInfo.xcprivacy durante a integração via pod. Nenhuma configuração adicional é necessária.
Importe os arquivos de cabeçalho necessários:
#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>
Fluxo de trabalho de upload
Inicializar uma instância de upload
O VODUploadConfig utiliza propriedades para configuração direta. Chame o método de fábrica +uploaderWithConfig: para criar uma instância:
VODUploadConfig *config = [[VODUploadConfig alloc] init];
config.getAuth = getAuth; // Required: authorization callback. For more information, see "Handle authorization callbacks".
VODUploadV2Client *uploader = [VODUploadV2Client uploaderWithConfig:config];
A instância uploader deve ser retida como uma propriedade. Se for uma variável local, o ARC a liberará, causando perda de callbacks. É possível reutilizar a mesma instância para enviar vários arquivos simultaneamente. Chame [uploader dispose] para liberar recursos quando o ciclo de vida terminar.
Enviar arquivos
Chame uploadFile:options:callback: para iniciar um upload. O método retorna um identificador VODUploadTask que pode ser usado para cancelamento:
VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"My Video";
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);
}];
// Cancel during upload. Resumable upload is enabled by default. The next uploadFile call with the same file automatically resumes the upload.
[task cancel];
// task.uploadTaskId can be used to correlate logs and integrate with tracking.
Upload de imagens: O SDK utiliza automaticamente o processo de upload de imagens com base na extensão do arquivo (jpg / jpeg / png / gif / bmp / webp / heic) ou se options.imageMeta != nil estiver definido explicitamente. No callback de sucesso, imageId e imageUrl terão valores preenchidos:
VODImageMeta *imgMeta = [[VODImageMeta alloc] init];
imgMeta.imageType = @"cover";
imgMeta.title = @"Cover";
VODUploadOptions *opts = [[VODUploadOptions alloc] init];
opts.imageMeta = imgMeta;
[uploader uploadFile:imagePath options:opts callback:cb];
O campo de descrição do VODVideoMeta é desc (e não description, para evitar conflitos com o método reservado do Objective-C).
Tratar callbacks de autorização
Na versão 2, o bloco VODGetAuthCallback solicita credenciais de upload ao seu aplicativo. O SDK chama getAuth em pontos específicos e usa VODAuthContext.kind para indicar o tipo de credencial necessário:
|
Kind |
Gatilho |
OpenAPI a ser chamada |
|
VODAuthKindCreateVideo |
Primeiro upload de um arquivo de vídeo |
|
|
VODAuthKindRefreshVideo |
Upload retomável / atualização de credencial |
|
|
VODAuthKindCreateImage |
Upload de imagem |
Sua aplicação passa a resposta JSON bruta da chamada OpenAPI do backend diretamente para completion. O SDK lê as seguintes chaves da resposta da OpenAPI pelo nome do campo (diferencia maiúsculas de minúsculas):
|
Kind |
Campos obrigatórios |
|
VODAuthKindCreateVideo / VODAuthKindRefreshVideo |
UploadAuth, UploadAddress, VideoId |
|
VODAuthKindCreateImage |
UploadAuth, UploadAddress, ImageId, ImageURL (repassado para result.imageUrl) |
Os nomes dos campos diferenciam maiúsculas de minúsculas. Repasse a resposta da OpenAPI diretamente. Renomear manualmente os campos para videoId, imageUrl ou image_url fará com que o SDK os interprete como 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;
}
};
Configurações avançadas
Aceleração de upload
Defina VODVideoMeta.userData com o seguinte JSON. O servidor VOD retorna automaticamente o endpoint de aceleração de transferência global do OSS (oss-accelerate.aliyuncs.com) ao emitir o UploadAddress. Em seguida, o SDK envia diretamente para o endpoint de aceleração:
VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"My Video";
meta.userData = @"{\"Type\":\"oss\",\"Domain\":\"oss-accelerate.aliyuncs.com\"}";
A aceleração de upload depende da aceleração de transferência global do OSS. É necessário ativar a aceleração de transferência para o bucket no console do OSS. Para mais informações, consulte Access OSS using transfer acceleration.
Upload e transcodificação
Especifique um grupo de modelos de transcodificação ou workflow usando VODVideoMeta:
VODVideoMeta *meta = [[VODVideoMeta alloc] init];
meta.title = @"My Video";
meta.desc = @"Video description"; // Note: use desc, not description
meta.coverUrl = @"https://example.com/cover.jpg";
meta.cateId = @(1000);
meta.tags = @"tag1,tag2";
meta.storageLocation = @"<Optional: custom storage region>";
meta.templateGroupId = @"<Your template group ID>"; // Transcoding template group
meta.workflowId = @"<Your workflow ID>"; // Workflow (optional)
meta.appId = @"<Optional: application ID>";
Campos suportados pelo VODVideoMeta: title, desc, coverUrl, cateId, tags, userData, storageLocation, templateGroupId, workflowId e appId. Todos os campos são opcionais e repassados para CreateUploadVideo.
Após a conclusão do upload, o servidor VOD transcodifica o vídeo original com base no grupo de modelos. Caso não deseje acionar a transcodificação, passe um grupo de modelos "sem transcodificação" ao chamar CreateUploadVideo no seu backend.
Timeout e nova tentativa
VODUploadConfig *config = [[VODUploadConfig alloc] init];
config.getAuth = getAuth;
config.timeout = 60; // Unit: seconds. Default value: 60
config.maxRetryCount = 2; // Default value: 2
O parâmetro timeout controla o tempo limite de conexão e leitura/escrita (NSTimeInterval, em segundos) para uma única solicitação ao OSS. Já o maxRetryCount define o número de novas tentativas para solicitações ao OSS em caso de erros de rede.
A unidade de timeout é milissegundos no Android e segundos no iOS. Atenção a essa diferença ao integrar em múltiplas plataformas.
Versão da assinatura
config.signature = @"v4"; // Default value: @"v4". Valid values: @"v1"
A assinatura V4 do OSS é a versão recomendada. A partir de 1º de setembro de 2025, a assinatura V4 será obrigatória para buckets recém-criados. Recomenda-se também que clientes existentes migrem o quanto antes. Defina @"v1" explicitamente apenas se o bucket utilizado pela sua aplicação ainda suportar exclusivamente assinaturas V1.
Upload retomável
O upload retomável vem ativado por padrão. O SDK usa a tríade (lastModified, fileName, fileSize) como chave de retomada e a persiste automaticamente no diretório local Caches:
|
Cenário |
Comportamento do SDK |
|
Chamada de |
O registro de upload retomável é mantido. A próxima chamada de |
|
Falha do aplicativo ou encerramento em segundo plano |
O registro de upload retomável é mantido. A próxima chamada de |
|
Qualquer alteração na impressão digital do arquivo |
O arquivo é tratado como novo e enviado desde o início. |
|
Expiração do uploadId no OSS |
O SDK limpa automaticamente o registro antigo e inicia um novo upload via VODAuthKindCreateVideo. |
Para desativar o upload retomável:
config.checkpoint = NO;
Upload multipart
Utilize partSize para controlar o tamanho das partes e parallel para definir o número de partes simultâneas:
// Global configuration
config.partSize = 1024 * 1024; // Default value: 1 MB
config.parallel = 4; // Default value: 4
// Per-task override
VODUploadOptions *options = [[VODUploadOptions alloc] init];
options.videoMeta = meta;
options.partSize = 2 * 1024 * 1024;
options.parallel = 6;
Definir a região do service VOD
config.region = @"cn-shanghai"; // Default value: cn-shanghai
Para consultar a lista de regiões suportadas, veja ApsaraVideo VOD region IDs.
Relatório de dados
O SDK ativa o rastreamento de link de upload por padrão para monitoramento da qualidade do product. Apenas métricas de tempo de execução do processo de upload são coletadas, sem inclusão do conteúdo dos arquivos. Para desativar o relatório de dados:
config.reportEnabled = NO; // Default value: YES
Tratamento de erros
O VODUploadError herda de NSError. Os códigos de erro seguem o formato de três segmentos UPLOAD.{LAYER}.{TYPE}:
|
LAYER |
Código de erro |
Descrição |
|
AUTH |
UPLOAD.AUTH.GET_AUTH_FAILED |
Falha no callback getAuth. |
|
AUTH |
UPLOAD.AUTH.DECODE_FAILED |
Falha ao decodificar UploadAuth. |
|
AUTH |
UPLOAD.AUTH.EXPIRED |
A credencial expirou. |
|
OSS |
UPLOAD.OSS.ACCESS_DENIED |
Acesso negado ao OSS (problema de permissão/assinatura). |
|
OSS |
UPLOAD.OSS.NO_SUCH_BUCKET |
O bucket não existe. |
|
OSS |
UPLOAD.OSS.NO_SUCH_UPLOAD |
O uploadId expirou. O SDK faz fallback automaticamente. |
|
OSS |
UPLOAD.OSS.UPLOAD_FAILED |
Falha no upload para o OSS. |
|
OSS |
UPLOAD.OSS.MERGE_FAILED |
Falha na mesclagem multipart do OSS. |
|
NETWORK |
UPLOAD.NETWORK.TIMEOUT |
Tempo limite de rede esgotado. |
|
NETWORK |
UPLOAD.NETWORK.UNREACHABLE |
Rede inacessível. |
|
FILE |
UPLOAD.FILE.NOT_FOUND |
O arquivo não existe. |
|
FILE |
UPLOAD.FILE.EMPTY |
O arquivo está vazio. |
|
CANCEL |
UPLOAD.CANCEL.USER_CANCELLED |
O usuário cancelou o upload. |
|
INTERNAL |
UPLOAD.INTERNAL.DISPOSED |
A instância foi descartada. |
|
INTERNAL |
UPLOAD.INTERNAL.INVALID_CONFIG |
A configuração é inválida. |
Propriedades públicas:
NSString *errorCode— Código de erroNSString *errorMessage— Mensagem de erroNSError *cause— Exceção subjacente do OSSNSString *uploadTaskId— ID da tarefa de uploadNSString *suggestion— Sugestão de correção integrada do SDK
if ([error.errorCode hasPrefix:@"UPLOAD.AUTH."]) {
// Prompt the user to check the backend authorization
} else if ([error.errorCode isEqualToString:VODErrorCodeOssUploadFailed]) {
// Retry or prompt the user to check the network
}
NSLog(@"%@ : %@ (cause=%@, suggestion=%@)",
error.errorCode, error.errorMessage, error.cause, error.suggestion);
Perguntas frequentes
Posso iniciar várias chamadas uploadFile simultaneamente?
Sim. Cada task é independente. Controle o número de uploads simultâneos conforme as condições da rede para evitar pressão excessiva na largura de banda de upstream causada pela combinação com parallel.
O upload retomável não funciona após cancelamento e novo envio
Solucione o problema executando as etapas abaixo:
Verifique se o caminho do arquivo é o mesmo.
Confira se o lastModified ou o tamanho do arquivo foi alterado.
Certifique-se de que
config.checkpointesteja definido comoYES.Valide se o uploadId expirou. Ao receber a resposta
NoSuchUpload, o SDK reverte automaticamente para um novo upload. Esse comportamento é esperado.
Revisão do App Store Connect rejeitada com "missing privacy manifest"
O SDK inclui um arquivo PrivacyInfo.xcprivacy que é injetado automaticamente durante a integração via pod. Certifique-se de que seu app também declare a Required Reason API que ele utiliza.
Callbacks não são acionados após criar o uploader
Garanta que uploader não seja uma variável local. A instância VODUploadV2Client deve ser retida como propriedade de self. Caso contrário, o ARC a liberará prematuramente.