链接背景NSURLSession上传

有没有人成功链接NSURLSession后台上传?

我正尝试使用NSURLSession的后台上传以5 MB的部分上传一个巨大的video文件。 上传必须按顺序进行。 整个事情在前台工作正常。 我正在使用AFNetwoking这个,它的一个多部分上传。 但是,当应用程序在后台,第一项上传罚款,并在后台启动第二个(在AFURLSessionManager setDidFinishEventsForBackgroundURLSessionBlock)。 但是它突然停止(我最好的猜测是在30秒内,因为在后台唤醒的应用程序的最大寿命为30秒),然后什么也没有发生。 我预计第二届会议将在后台完成,并呼吁第三等 – 连锁行为,但这似乎并没有工作。

我已经试着用一个HTTPMaximumConnectionsPerHost = 1一次性添加所有的文件部分到一个NSURLSession – 这工作正常,并上传完整的文件的部分。 但文件部分是随机select的,即第1部分上传,然后第5部分,第3部分,第10部分等。 我试图在NSOperationQueue中添加这个操作之间的依赖关系,这似乎弄乱了整个事情 – 上传根本不起作用。

我知道video文件可以在后台作为一个单独的file upload,但服务器期望在5 MB的部分。 因此,我想我唯一的select是链上传,或者将所有的部分添加到NSURLSession,但要确保它们总是按照它们添加的顺序上传。

任何帮助,将不胜感激。

我的代码:

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:@"%d", rand()]]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:config]; config.HTTPMaximumConnectionsPerHost = 1; [manager setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession *session) { dispatch_async(dispatch_get_main_queue(), ^{ // Call the completion handler to tell the system that there are no other background transfers. // completionHandler(); [self upload]; }); }]; } - (IBAction)start:(id)sender { [self upload]; } -(void) upload { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"mp4"]; AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer]; NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:@"234", @"u", @"Sample.mp4", @"f",nil]; NSMutableURLRequest *request = [serializer multipartFormRequestWithMethod:@"POST" URLString:urlString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { [formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath] name:@"data" fileName:@"Sample.mp4" mimeType:@"video/mp4" error:nil]; } error:nil]; __block NSString *tempMultipartFile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Test"]; tempMultipartFile = [tempMultipartFile stringByAppendingString:[NSString stringWithFormat:@"%d", rand()]]; NSURL *filePathtemp = [NSURL fileURLWithPath:tempMultipartFile]; __block NSProgress *progress = nil; [serializer requestWithMultipartFormRequest:request writingStreamContentsToFile:filePathtemp completionHandler:^(NSError *error) { NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePathtemp progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { NSLog(@"Request--> %@.\n Response --> %@ \n%@", request.URL.absoluteString ,responseObject, error? [NSString stringWithFormat:@" with error: %@", [error localizedDescription]] : @""); //Lets us know the result including failures [[NSFileManager defaultManager] removeItemAtPath:tempMultipartFile error:nil]; }]; [uploadTask resume]; [manager setTaskDidSendBodyDataBlock:^(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { NSLog(@"uploading"); }]; }]; } 

那么,最后我联系了苹果澄清链背景上传 – 这是不可能在iOS.NSURLSession有一个恢复速率限制器,它阻止应用程序在后台执行链接的任务,如https://forums.developer.apple中所述&#x3002; com / thread / 14854 。 相反,苹果build议批量转移或其他选项,如https://forums.developer.apple.com/thread/14853 。 我所要求的另一件事是在上传队列中sorting多个任务 – 即强制NSURLSession按照添加顺序上传任务。 正如dgatwood所指出的那样 ,使用NSOperationQueue是不可能的,而且苹果也提到了这一点。正如Eskimo在回复邮件中提到的:“NSURLSession不能保证按顺序运行你的请求,也没有办法强制执行。 所以我几乎没有select我最初的问题。

一个NSOperationQueue会在你的应用程序执行时消失,在你把它放到后台后不会太长。 所以这不会很好。

而是根据您的个人偏好,按顺序存储剩余要上传的文件列表(无论是在磁盘上还是在NSUserDefaults中) 。 然后,在后台会话中使用上传任务来启动第一个任务。 完成后,如果您的应用程序未运行,则应自动在后台重新启动以处理数据。

为了支持这种行为,在你的应用程序中:handleEventsForBackgroundURLSession:completionHandler:方法,像原来一样重新创build后台会话,并存储完成处理程序。

此后不久,请求的委托方法应该被调用,就像您的应用程序在下载完成时仍在运行一样。 除此之外,这些方法可以为您的应用程序提供来自服务器的响应数据,响应对象(用于检查状态码)等。

当你得到didCompleteWithError委托调用(这是成功的,IIRC),如果传输失败,再试一次或者别的。 如果成功,请开始上传下一个并更新磁盘上的文件列表。

无论哪种方式,当你的会议委托的** URLSessionDidFinishEventsForBackgroundURLSession:**方法被调用时,调用你以前存储的处理程序,大致是这样的:

 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ storedHandler(); }]; 

通过调用完成处理程序,您告诉操作系统,您不需要继续运行。

冲洗,重复。

如果您的应用程序在请求完成时仍在运行,则除了您没有获得应用程序之外,所有事情都将如上所述进行:handleEventsForBackgroundURLSession:completionHandler:URLSessionDidFinishEventsForBackgroundURLSession: calls,这意味着您不必存储完成处理程序或叫它。

有关详情,请参阅URL会话编程指南 。