3

NSURLSessionUploadTask를 사용하여 백그라운드 세션에서 실행할 수있는 PUT을 통해 콘텐츠를 AWS S3에 업로드해야합니다.NSURLSession backgroundSession 완료시 추가 API 호출

지금까지 훌륭했습니다. 그러나 S3 로의 업로드가 완료되면 상태를 변경하기 위해 완료되면 API를 호출해야합니다.

S3 요청을 생성하려면 AWSS3을 입력 한 다음 this SO answer에 따라 NSURLSessionUploadTask에 복사합니다. 이것은 포 그라운드와 백그라운드에서 실행되며 파일을 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]; 
} 

그런 다음 응용 프로그램은 당신이 될 것 같지 않습니다 AppDelegate에, 그것을 처리해야합니다 실행되지 않은 상태에서 백그라운드 작업이 완료되면 뷰 컨트롤러

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

답변

0

에서 하기. 이 같은

뭔가 작동합니다 :

NSURLSessionDidFinishEventsForBackgroundURLSession에 대한 설명서는 말한다
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { 

    // the identifier you used to create the background session 
    NSString *identifier = [NSString stringWithFormat:@"com.journeyhq.backgroundSession.%@-%@", @"S3", @"ATTACHMENT_REMOTE_ID"]; 

    if ([identifier isEqualToString:identifier]) { 
     // call your API here 
    } 

    // call the handler block so the app can exit again 
    completionHandler();  
} 
+0

답장을 보내 주셔서 감사합니다. 애플 리케이션 델리게이트 내부에 직접 있지는 않지만, 뷰 컨트롤러에서 처리되는 handleEventsForBackgroundURLSession 내에서 트리거 된 알림을 통해 이전에 시도한 적이 있습니다. 불행히도 그 결과는 같았습니다. 그것은 비록 내가 응용 프로그램을 열고 다음 작업을 실행하지 않는 한, 작업에 대한 이력서를 호출에도 불구하고, 그냥 화재가 발생하지 않는 작업을 만듭니다. handleEventsForBackgroundURLSession에서 직접 시도했지만 여전히 실행되지 않습니다. –

+2

앱 위임 방법으로 시도한 코드를 게시 할 수 있습니까? –

+0

혹시이 문제를 해결 했습니까? 나는 똑같은 문제를 겪고있다. – d0n13

1

으로 :

아이폰 OS에서

, 배경 전송이 완료되거나 앱이 더 이상 실행하는 경우, 자격 증명을 필요로하지 않을 때, 앱이 백그라운드에서 자동으로 다시 시작되며 앱의 UIApplicationDelegateapplication:handleEventsForBackgroundURLSession:completionHandler: 메시지가 전송됩니다. 이 호출에는 앱을 시작한 세션의 식별자가 포함되어 있습니다. 그런 다음 앱은 동일한 식별자로 백그라운드 구성 객체를 생성하고 해당 구성으로 세션을 생성하기 전에 완성 처리기를 저장해야합니다. 새로 생성 된 세션은 진행중인 백그라운드 활동과 자동으로 다시 연관됩니다.

나중에 응용 프로그램이 URLSessionDidFinishEventsForBackgroundURLSession: 메시지를 받으면이 세션에 대해 이전에 대기열에 추가 된 모든 메시지가 전달되었으며 이전에 저장된 완료 처리기를 호출하거나 다음과 같은 결과를 초래할 수있는 내부 업데이트를 시작하는 것이 안전하다는 것을 나타냅니다. 완료 핸들러를 호출합니다.

그래서, handleEventsForBackgroundURLSessioncompletionHandler 및 reinstantiate 배경 NSURLSession을 저장해야합니다.그런 다음 URLSessionDidFinishEventsForBackgroundURLSessioncompletionHandler이라고해야합니다.

앱이 다시 깨어나고 handleEventsForBackgroundURLSession이 호출 될 때 어디에도 배경 세션을 다시 인스턴스화하지 않습니다. 또한 completionHandler을 호출 할 URLSessionDidFinishEventsForBackgroundURLSession을 구현하는 것도 볼 수 없습니다.