iOS开发中集成阿里云视频上传SDK总结
来源:互联网 发布:百度指数如何导出知乎 编辑:程序博客网 时间:2024/05/23 07:23
阿里云iOS视频上传SDK说明文档
安装
说明1:这两个Framework均需导入。
说明2:此处引入头文件
#import <VODUpload/VODUploadClient.h>#import <VODUpload/VODUploadModel.h>
实例化
首先,添加属性
@property (nonatomic, strong) VODUploadClient *uploader;@property (nonatomic, strong) NSString *UploadAuth;@property (nonatomic, strong) NSString *UploadAddress;
然后,初始化
#pragma mark --初始化- (void)initVODUpload { __weak typeof(self) weakSelf = self; OnUploadStartedListener testUploadStartedCallbackFunc = ^(UploadFileInfo* fileInfo) { NSLog(@"upload started ."); [weakSelf.uploader setUploadAuthAndAddress:fileInfo uploadAuth:self.UploadAuth uploadAddress:self.UploadAddress]; }; OnUploadSucceedListener testSuccessCallbackFunc = ^(UploadFileInfo* fileInfo){ NSLog(@"file:%@ upload success!", fileInfo.filePath); }; OnUploadFailedListener testFailedCallbackFunc = ^(UploadFileInfo* fileInfo, NSString *code, NSString * message){ NSLog(@"failed, filePath:%@, code = %@, error message = %@", fileInfo.filePath, code, message); }; // 单位:字节 OnUploadProgressListener testProgressCallbackFunc = ^(UploadFileInfo* fileInfo, long uploadedSize, long totalSize) { NSLog(@"progress uploadedSize : %li, totalSize : %li", uploadedSize, totalSize); }; OnUploadTokenExpiredListener testTokenExpiredCallbackFunc = ^{ NSLog(@"*token expired."); // get token and call resmeUploadWithAuth. }; OnUploadRertyListener testUploadRertyListener = ^{ NSLog(@"retry begin."); }; OnUploadRertyResumeListener testUploadRertyResumeListener = ^{ NSLog(@"retry resume."); }; VODUploadListener *listener; listener = [[VODUploadListener alloc] init]; listener.started = testUploadStartedCallbackFunc; listener.success = testSuccessCallbackFunc; listener.failure = testFailedCallbackFunc; listener.progress = testProgressCallbackFunc; listener.expire = testTokenExpiredCallbackFunc; listener.retry = testUploadRertyListener; listener.retryResume = testUploadRertyResumeListener; self.uploader = [[VODUploadClient alloc] init]; [self.uploader init:@"替换为你的AccessKeyId" accessKeySecret:@"替换为你的AccessKeySecret" listener:listener];}
注意:AccessKeyId和AccessKeySecret需要替换
上传视频
#pragma mark --上传视频文件- (void)uploadVideo:(HQVideoListModel *)model { //添加上传文件 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *filePath = [[paths firstObject] stringByAppendingString:[NSString stringWithFormat:@"/%@", model.fileName]]; NSLog(@"上传视频文件:%@", filePath); [self.uploader addFile:filePath vodInfo:nil]; //注意:开始上传前要先获取授权,开始上传时需要用到授权信息 [self getUploadAuthAndAddressWithFilePath:filePath];}
注意1:使用说明 中的流程是:用户选择文件 -> 添加文件到列表 -> 开始上传 -> 设置上传凭证和地址 -> 上传完成事件。但是,实际上我们要在开始上传前获取上传凭证和地址。
注意2:在开始上传的回调中设置上传凭证和地址
__weak typeof(self) weakSelf = self; OnUploadStartedListener testUploadStartedCallbackFunc = ^(UploadFileInfo* fileInfo) { NSLog(@"upload started ."); [weakSelf.uploader setUploadAuthAndAddress:fileInfo uploadAuth:self.UploadAuth uploadAddress:self.UploadAddress]; };
下面才是本文的重点
获取上传凭证和地址
#pragma mark --获取授权- (void)getUploadAuthAndAddressWithFilePath:(NSString *)filePath { if (!filePath) { NSLog(@"视频文件路径错误"); return; } NSArray *arr1 = [filePath componentsSeparatedByString:@"/"]; NSString *fileName = [arr1 lastObject]; if (!fileName) { NSLog(@"获取视频文件名称错误"); return; } NSArray *arr2 = [fileName componentsSeparatedByString:@"."]; NSString *fileTitle = [arr2 firstObject]; if (!fileTitle) { NSLog(@"获取视频文件标题错误"); return; } //获取时间戳 NSString *dateStr = [NSString stringWithFormat:@"%@", [NSDate date]]; dateStr = [dateStr substringWithRange:NSMakeRange(0, 19)]; dateStr = [dateStr stringByReplacingOccurrencesOfString:@" " withString:@"T"]; dateStr = [dateStr stringByAppendingString:@"Z"]; //生成随机数 NSString *randomStr = [NSString stringWithFormat:@"%d", arc4random()]; //参数 NSDictionary *parameters = @{ @"Action":@"CreateUploadVideo", @"Title":fileTitle, @"FileName":fileName, @"Format":@"JSON", @"Version":@"2017-03-21", @"AccessKeyId":@"替换为你的AccessKeyId", @"SignatureMethod":@"HMAC-SHA1", @"Timestamp":dateStr, @"SignatureVersion":@"1.0", @"SignatureNonce":randomStr, }; NSString *signedUrlStr = [self getSignedURLStrWithHost:@"http://vod.cn-shanghai.aliyuncs.com/" withParameters:parameters]; NSURL *url = [NSURL URLWithString:signedUrlStr]; NSLog(@"urlStr:%@", signedUrlStr); NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200) { NSDictionary *obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"请求成功:%@", obj); NSString *UploadAddress = [obj objectForKey:@"UploadAddress"]; NSString *UploadAuth = [obj objectForKey:@"UploadAuth"]; self.UploadAddress = UploadAddress; self.UploadAuth = UploadAuth; //开始上传 [self.uploader start]; }else { NSLog(@"请求失败:%@", error); } }]; [dataTask resume];}
注意:获取上传凭证和地址的方法有两种,一种是服务器端获取,另一种是手机端获取。
我们采用的是在手机端获取上传凭证和地址,具体做法查看API使用手册
这里边最复杂就是签名机制,下面是我写的方法,仅供参考。
#pragma mark --获取签名后的URL- (NSString *)getSignedURLStrWithHost:(NSString *)host withParameters:(NSDictionary *)parameters { //签名机制 //1.使用请求参数构造规范化的请求字符串 //a.按照参数名称的字典顺序对请求中所有的请求参数(包括文档中描述的”公共请求参数”和给定了的请求接口的自定义参数,但不能包括”公共请求参数”中提到的Signature参数本身)进行排序。 //获取所有参数 NSArray *keyArr = [parameters allKeys]; NSLog(@"排序前的keyArr:%@", keyArr); //排序 NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:descriptor]; keyArr = [keyArr sortedArrayUsingDescriptors:descriptors]; NSLog(@"排序后的keyArr:%@", keyArr); //b.对相关请求参数的名称和值进行编码 //c.对编码后的参数名称和值使用英文等号(=)进行连接 //d.再把英文等号连接得到字符串按参数名称的字典顺序依次使用&符号连接,即得到规范化请求字符串 //编码并拼接参数 NSString *parametersStr = @""; for (NSInteger i = 0; i < keyArr.count; i++) { NSString *key = keyArr[i]; NSString *value = parameters[key]; if (parametersStr.length > 0) { parametersStr = [parametersStr stringByAppendingString:@"&"]; } parametersStr = [parametersStr stringByAppendingString:[HQUtils urlStringEncoding:key]]; parametersStr = [parametersStr stringByAppendingString:@"="]; parametersStr = [parametersStr stringByAppendingString:[HQUtils urlStringEncoding:value]]; } NSLog(@"拼接的参数:%@", parametersStr); //2.使用上一步构造的规范化字符串按照下面的规则构造用于计算签名的字符串 NSString *stringToSign = [NSString stringWithFormat:@"GET&%@&%@", [HQUtils urlStringEncoding:@"/"], [HQUtils urlStringEncoding:parametersStr]]; NSLog(@"用于计算签名的字符串:%@", stringToSign); //3.按照RFC2104的定义,使用上面的用于签名的字符串计算签名HMAC值。注意:计算签名时使用的Key就是用户持有的Access Key Secret并加上一个”&”字符(ASCII:38),使用的哈希算法是SHA1。 //4.按照Base64编码规则把上面的HMAC值编码成字符串,即得到签名值(Signature)。 NSString *signature = [self hmacsha1:stringToSign key:@"替换为你的AccessKeySecret&"]; NSLog(@"签名后的字符串:%@", signature); //5.将得到的签名值作为Signature参数添加到请求参数中,即完成对请求签名的过程。 NSString *resultStr = [NSString stringWithFormat:@"%@?Signature=%@&%@", host, signature, parametersStr]; return resultStr;}#pragma mark - (NSString *)hmacsha1:(NSString *)text key:(NSString *)secret { NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; unsigned char result[20]; CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result); char base64Result[32]; size_t theResultLength = 32; Base64EncodeData(result, 20, base64Result, &theResultLength,YES); NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; NSString *base64EncodedResult = [[NSString alloc] initWithData:theData encoding:NSASCIIStringEncoding]; return base64EncodedResult;}
注意:此处需要引入三个文件
#include <CommonCrypto/CommonDigest.h>#include <CommonCrypto/CommonHMAC.h>#include "HQbase64.h"
其中,HQbase64.h的具体实现
#import <Foundation/Foundation.h>extern size_t EstimateBas64EncodedDataSize(size_t inDataSize);extern size_t EstimateBas64DecodedDataSize(size_t inDataSize);extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize, BOOL wrapped);extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize);@interface HQbase64 : NSObject@end
HQbase64.m的具体实现
#import "HQbase64.h"#include <math.h>const UInt8 kBase64EncodeTable[64] = { /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/'};/* -1 = Base64 end of data marker. -2 = White space (tabs, cr, lf, space) -3 = Noise (all non whitespace, non-base64 characters) -4 = Dangerous noise -5 = Illegal noise (null byte) */const SInt8 kBase64DecodeTable[128] = { /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3};const UInt8 kBits_00000011 = 0x03;const UInt8 kBits_00001111 = 0x0F;const UInt8 kBits_00110000 = 0x30;const UInt8 kBits_00111100 = 0x3C;const UInt8 kBits_00111111 = 0x3F;const UInt8 kBits_11000000 = 0xC0;const UInt8 kBits_11110000 = 0xF0;const UInt8 kBits_11111100 = 0xFC;size_t EstimateBas64EncodedDataSize(size_t inDataSize){ size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; return(theEncodedDataSize);}size_t EstimateBas64DecodedDataSize(size_t inDataSize){ size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; //theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; return(theDecodedDataSize);}bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize, BOOL wrapped){ size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); if (*ioOutputDataSize < theEncodedDataSize) return(false); *ioOutputDataSize = theEncodedDataSize; const UInt8 *theInPtr = (const UInt8 *)inInputData; UInt32 theInIndex = 0, theOutIndex = 0; for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) { outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; if (wrapped && (theOutIndex % 74 == 72)) { outOutputData[theOutIndex++] = '\r'; outOutputData[theOutIndex++] = '\n'; } } const size_t theRemainingBytes = inInputDataSize - theInIndex; if (theRemainingBytes == 1) { outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; outOutputData[theOutIndex++] = '='; outOutputData[theOutIndex++] = '='; if (wrapped && (theOutIndex % 74 == 72)) { outOutputData[theOutIndex++] = '\r'; outOutputData[theOutIndex++] = '\n'; } } else if (theRemainingBytes == 2) { outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; outOutputData[theOutIndex++] = '='; if (wrapped && (theOutIndex % 74 == 72)) { outOutputData[theOutIndex++] = '\r'; outOutputData[theOutIndex++] = '\n'; } } return(true);}bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize){ memset(ioOutputData, '.', *ioOutputDataSize); size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); if (*ioOutputDataSize < theDecodedDataSize) return(false); *ioOutputDataSize = 0; const UInt8 *theInPtr = (const UInt8 *)inInputData; UInt8 *theOutPtr = (UInt8 *)ioOutputData; size_t theInIndex = 0, theOutIndex = 0; UInt8 theOutputOctet; size_t theSequence = 0; for (; theInIndex < inInputDataSize; ) { SInt8 theSextet = 0; SInt8 theCurrentInputOctet = theInPtr[theInIndex]; theSextet = kBase64DecodeTable[theCurrentInputOctet]; if (theSextet == -1) break; while (theSextet == -2) { theCurrentInputOctet = theInPtr[++theInIndex]; theSextet = kBase64DecodeTable[theCurrentInputOctet]; } while (theSextet == -3) { theCurrentInputOctet = theInPtr[++theInIndex]; theSextet = kBase64DecodeTable[theCurrentInputOctet]; } if (theSequence == 0) { theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; } else if (theSequence == 1) { theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; theOutPtr[theOutIndex++] = theOutputOctet; } else if (theSequence == 2) { theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; } else if (theSequence == 3) { theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; theOutPtr[theOutIndex++] = theOutputOctet; } else if (theSequence == 4) { theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; } else if (theSequence == 5) { theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; theOutPtr[theOutIndex++] = theOutputOctet; } theSequence = (theSequence + 1) % 6; if (theSequence != 2 && theSequence != 4) theInIndex++; } *ioOutputDataSize = theOutIndex; return(true);}@implementation HQbase64@end
注意:urlStringEncoding方法的具体实现:
+(NSString *)urlStringEncoding:(NSString *)urlStr { NSString *outputStr = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes( NULL, /* allocator */ (__bridge CFStringRef)urlStr, NULL, /* charactersToLeaveUnescaped */ (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); return outputStr;}
最后,参考文章:
iOS下HMAC_SHA1加密算法
NSSortDescriptor使用注意以及直接排序字符串数组
阅读全文
0 0
- iOS开发中集成阿里云视频上传SDK总结
- 阿里云日志服务 sdk集成
- iOS开发中向服务器上传视频的实践
- iOS开发中向服务器上传视频的实践
- iOS 阿里云上传图片
- iOS开发百度地图SDK集成方法
- iOS开发支付宝 集成SDK注意事项
- IOS支付宝开发SDK的集成
- iOS开发如何集成支付宝SDK
- ThinkPHP中集成阿里大于短信发送SDK
- ThinkPHP中集成阿里大于短信发送SDK
- vue2.0集成ueditor以及图片上传,视频上传总结
- 上传视频到阿里云服务器
- iOS音视频SDK开发技术解决方案
- Android/iOS视频编辑SDK开发记
- iOS开发之集成ijkplayer视频直播
- iOS开发之集成ijkplayer视频直播
- iOS开发之集成ijkplayer视频直播
- 带有图片预览功能的上传表单
- MyBatis输出日志
- UVALive
- Android 仿美团选择城市、微信通讯录、饿了么点餐列表的导航悬停分组索引列表
- ros_network两台计算机通信
- iOS开发中集成阿里云视频上传SDK总结
- C语言入门第一章
- hdu6127 思维
- 使用java语言实现9*9乘法表
- .NET Core 2.0发布了
- 三分
- weblogic.descriptor.DescriptorException
- volatile关键字和CAS
- CodeForces 498 D.Traffic Jams in the Land(线段树)