NSURLSessionノート(4)バックグラウンドダウンロードの重要な方法のいくつかの記録

6937 ワード

demoはここにいる
簡単にNSURLSessionを利用してダウンロードする前の文章はもう話しましたが、ここでもあまり言いません.
バックグラウンド転送サービスを利用するには、+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifierを使用してセッション構成を作成します.バックグラウンドセッションに追加されたタスクは、アプリケーションが停止、クラッシュ、または(システム)によって殺されても実行されます.(バックグラウンド転送もアップロード作業ができますが、ここではダウンロードで説明するだけです)
主に3つの呼び出される方法(呼び出される順序):1.AppDelegate委任メソッド:- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandlerすべてのバックグラウンド転送が完了した場合(成功またはエラーにかかわらず)、このメソッドはコールバックされます.このメソッドには、アプリケーションがすべての処理を完了したことを示すcompetionHandlerが含まれています.通常、このオブジェクトは保存されます.最後のタスクが完了するまで、session identifier(上のsessionConfigで設定されている)を使用して、対応するsessionを見つけてNSURLSessionを呼び出す-(void)U r e s s s e s s s i o n D i d F i n s E v e n t s ForBackgroundURLSession:(NSURLSession*)sessionエージェントメソッドを探し直します.このメソッドでは、UIの更新が一般的に行われ、completionHandlerを呼び出してシステムがすべての操作を完了したことを通知します.
completionHandlerについて:uiリフレッシュ、スクリーンショットと関係がある
セッション完了時にappがシステムによって殺された場合、イベントを処理できるようにバックグラウンドにappがロードされます.この場合、このメソッドで提供されたidentifierを使用して、新しいNSURLSessionConfigurationオブジェクトとNSURLSessionオブジェクトを作成し、session delegateがメソッドを呼び出して処理することができます.appに特定のidentifierのセッションオブジェクト(実行または保留)がある場合は、この方法でセッションオブジェクトを新規作成する必要はありません.保留中のappはバックグラウンドにあり、再実行すると、この特定のidのセッションオブジェクトはイベントを受信し、正常に処理します.appをロードするとき、転送タスクがまだ進行中であれば、この方法は呼び出されません.uiで現在の転送の進捗状況を示すには、セッションオブジェクトを自分で再構築します(identifierを保存してセッションを再構築するときに使用します).
2.- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error;タスクのダウンロードが完了し、ダウンロードに失敗し、アプリケーションが殺され、アプリケーションを再起動し、関連identifierのセッションを作成するときに呼び出されます.
3.- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)sessionはバックグラウンドに適用され、バックグラウンドのすべてのtaskが完了した後、他のすべてのURLSessionおよびdownloadTask委任メソッドが完了した後にコールバックする.ダウンロードデータ管理とUI更新は、この方法で行うことができます.あとで1メソッド保存のcompletionHandlerを呼び出します
1、3の2つの方法はappがシステムによって殺されたときに呼び出される.demoを書いたとき、この2つの方法はどうしても呼び出せないことに気づき、stackoverflowで答えを見つけました.
If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.
バックグラウンド転送が完了すると、アプリケーションがシステムによって殺された場合、iOSはバックグラウンドでアプリケーションを起動し、ダウンロード関連の委任メソッドはアプリケーション:d i d F i nishLaunchingWithOptions:メソッドが呼び出された後に呼び出されます.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.completionHandlerDictionary = [NSMutableDictionary dictionary];
    
    [[SessionManager shareSession]backgroundSession];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callCompletionHandlerForSession:) name:@"completionHandlerNotification" object:nil];
    return YES;
}

- (void)callCompletionHandlerForSession:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo;
    NSString *sessionConfigID = userInfo[@"downloadID"];
    void (^completionHandler)() = [self.completionHandlerDictionary objectForKey:sessionConfigID];
    
    if (completionHandler) {
        [self.completionHandlerDictionary removeObjectForKey: sessionConfigID];
        NSLog(@"Calling completion handler for session %@", sessionConfigID);
        completionHandler();
    }
}

// 
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    NSURLSession *backgroundSession = [[SessionManager shareSession]backgroundSession];
    NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession);
    
    //   completion handler   session   UI
    if ([self.completionHandlerDictionary objectForKey:identifier]) {
        NSLog(@"Error: Got multiple handlers for a single session identifier.  This should not happen.
"); } [self.completionHandlerDictionary setObject:completionHandler forKey:identifier]; }
SessionManager.m
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (error) {        
        if ([error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]) {
            self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
//            self.downloadTask = [self.backgroundSession downloadTaskWithResumeData:self.resumeData];// task, 
//            [self.downloadTask resume];//
        }
    }else{
        NSLog(@" ");
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@" "
                                                        message:nil
                                                       delegate:nil
                                              cancelButtonTitle:@" "
                                              otherButtonTitles:nil];
        [alert show];
    }
}

// 
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    NSLog(@"%s",__func__);
    NSDictionary *userInfo = @{@"downloadID":session.configuration.identifier};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"completionHandlerNotification" object:nil userInfo:userInfo];
}
  • バックグラウンドダウンロードワークフローのいくつかのシナリオプログラムがバックグラウンドに切断されると、BackgroundSessionのTaskはダウンロードを継続します.この文章ではいくつかの可能なシナリオを分析しましたが、ほとんどが正しいですが、appがシステムに殺されたときだけsessionがApplicationDelegateとインタラクティブになると思います.以下に引用するこの結論は、私の実際のテストでは、バックグラウンドに切り替えるだけであれば、application:handleEventsForBackgroundURLSession:completionHandler:URLSessionDidFinishEventsForBackgroundURLSession:の2つの方法
  • は呼び出されません.
    2)複数のTaskが加わると,プログラムがバックグラウンドに切り込まれ,すべてのTaskがダウンロードを完了する.バックグラウンドにカットされた後、SessionのDelegateは二度と受信しません.Task関連のメッセージは、すべてのTaskが完了するまで、アプリケーションDelegateのアプリケーション:h a n d l e v e n t s ForBackgroundURLSession:completionHandler:コールバックを呼び出し、その後ダウンロードワークを「報告」します.バックグラウンドごとにダウンロードしたTaskに対してSessionのDelegateのURLSession:downloadTask:didFinishDownloadingToURL:(成功すると)とURLSession:task:didCompleteWithError:(成功または失敗は呼び出されます).を選択してもアクセスできます.
    また、バックグラウンドのダウンロード時にログを印刷しない:homeキーの後、バックグラウンドでは、ダウンロードの進捗状況を印刷しない(ただし、ダウンロードが一時停止したという意味ではなく、フロントに切り替えた後も印刷を継続する)、すなわちsessionのエージェント方法はコールバックしない;しばらく待つと、砂箱ディレクトリにダウンロードされたファイルがあり、ダウンロードが完了したことを示します(コンソールインタフェースでは何も見えませんが).
    demoはここにいる