gpt4 book ai didi

ios - NSURLSession backgroundSession 完成时额外的 API 调用

转载 作者:可可西里 更新时间:2023-11-01 06:08:06 25 4
gpt4 key购买 nike

我需要通过 PUT 将内容上传到 AWS S3,该 PUT 可以使用 NSURLSessionUploadTask 在后台 session 中运行。

到目前为止效果很好。但是,我需要在上传到 S3 完成后调用我的 API 以将其状态更改为完成。

我使用 AWSS3 创建 S3 请求,然后根据 this SO answer 将其复制到 NSURLSessionUploadTask .这在前台和后台都运行,并将文件 ok 上传到 S3。

现在这是我需要帮助的部分。我尝试同时使用 URLSession:task:didCompleteWithError 和 URLSessionDidFinishEventsForBackgroundURLSession 委托(delegate)方法来调用我的附加 API 请求,我使用了标准数据任务以及下载任务,它们似乎不会在后台触发请求,直到我再次打开应用程序。理想情况下,我希望他们立即开火。他们上传的火是在前台。我已经看到奇妙 list 在后台完全按照我的意愿进行操作,但不确定他们是如何做到的。

这是我到目前为止所拥有的......任何帮助/建议都会很棒,这让我发疯! :)

- (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 {
}

EDIT 我也试过以下方法。任务像以前一样创建,当我恢复任务时仍然没有触发。

- (void)application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler {

NSDictionary *userInfo = @{
@"completionHandler" : completionHandler,
@"sessionIdentifier" : identifier
};

[[NSNotificationCenter defaultCenter]
postNotificationName:@"BackgroundTransferNotification"
object:nil
userInfo:userInfo];
}

然后在 View Controller 中

- (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
...
}

最佳答案

正如 NSURLSessionDidFinishEventsForBackgroundURLSession 的文档所说:

In iOS, when a background transfer completes or requires credentials, if your app is no longer running, your app is automatically relaunched in the background, and the app’s UIApplicationDelegate is sent an application:handleEventsForBackgroundURLSession:completionHandler: message. This call contains the identifier of the session that caused your app to be launched. Your app should then store that completion handler before creating a background configuration object with the same identifier, and creating a session with that configuration. The newly created session is automatically reassociated with ongoing background activity.

When your app later receives a URLSessionDidFinishEventsForBackgroundURLSession: message, this indicates that all messages previously enqueued for this session have been delivered, and that it is now safe to invoke the previously stored completion handler or to begin any internal updates that may result in invoking the completion handler.

因此,handleEventsForBackgroundURLSession 应该保存 completionHandler 并重新实例化后台 NSURLSession。然后,URLSessionDidFinishEventsForBackgroundURLSession 应该调用那个 completionHandler

当您的应用程序被重新唤醒并调用 handleEventsForBackgroundURLSession 时,我没有看到您在任何地方重新实例化后台 session 。我也没有看到您实现了将调用 completionHandlerURLSessionDidFinishEventsForBackgroundURLSession

关于ios - NSURLSession backgroundSession 完成时额外的 API 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22919568/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com