如何在应用程序处于后台模式时使用AFNetworking上传大文件(视频)?

问题描述:

我想在应用程序处于后台模式时从我的应用程序上传大文件(视频)。我正在使用AFNetworking库。应用程序从3分钟开始运行,但在此之后它会终止所有活动。如何在应用程序处于后台模式时使用AFNetworking上传大文件(视频)?

下面的代码我在应用程序中使用。

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; 

AFHTTPRequestOperation *operation = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {} failure:^(AFHTTPRequestOperation *operation, NSError *error) {}]; 

[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten, 
              long long totalBytesWritten, 
              long long totalBytesExpectedToWrite) {}]; 

[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{}]; 

[manager.operationQueue addOperation:operation]; 
+0

显示您的代码 – Wain

+0

最后我解决了问题。当我们尝试将大文件上传到服务器并且应用处于后台状态时,我们需要每60秒更新一次位置准确性。通过哪些应用程序不处于暂停状态,并且在完成文件上传后需要停止位置更新计时器时,我们可以将文件上传到服务器。 –

对于上传大文件,您必须使用AFURLSessionManager类并使用NSURLSessionConfiguration配置其对象。

你的代码中使用AFNetworking将上传大文件如下:

NSString *appID = [[NSBundle mainBundle] bundleIdentifier]; 
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:appID]; 

[manager setTaskDidSendBodyDataBlock:^(NSURLSession *session,NSURLSessionTask *task ,int64_t bytesSent, int64_t totalBytesSent,int64_t totalBytesExpectedToSend){ 
    CGFloat progress = ((CGFloat)totalBytesSent/(CGFloat)sensize); 

    NSLog(@"Uploading files %lld -- > %lld",totalBytesSent,totalBytesExpectedToSend); 
    [self.delegate showingProgress:progress forIndex:ind]; 
}]; 


dataTask = [manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 
    if (error) { 
     NSLog(@"Error: %@", error); 
    } 
    else { 

    } 

    }]; 

你也有NSURLSessionConfiguration对象的sessionSendsLaunchEvents属性的值设置为YES并执行应用程序:handleEventsForBackgroundURLSession:completionHandler:在您的应用程序代理这样当你的文件完全上传时,系统会调用这个委托方法来唤醒你的应用程序。因此,您可以知道上传过程已完成并可以执行任何其他任务。

您可以更好地了解如何使用NSURLSession和NSURLSessionConfiguration下载和上传文件,同时该应用程序位于2链接以下的背景中,因此请参阅这些链接以实施它。

https://developer.apple.com/library/prerelease/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

http://w3facility.org/question/how-to-work-with-large-file-uploads-in-ios/

+0

嗨!这种方法有没有时间限制?我想知道哪一个是最好的解决方案,这个方法和使用'beginBackgroundTaskWithExpirationHandler'方法的方法是一样的。第二个给予“仅”180秒的额外时间。 – Zeb

+0

使用beginBackgroundTaskWithExpirationHandler:在后台模式下上传或下载大文件时更好。 – sajgan2015

+0

好的,但有没有时间限制或完成? – Zeb

最后我用下面的代码解决我的问题。把下面的鳕鱼放在applicationDidEnterBackground。文件上传完成后,您需要停止位置更新和计时器。

if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4 
     if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking 
      UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance 

      __block UIBackgroundTaskIdentifier background_task; //Create a task object 

      background_task = [application beginBackgroundTaskWithExpirationHandler:^{ 
       [application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks 
       background_task = UIBackgroundTaskInvalid; //Set the task to be invalid 

       //System will be shutting down the app at any point in time now 
      }]; 

      //Background tasks require you to use asyncrous tasks 

      if (videoManager.isUploading) 
      { 
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        //Perform your tasks that your application requires 

        /*[application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform 
        background_task = UIBackgroundTaskInvalid; //Invalidate the background_task*/ 

        if (self.locManager != nil) 
        { 
         [self.locManager stopUpdatingLocation]; 
         [self.locManager stopMonitoringSignificantLocationChanges]; 
        } 

        self.locManager = [[CLLocationManager alloc] init]; 
        self.locManager.desiredAccuracy = kCLLocationAccuracyKilometer; 
        if (IS_OS_8_OR_LATER) 
        { 
         if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) 
         { 
          [self.locManager requestAlwaysAuthorization]; 
         } 
        } 
        self.locManager.delegate = self; 
        [self.locManager setDistanceFilter:1000]; 
        self.locManager.pausesLocationUpdatesAutomatically = NO; 
        [self.locManager startMonitoringSignificantLocationChanges]; 
        [self.locManager startUpdatingLocation]; 
       }); 

       if (![timer isValid]) 
       { 
        timer = [NSTimer scheduledTimerWithTimeInterval:60 
                  target:self 
                  selector:@selector(changeAccuracy) 
                  userInfo:nil 
                  repeats:YES]; 
       } 

      } 
      else 
      { 
       [self.locManager stopUpdatingLocation]; 
       [self.locManager stopMonitoringSignificantLocationChanges]; 
       fromBackGround = false; 
       self.locManager.activityType = CLActivityTypeAutomotiveNavigation; 
       [self.locManager setDesiredAccuracy:kCLLocationAccuracyBest]; 
       [self.locManager setDistanceFilter:kCLDistanceFilterNone]; 
       self.locManager.pausesLocationUpdatesAutomatically = NO; 


       [self.locManager startUpdatingLocation]; 
      } 
     } 
    } 

- (void) changeAccuracy{ 
[self.locManager setDesiredAccuracy:kCLLocationAccuracyBest]; 
[self.locManager setDistanceFilter:900];}