链接背景NSURLSession上传

tut*_*u47 4 ios afnetworking-2 nsurlsession

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

我正在尝试使用NSURLSession的后台上传来上传5 MB部分的巨大视频文件.上传必须是有序的.整个事情在前景中运作良好.我正在使用AFNetwoking,它是一个多部分上传.但是当应用程序处于后台时,第一项上传正常并在后台启动第二项(在AFURLSessionManager的setDidFinishEventsForBackgroundURLSessionBlock中).但它突然停止(我最好的猜测是在30秒内,因为在后台唤醒的应用程序的最大生命周期为30秒)然后没有任何反应.我预计第二次会议将在后台完成,并调用第三次等 - 链式行为,但这似乎不起作用.

我尝试使用HTTPMaximumConnectionsPerHost = 1一次性将所有文件部分添加到单个NSURLSession中 - 这样可以正常工作并将部分文件上传到整个文件.但文件部分是按随机顺序挑选的,即第1部分上传,然后是第5部分,第3部分,第10部分等等.我尝试在NSOperationQueue中添加这个操作之间的依赖关系,这似乎弄乱了整个事情 - 上传根本不起作用.

我知道视频文件可以作为单个文件在后台上传,但服务器需要5 MB部分.因此,我想我唯一的选择是链接上传,或将所有部分添加到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");
        }];
    }];
}
Run Code Online (Sandbox Code Playgroud)

tut*_*u47 6

好吧,最后我联系Apple了解关于链接后台上传的说明 - 这在iOS中是不可能的.NSURLSession有一个恢复速率限制器,它可以阻止应用程序在后台执行链式任务,如https://forums.developer.apple中所述. com/thread/14854.相反,苹果建议批量转移或其他选项,如https://forums.developer.apple.com/thread/14853.我要问的另一件事是在上传队列中订购多个任务 - 即强制NSURLSession按照添加顺序上传任务.正如指出的dgatwood,使用NSOperationQueue是不可能的,苹果还提到提到same.As 爱斯基摩响应邮件"NSURLSession不保证运行,以便您的要求,而且也没有办法强制执行." 所以我在原来的问题上几乎没有选择.


dga*_*ood 1

当你的应用程序消失时,NSOperationQueue 就会消失,这在你将其放入后台后不久就会消失。所以这不会很好地发挥作用。

\n\n

相反,请按照\xe2\x80\x94 的顺序存储剩余要上传的文件列表,或者存储在磁盘上的文件中,或者存储在NSUserDefaults中,具体取决于您的个人喜好。然后,在后台会话中使用上传任务来启动第一个任务。完成后,如果您的应用程序未运行,它应该自动在后台重新启动以处理数据。

\n\n

为了支持此行为,请在您的application:handleEventsForBackgroundURLSession:completionHandler:方法中,像最初一样重新创建后台会话,并存储完成处理程序。

\n\n

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

\n\n

当您收到 didCompleteWithError 委托调用(成功时为 nil,IIRC)时,如果传输失败,请重试或执行其他操作。如果成功,请开始上传下一个并更新磁盘上的文件列表。

\n\n

无论哪种方式,当调用会话委托的 ** URLSessionDidFinishEventsForBackgroundURLSession:** 方法时,调用您之前存储的处理程序,大致如下:

\n\n
[[NSOperationQueue mainQueue] addOperationWithBlock:^{\n    storedHandler();\n}];\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

冲洗,重复。

\n\n

如果请求完成时您的应用程序仍在运行,则一切都会按照上述方式发生,只是您没有获取 application :handleEventsForBackgroundURLSession:completionHandler:URLSessionDidFinishEventsForBackgroundURLSession:调用,这意味着您不必存储完成结果处理程序或调用它。

\n\n

请参阅URL 会话编程指南

\n