Example/AliyunOSSSDK-Example/Classes/Services/OssService.m (265 lines of code) (raw):

// // OssService.m // OssIOSDemo // // Created by 凌琨 on 15/12/15. // Copyright © 2015年 Ali. All rights reserved. // #import <UIKit/UIKit.h> #import <AliyunOSSiOS/OSSService.h> #import "OssService.h" NSString * const bucketName = @"sdk-demo"; NSString * const STSServer = @"http://oss-demo.aliyuncs.com/app-server/sts.php"; @implementation OssService { OSSClient * client; NSString * endPoint; NSString * callbackAddress; NSMutableDictionary * uploadStatusRecorder; NSString * currentUploadRecordKey; OSSPutObjectRequest * putRequest; OSSGetObjectRequest * getRequest; // 简单起见,全局只维护一个断点上传任务 OSSResumableUploadRequest * resumableRequest; ViewController * viewController; BOOL isCancelled; BOOL isResumeUpload; } - (id)initWithViewController:(ViewController *)view withEndPoint:(NSString *)enpoint { if (self = [super init]) { viewController = view; endPoint = enpoint; isResumeUpload = NO; isCancelled = NO; currentUploadRecordKey = @""; uploadStatusRecorder = [NSMutableDictionary new]; [self ossInit]; } return self; } /** * @brief 获取FederationToken * * @return */ - (OSSFederationToken *) getFederationToken { NSURL * url = [NSURL URLWithString:STSServer]; NSURLRequest * request = [NSURLRequest requestWithURL:url]; OSSTaskCompletionSource * tcs = [OSSTaskCompletionSource taskCompletionSource]; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionTask * sessionTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { [tcs setError:error]; return; } [tcs setResult:data]; }]; [sessionTask resume]; // 实现这个回调需要同步返回Token,所以要waitUntilFinished [tcs.task waitUntilFinished]; if (tcs.task.error) { return nil; } else { NSDictionary * object = [NSJSONSerialization JSONObjectWithData:tcs.task.result options:kNilOptions error:nil]; OSSFederationToken * token = [OSSFederationToken new]; token.tAccessKey = [object objectForKey:@"AccessKeyId"]; token.tSecretKey = [object objectForKey:@"AccessKeySecret"]; token.tToken = [object objectForKey:@"SecurityToken"]; token.expirationTimeInGMTFormat = [object objectForKey:@"Expiration"]; NSLog(@"AccessKey: %@ \n SecretKey: %@ \n Token:%@ expirationTime: %@ \n", token.tAccessKey, token.tSecretKey, token.tToken, token.expirationTimeInGMTFormat); return token; } } /** * @brief 初始化获取OSSClient */ - (void)ossInit { id<OSSCredentialProvider> credential = [[OSSFederationCredentialProvider alloc] initWithFederationTokenGetter:^OSSFederationToken * { return [self getFederationToken]; }]; client = [[OSSClient alloc] initWithEndpoint:endPoint credentialProvider:credential]; } /** * @brief 设置server callback地址 * * @param address */ - (void)setCallbackAddress:(NSString *)address { callbackAddress = address; } /** * @brief 上传图片 * * @param objectKey objectKey * @param filePath 路径 */ - (void)asyncPutImage:(NSString *)objectKey localFilePath:(NSString *)filePath { if (objectKey == nil || [objectKey length] == 0) { return; } putRequest = [OSSPutObjectRequest new]; putRequest.bucketName = bucketName; putRequest.objectKey = objectKey; putRequest.uploadingFileURL = [NSURL fileURLWithPath:filePath]; putRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) { NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend); }; if (callbackAddress != nil) { putRequest.callbackParam = @{ @"callbackUrl": callbackAddress, // callbackBody可自定义传入的信息 @"callbackBody": @"filename=${object}" }; } OSSTask * task = [client putObject:putRequest]; [task continueWithBlock:^id(OSSTask *task) { OSSPutObjectResult * result = task.result; // 查看server callback是否成功 if (!task.error) { NSLog(@"Put image success!"); NSLog(@"server callback : %@", result.serverReturnJsonString); dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"普通上传" inputMessage:@"Success!"]; }); } else { NSLog(@"Put image failed, %@", task.error); if (task.error.code == OSSClientErrorCodeTaskCancelled) { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"普通上传" inputMessage:@"任务取消!"]; }); } else { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"普通上传" inputMessage:@"Failed!"]; }); } } putRequest = nil; return nil; }]; } /** * @brief 下载图片 * * @param objectKey */ - (void)asyncGetImage:(NSString *)objectKey { if (objectKey == nil || [objectKey length] == 0) { return; } getRequest = [OSSGetObjectRequest new]; getRequest.bucketName = bucketName; getRequest.objectKey = objectKey; OSSTask * task = [client getObject:getRequest]; [task continueWithBlock:^id(OSSTask *task) { OSSGetObjectResult * result = task.result; if (!task.error) { NSLog(@"Get image success!"); dispatch_async(dispatch_get_main_queue(), ^{ [viewController saveAndDisplayImage:result.downloadedData downloadObjectKey:objectKey]; [viewController showMessage:@"普通下载" inputMessage:@"Success!"]; }); } else { NSLog(@"Get image failed, %@", task.error); if (task.error.code == OSSClientErrorCodeTaskCancelled) { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"普通下载" inputMessage:@"任务取消!"]; }); } else { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"普通下载" inputMessage:@"Failed!"]; }); } } getRequest = nil; return nil; }]; } - (void)doResumableUpload { resumableRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) { NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend); }; OSSTask * resumeTask = [client resumableUpload:resumableRequest]; [resumeTask continueWithBlock:^id(OSSTask *task) { if (!task.error) { NSLog(@"Resumable put success!"); // 清空该项纪录 [uploadStatusRecorder removeObjectForKey:currentUploadRecordKey]; if (isResumeUpload) { currentUploadRecordKey = @""; isResumeUpload = NO; dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"恢复暂停任务上传" inputMessage:@"Success!"]; }); } else { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"断点上传" inputMessage:@"Success!"]; }); } } else { NSLog(@"Resumable put failed, %@", task.error); // 无法继续上传错误,删除该项记录,重新获取uploadId上传 if ([task.error.domain isEqualToString:OSSClientErrorDomain] && task.error.code == OSSClientErrorCodeCannotResumeUpload) { [uploadStatusRecorder removeObjectForKey:currentUploadRecordKey]; } else if ([[NSString stringWithFormat:@"%@", task.error] containsString:@"cancel"]) { NSLog(@"Resumable put cancel!"); // 用户主动取消上传任务 if (isCancelled) { OSSAbortMultipartUploadRequest * abortRequest = [OSSAbortMultipartUploadRequest new]; abortRequest.bucketName = resumableRequest.bucketName; abortRequest.objectKey = resumableRequest.objectKey; abortRequest.uploadId = resumableRequest.uploadId; OSSTask * task = [client abortMultipartUpload:abortRequest]; [task continueWithBlock:^id(OSSTask *task) { if (!task.error) { NSLog(@"断点上传删除服务端uploadId"); } return nil; }]; dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"断点上传" inputMessage:@"任务取消!"]; isCancelled = NO; [uploadStatusRecorder removeObjectForKey:currentUploadRecordKey]; }); } else { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"断点上传" inputMessage:@"Paused!"]; }); } } else { dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"断点上传" inputMessage:@"Failed!"]; }); } } return nil; }]; } /** * @brief 断点上传,可暂停,然后恢复上传任务继续 * 调用OSSResumableUpload,根据计算md5(fileMd5 + bucketName + objectKey + partSize),作为上传纪录key * @param objectKey 设置上传文件的objectKey * @param filePath 文件路径 * @param size 分片大小 */ - (void)resumableUpload:(NSString *)objectKey localFilePath:(NSString *)filePath partSize:(int)size { resumableRequest = [OSSResumableUploadRequest new]; NSString * fileMd5 = [OSSUtil fileMD5String:filePath]; // 从文件内容MD5、上传的目标地址、分片大小获取一个唯一标识 NSString * recordIdentifier = [OSSUtil dataMD5String: [[NSString stringWithFormat:@"%@%@%@%d", fileMd5, bucketName, objectKey, size] dataUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"upload record identifier: %@", recordIdentifier); currentUploadRecordKey = recordIdentifier; resumableRequest = [OSSResumableUploadRequest new]; resumableRequest.bucketName = bucketName; resumableRequest.objectKey = objectKey; resumableRequest.uploadingFileURL = [NSURL fileURLWithPath:filePath]; resumableRequest.partSize = size; __block NSString * uploadId = [uploadStatusRecorder objectForKey:currentUploadRecordKey]; if (uploadId == nil) { // get uploadId OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new]; init.bucketName = bucketName; init.objectKey = objectKey; OSSTask * task = [client multipartUploadInit:init]; [task continueWithBlock:^id(OSSTask *task) { if (!task.error) { OSSInitMultipartUploadResult * result = task.result; resumableRequest.uploadId = result.uploadId; [uploadStatusRecorder setObject:result.uploadId forKey:currentUploadRecordKey]; [self doResumableUpload]; } else { NSLog(@"Get uploadId failed, %@", task.error); dispatch_async(dispatch_get_main_queue(), ^{ [viewController showMessage:@"断点上传" inputMessage:@"Get uploadId failed!"]; }); } return nil; }]; } else { isResumeUpload = YES; resumableRequest.uploadId = uploadId; [self doResumableUpload]; } } /** * @brief 断点续传暂停 */ - (void)resumableUploadPause { if (!resumableRequest.isCancelled) { isCancelled = NO; [resumableRequest cancel]; } } /** * @brief 普通上传/下载取消 */ - (void)normalRequestCancel { if (putRequest) { [putRequest cancel]; } if (getRequest) { [getRequest cancel]; } } /** * @brief 断点上传任务取消 */ - (void)ResumableUploadCancel { if (!resumableRequest.isCancelled) { isCancelled = YES; [resumableRequest cancel]; } } @end