我需要通过 PUT 将内容上传到 AWS S3,可以使用 NSURLSessionUploadTask 在后台会话中运行。
到目前为止效果很好。但是,一旦上传到 S3 完成,我需要调用我的 API 以将其状态更改为完成。
我使用 AWSS3 创建 S3 请求,然后根据此 SO answer将其复制到 NSURLSessionUploadTask 。这在前台和后台运行,并将文件 ok 上传到 S3。
现在这是我需要帮助的部分。我尝试使用 URLSession:task:didCompleteWithError 和 URLSessionDidFinishEventsForBackgroundURLSession 委托方法来调用我的附加 API 请求,我使用了标准数据任务和下载任务,它们似乎不会在后台触发请求,直到我再次打开应用程序。理想情况下,我希望他们立即开火。他们确实上传的火是在前台。我已经看到 Wunderlist 完全按照我在后台尝试做的事情,但不确定他们是如何做到的。
这是我到目前为止所拥有的......任何帮助/建议都会很棒,这让我发疯!:)
- (IBAction)upload:(id)sender {
AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:@"ABC" withSecretKey:@"123"];
NSString *identifier = [NSString stringWithFormat:@"com.journeyhq.backgroundSession.%@-%@", @"S3", @"ATTACHMENT_REMOTE_ID"];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"img.jpg"];
NSURL *fromFile = [NSURL fileURLWithPath:filePath isDirectory:NO];
S3PutObjectRequest *s3Request = [[S3PutObjectRequest alloc] initWithKey:[[NSString stringWithFormat:@"%@__%@__%@", @"ATTACHMENT_ID", @"ATTACHMENT_UUID", @"img.jpg"] lowercaseString] inBucket:@"BUCKET_NAME"];
s3Request.cannedACL = [S3CannedACL publicReadWrite];
NSMutableURLRequest *request = [s3Client signS3Request:s3Request];
NSString *urlString = [NSString stringWithFormat:@"https://%@.%@/%@", @"BUCKET_NAME", @"s3-eu-west-1.amazonaws.com", [[NSString stringWithFormat:@"%@__%@__%@", @"ATTACHMENT_ID", @"ATTACHMENT_UUID", @"img.jpg"] lowercaseString]];
request.URL = [NSURL URLWithString:urlString];
NSMutableURLRequest *request2 = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request2 setHTTPMethod:@"PUT"];
[request2 setAllHTTPHeaderFields:[request allHTTPHeaderFields]];
[request2 setValue:@"BUCKET_NAME.s3-eu-west-1.amazonaws.com" forHTTPHeaderField:@"Host"];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request2 fromFile:fromFile];
[uploadTask resume];
}
#pragma - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.progress = (float)totalBytesSent / (float) totalBytesExpectedToSend;
});
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSURLSessionConfiguration *sessionConfig = [session configuration];
NSString *identifier = [sessionConfig identifier];
NSLog(@"**identifier**: %@", identifier);
NSArray *identifierComponents = [identifier componentsSeparatedByString:@"."];
NSString *lastComponent = [identifierComponents lastObject];
NSArray *components = [lastComponent componentsSeparatedByString:@"-"];
NSString *sessionType = [components firstObject];
NSString *attachmentID = [components lastObject];
NSLog(@"sessionType: %@", sessionType);
NSLog(@"attachmentID: %@", attachmentID);
if (error == nil)
{
NSLog(@"Task %@ completed successfully", task);
if ([sessionType isEqualToString:@"S3"]) {
NSString *downloadIdentifier = [NSString stringWithFormat:@"com.journeyhq.backgroundSession.%@-%@", @"s3Completion", attachmentID];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:downloadIdentifier];
NSURLSession *downloadSession = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
NSString *urlString = @"API_COMPLETION_URL";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
NSURLSessionDownloadTask *downloadTask = [downloadSession downloadTaskWithRequest:request];
[downloadTask resume];
}
}
else
{
NSLog(@"Task %@ completed with error: %@", task,
[error localizedDescription]);
}
task = nil;
}
AppDelegate.h
- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
}
编辑我也尝试了以下方法。任务像以前一样创建,当我恢复任务时仍然不会触发。
- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {
NSDictionary *userInfo = @{
@"completionHandler" : completionHandler,
@"sessionIdentifier" : identifier
};
[[NSNotificationCenter defaultCenter]
postNotificationName:@"BackgroundTransferNotification"
object:nil
userInfo:userInfo];
}
然后在视图控制器中
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleBackgroundTransfer:)
name:@"BackgroundTransferNotification"
object:nil];
}
- (void)handleBackgroundTransfer:(NSNotification *)notification {
// handle the API call as shown in original example
...
}