AWSS3 iOS SDK 使用教程
创建AWSServiceConfiguration
方式一:自定义创建ServiceConfiguration
AWSBasicSessionCredentialsProvider *provider = [[AWSBasicSessionCredentialsProvider alloc]
initWithAccessKey:access_key secretKey:secret_key sessionToken:token];
AWSRegionType regionType = [AWSEndpoint regionTypeFromName:config.region];
AWSEndpoint *endpoint = [[AWSEndpoint alloc] initWithRegion:regionType
service:AWSServiceS3 URL:[NSURL URLWithString:config.endpoint]];
AWSServiceConfiguration *serviceConfig = [[AWSServiceConfiguration alloc]
initWithRegion:regionType endpoint:endpoint credentialsProvider:provider];
方式二: 根据IdentityPoolId创建
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1 identityPoolId:@"YourIdentityPoolId"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]
initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
获取上传对象
两种方式获取 AWSS3TransferUtility
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
AWSS3TransferUtility *S3TransferUtility = [AWSS3TransferUtility
defaultS3TransferUtility:^(NSError * _Nullable error) { }];
// 或
AWSS3TransferUtility *S3TransferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
方式2:
[AWSS3TransferUtility registerS3TransferUtilityWithConfiguration:configuration
forKey:@"USWest2S3TransferUtility"];
// 获取注册结果
[AWSS3TransferUtility registerS3TransferUtilityWithConfiguration:configuration
forKey:@"USWest2S3TransferUtility" completionHandler:^(NSError * _Nullable error) {
}];
AWSS3TransferUtility *S3TransferUtility = [AWSS3TransferUtility
S3TransferUtilityForKey:@"USWest2S3TransferUtility"];
移除上传对象 AWSS3TransferUtility
+ (void)removeS3TransferUtilityForKey:(NSString *)key;
在上传任务上传完毕后,进行移除.
可以监听AWSS3TransferUtilityURLSessionDidBecomeInvalidNotification
后,进行移除.
使用AWSS3TransferUtility进行单文件上传
// 上传进度
AWSS3TransferUtilityUploadExpression *expression =
[AWSS3TransferUtilityUploadExpression new];
expression.progressBlock = ^(AWSS3TransferUtilityTask *task, NSProgress *progress) {
!progressBlock ?: progressBlock(progress);
};
// AWSS3TransferUtility对象
AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility
S3TransferUtilityForKey:key];
// 上传NSData
[[transferUtility uploadData:data bucket:bucket key:key contentType:contentType
expression:expression completionHandler:^(AWSS3TransferUtilityUploadTask * _Nonnull task, NSError * _Nullable error) {
// 完成回调
!completionHandler ?: completionHandler(error);
}] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"AWSTask.error: %@", task.error);
}
if (task.result) {
NSLog(@"AWSTask.result: %@", task.result);
}
return nil;
}];
// 上传URL
[[transferUtility uploadFile:fileUrl bucket:bucket key:key contentType:contentType
expression:expression completionHandler:^(AWSS3TransferUtilityUploadTask * _Nonnull task, NSError * _Nullable error) {
// 完成回调
!completionHandler ?: completionHandler(error);
}] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
DLog(@"AWSTask.error: %@", task.error);
}
if (task.result) {
DLog(@"AWSTask.result: %@", task.result);
}
return nil;
}];
使用AWSS3TransferUtility进行大文件分片上传
// 上传进度
AWSS3TransferUtilityMultiPartUploadExpression *multipartExpression =
[AWSS3TransferUtilityMultiPartUploadExpression new];
multipartExpression.progressBlock = ^(AWSS3TransferUtilityMultiPartUploadTask * _Nonnull task, NSProgress * _Nonnull progress){
!progressBlock ?: progressBlock(progress);
};
// 上传对象
AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility
S3TransferUtilityForKey:key];
// NSData 上传
[[transferUtility uploadDataUsingMultiPart:data bucket:bucket key:key contentType:contentType
expression:multipartExpression completionHandler:^(AWSS3TransferUtilityMultiPartUploadTask * _Nonnull task, NSError * _Nullable error) {
!completionHandler ?: completionHandler(error);
}] continueWithBlock:^id _Nullable(AWSTask<AWSS3TransferUtilityMultiPartUploadTask *> * _Nonnull task) {
if (task.error) {
NSLog(@"AWSTask.error: %@", task.error);
}
if (task.result) {
NSLog(@"AWSTask.result: %@", task.result);
}
return nil;
}];
// NSUrl上传
[[transferUtility uploadFileUsingMultiPart:fileUrl bucket:bucket key:key contentType:contentType
expression:multipartExpression completionHandler:^(AWSS3TransferUtilityMultiPartUploadTask * _Nonnull task, NSError * _Nullable error) {
!completionHandler ?: completionHandler(error);
}] continueWithBlock:^id _Nullable(AWSTask<AWSS3TransferUtilityMultiPartUploadTask *> * _Nonnull task) {
if (task.error) {
NSLog(@"AWSTask.error: %@", task.error);
}
if (task.result) {
NSLog(@"AWSTask.result: %@", task.result);
}
return nil;
}];
使用AWSS3
获取AWSS3
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
AWSS3 *S3 = [AWSS3 defaultS3];
// 或
[AWSS3 registerS3WithConfiguration:configuration forKey:@"USWest2S3"
AWSS3 *S3 = [AWSS3 S3ForKey:@"USWest2S3"];
移除AWSS3
+ (void)removeS3ForKey:(NSString *)key;
全部上传任务完成后,才可进行移除.
使用AWSS3 单文件上传
AWSS3PutObjectRequest *request = [[AWSS3PutObjectRequest alloc] init];
request.key = key;
request.body = data;
request.bucket = bucket;
// 上传进度
request.uploadProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend){
// totalBytes: data.length 数据的总长度
// totalBytesSent: 已完成的长度
NSProgress *progress = [[NSProgress alloc] init];
progress.totalUnitCount = (int64_t)data.length;
progress.completedUnitCount = totalBytesSent;
!progressBlock ?: progressBlock(progress);
};
[S3 putObject:request completionHandler:^(AWSS3PutObjectOutput * _Nullable response, NSError * _Nullable error) {
!completionHandler ?: completionHandler(error);
}];
使用AWSS3 大文件分片上传
AWSS3TransferUtility 大文件分片上传底层同此方法.
系统默认每片大小: 5 x 1024 x 1024
分片上传逻辑
- 初始化分片上传事件: 调用initiateMultipartUpload方法返回OSS创建的全局唯一的uploadId
- 上传分片: 调用uploadPart方法上传分片数据
- 完成分片上传: 所有分片上传完成后,调用completeMultipartUpload方法将所有分片合并成完整的文件。
- 列举正在上传的分片
- 取消分片上传: 调用abortMultipartUpload方法来取消分片上传事件。
当一个分片上传事件被取消后,无法再使用这个uploadId做任何操作,已经上传的分片数据会被删除。
详细示例
// AWSUploadConfig: 自定义对象
- (void)AWSS3UploadMultipartData:(NSData *)data config:(AWSUploadConfig *)config progressBlock:(void(^)(NSProgress *progress))progressBlock completionHandler:(void (^)(NSError *error))completionHandler {
// 获取serviceConfig/注册/获取AWSS3
AWSServiceConfiguration *serviceConfig = [self createAWSServiceConfigByUploadConfig:config];
[AWSS3 registerS3WithConfiguration:serviceConfig forKey:config.key];
AWSS3 *S3 = [AWSS3 S3ForKey:config.key];
// 1.初始化分片上传事件: 调用[[AWSS3CreateMultipartUploadRequest alloc] init]方法返回OSS创建的全局唯一的uploadId
AWSS3CreateMultipartUploadRequest *createRequest = [[AWSS3CreateMultipartUploadRequest alloc] init];
createRequest.bucket = config.bucket;
createRequest.key = config.key;
WS(weakSelf);
[S3 createMultipartUpload:createRequest completionHandler:^(AWSS3CreateMultipartUploadOutput * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"createMultipartUpload 创建失败: %@", error);
} else {
config.uploadId = response.uploadId;
NSLog(@"createMultipartUpload 创建成功: %@", config.uploadId);
[weakSelf AWSS3:S3 uploadPartData:data config:config progressBlock:^(NSProgress *progress) {
!progressBlock ?: progressBlock(progress);
} complete:^(NSArray *parts) {
if (parts.count > 0) {
[weakSelf AWSS3:S3 multipartUploadParts:parts config:config complete:^(NSError *error) {
!completionHandler ?: completionHandler(error);
}];
}
}];
}
}];
}
/// 2.上传分片: 调用uploadPart方法上传分片数据
- (void)AWSS3:(AWSS3 *)S3 uploadPartData:(NSData *)data config:(AWSUploadConfig *)config progressBlock:(void(^)(NSProgress *progress))progressBlock complete:(void(^)(NSArray *parts))complete {
// 默认每片5M
NSInteger partSize = 5 * 1024 * 1024;
NSUInteger chunkSize = ceil((float)data.length /(unsigned long) partSize);
__block NSInteger location = 0;
__block NSMutableArray<AWSS3CompletedPart *> *parts = [NSMutableArray array];
int64_t totalBytes = data.length;
__block int64_t completeBytes = 0;
for (int i = 1; location < data.length; i++) {
partSize = MIN(partSize, data.length - location);
NSData *partData = [data subdataWithRange:NSMakeRange(location, partSize)];
AWSS3UploadPartRequest *uploadRequest = [[AWSS3UploadPartRequest alloc] init];
uploadRequest.bucket = config.bucket;
uploadRequest.key = config.key;
uploadRequest.uploadId = config.uploadId;
uploadRequest.partNumber = @(i);
uploadRequest.body = partData;
uploadRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
completeBytes += bytesSent;
NSProgress *progress = [[NSProgress alloc] init];
progress.totalUnitCount = totalBytes;
progress.completedUnitCount = completeBytes;
!progressBlock ?: progressBlock(progress);
};
[S3 uploadPart:uploadRequest completionHandler:^(AWSS3UploadPartOutput * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"uploadPart 失败: %@", error);
} else {
AWSS3CompletedPart *part = [[AWSS3CompletedPart alloc] init];
part.ETag = response.ETag;
part.partNumber = @(i);
[parts addObject:part];
if (parts.count == chunkSize) {
// 分片块 要求升序排列
[parts sortUsingComparator:^NSComparisonResult(AWSS3CompletedPart *obj1, AWSS3CompletedPart *obj2) {
if ([obj1.partNumber integerValue] < [obj2.partNumber integerValue]) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}];
!complete ?: complete(parts);
}
}
}];
location += partSize;
}
}
/// 3.完成分片上传: 所有分片上传完成后,调用completeMultipartUpload方法将所有分片合并成完整的文件
- (void)AWSS3:(AWSS3 *)S3 multipartUploadParts:(NSArray *)parts config:(AWSUploadConfig *)config complete:(void (^)(NSError *error))complete {
AWSS3CompletedMultipartUpload *multipartUpload = [[AWSS3CompletedMultipartUpload alloc] init];
multipartUpload.parts = parts;
AWSS3CompleteMultipartUploadRequest *completeRequest = [[AWSS3CompleteMultipartUploadRequest alloc] init];
completeRequest.bucket = config.bucket;
completeRequest.key = config.key;
completeRequest.uploadId = config.uploadId;
completeRequest.multipartUpload = multipartUpload;
[S3 completeMultipartUpload:completeRequest completionHandler:^(AWSS3CompleteMultipartUploadOutput * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"completeMultipartUpload 失败: %@", error);
} else {
// 移除AWSS3
[S3 removeS3ForKey:config.key];
NSLog(@"completeMultipartUpload 成功: %@", response.location);
!complete ?: complete(error);
}
}];
}
/// 4.列举正在上传的分片
- (void)AWSS3:(AWSS3 *)S3 abortMultipartUploadConfig:(AWSUploadConfig *)config {
AWSS3ListMultipartUploadsRequest *listRequest = [[AWSS3ListMultipartUploadsRequest alloc] init];
listRequest.bucket = config.bucket;
[S3 listMultipartUploads:listRequest completionHandler:^(AWSS3ListMultipartUploadsOutput * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"listMultipartUploads 上传失败: %@", error);
} else {
NSInteger count = response.uploads.count;
NSLog(@"listMultipartUploads: %ld", count);
/// 5. 取消分片上传
for (AWSS3MultipartUpload *upload in response.uploads) {
AWSS3AbortMultipartUploadRequest *abortRequest = [[AWSS3AbortMultipartUploadRequest alloc] init];
abortRequest.bucket = config.bucket;
abortRequest.key = config.key;
abortRequest.uploadId = upload.uploadId;
[S3 abortMultipartUpload:abortRequest completionHandler:^(AWSS3AbortMultipartUploadOutput * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"abortMultipartUpload 失败: %@", error);
} else {
NSLog(@"abortMultipartUpload 成功");
}
}];
}
}
}];
}
下载文件
/// 下载文件
- (void)AWSS3:(AWSS3 *)S3 getObjectWithFilePath:(NSString *)filePath config:(AWSUploadConfig *)config {
AWSS3GetObjectRequest *request = [[AWSS3GetObjectRequest alloc] init];
request.key = config.key;
request.bucket = config.bucket;
request.downloadingFileURL = [NSURL fileURLWithPath:filePath];
[S3 getObject:request completionHandler:^(AWSS3GetObjectOutput * _Nullable response, NSError * _Nullable error) {
}];
}
更改AWSS3签名认证支持阿里云上传
在AWSSignature.m文件中,
更改- (NSString *)signS3RequestV4:(NSMutableURLRequest *)urlRequest credentials:(AWSCredentials *)credentials
方法中的生成的authorization
- 更改contentSha256,设置为
contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hashData:[urlRequest HTTPBody]] encoding:NSASCIIStringEncoding]];
- 更改设置HTTPBodyStream:
[urlRequest setHTTPBodyStream:stream];
具体如下:
- (NSString *)aliyun_signS3RequestV4:(NSMutableURLRequest *)urlRequest
credentials:(AWSCredentials *)credentials {
if ([urlRequest valueForHTTPHeaderField:@"Content-Type"] == nil) {
[urlRequest addValue:@"binary/octet-stream" forHTTPHeaderField:@"Content-Type"];
}
NSDate *date = [NSDate aws_clockSkewFixedDate];
NSString *dateStamp = [date aws_stringValue:AWSDateShortDateFormat1];
NSString *scope = [NSString stringWithFormat:@"%@/%@/%@/%@", dateStamp, self.endpoint.regionName, self.endpoint.serviceName, AWSSignatureV4Terminator];
NSString *signingCredentials = [NSString stringWithFormat:@"%@/%@", credentials.accessKey, scope];
// compute canonical request
NSString *httpMethod = urlRequest.HTTPMethod;
// URL.path returns unescaped path
// For S3, url-encoded URI need to be decoded before generate CanonicalURI, otherwise, signature doesn't match occurs. (I.e. CanonicalURI for "/ios-v2-test-445901470/name%3A" will still be "/ios-v2-test-445901470/name%3A". "%3A" -> ":" -> "%3A")
NSString *cfPath = (NSString*)CFBridgingRelease(CFURLCopyPath((CFURLRef)urlRequest.URL));
NSString *path = [cfPath aws_stringWithURLEncodingPath];
if (path.length == 0) {
path = [NSString stringWithFormat:@"/"];
}
NSString *query = urlRequest.URL.query;
if (query == nil) {
query = [NSString stringWithFormat:@""];
}
NSUInteger contentLength = [[urlRequest allHTTPHeaderFields][@"Content-Length"] integerValue];
if (contentLength == 0) {
[urlRequest setValue:nil forHTTPHeaderField:@"Content-Length"];
} else {
[urlRequest setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[[urlRequest HTTPBody] length]] forHTTPHeaderField:@"Content-Length"];
}
// aliyun 上传更改
// Compute contentSha256
NSString *contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hashData:[urlRequest HTTPBody]] encoding:NSASCIIStringEncoding]];
//[request.urlRequest setValue:dateTime forHTTPHeaderField:@"X-Amz-Date"];
[urlRequest setValue:contentSha256 forHTTPHeaderField:@"x-amz-content-sha256"];
//Set Content-MD5 header field if required by server.
if (([ urlRequest.HTTPMethod isEqualToString:@"PUT"] && ([[[urlRequest URL] query] hasPrefix:@"tagging"] ||
[[[urlRequest URL] query] hasPrefix:@"lifecycle"] ||
[[[urlRequest URL] query] hasPrefix:@"cors"]))
|| ([urlRequest.HTTPMethod isEqualToString:@"POST"] && [[[urlRequest URL] query] hasPrefix:@"delete"])
) {
if (![urlRequest valueForHTTPHeaderField:@"Content-MD5"]) {
[urlRequest setValue:[NSString aws_base64md5FromData:urlRequest.HTTPBody] forHTTPHeaderField:@"Content-MD5"];
}
}
NSMutableDictionary *headers = [[urlRequest allHTTPHeaderFields] mutableCopy];
NSString *canonicalRequest = [AWSSignatureV4Signer getCanonicalizedRequest:httpMethod
path:path
query:query
headers:headers
contentSha256:contentSha256];
AWSDDLogVerbose(@"Canonical request: [%@]", canonicalRequest);
NSString *stringToSign = [NSString stringWithFormat:@"%@n%@n%@n%@",
AWSSignatureV4Algorithm,
[urlRequest valueForHTTPHeaderField:@"X-Amz-Date"],
scope,
[AWSSignatureSignerUtility hexEncode:[AWSSignatureSignerUtility hashString:canonicalRequest]]];
AWSDDLogVerbose(@"AWS4 String to Sign: [%@]", stringToSign);
NSData *kSigning = [AWSSignatureV4Signer getV4DerivedKey:credentials.secretKey
date:dateStamp
region:self.endpoint.regionName
service:self.endpoint.serviceName];
NSData *signature = [AWSSignatureSignerUtility sha256HMacWithData:[stringToSign dataUsingEncoding:NSUTF8StringEncoding] withKey:kSigning];
NSString *signatureString = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:signature encoding:NSASCIIStringEncoding]];
NSString *authorization = [NSString stringWithFormat:@"%@ Credential=%@, SignedHeaders=%@, Signature=%@",
AWSSignatureV4Algorithm,
signingCredentials,
[AWSSignatureV4Signer getSignedHeadersString:headers],
signatureString];
NSInputStream *stream = [urlRequest HTTPBodyStream];
if (nil != stream) {
// 阿里云更改:取消分块上传
[urlRequest setHTTPBodyStream:stream];
}
return authorization;
}
文档参考
AWS源码地址
AWS示例代码地址
官方中文文档
阿里云关于AWSS3的开发指南
七牛关于AWSS3的开发指南
紫光云文档 这里面有AWS的一些说明和API介绍。
原文地址:https://blog.csdn.net/leleyuan1130/article/details/128715069
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_24778.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。