在 iOS 后台的同一 NSURLSession 中的 NSURLSessionDownloadTask 之后未调用 NSURLSessionDataTask

NSURLSessionDataTask not called after NSURLSessionDownloadTask in the same NSURLSession in iOS background

我的 iOS 应用按以下方式工作

  1. 我有一组音频文件名,我检查文件是否存在。如果它存在,它就会开始播放。完成后我开始播放下一个音频。

  2. 如果文件不存在,我会发出 NSURLSessionDataTask POST 请求 returns 我string 是要下载的文件的URL。(这个URL有效期为一分钟)

  3. 收到 URL 后,我发出 NSURLSessionDownloadTask 请求并下载文件,保存文件并播放音频。

当应用程序处于前台时,整个过程工作得很好。 当所有音频都存在并且应用程序在后台 运行 时,也可以正常工作。

当音频文件不存在且应用程序 运行 在后台时会出现问题

我的代码: BackgroundFetchManager.h

@interface BackgroundFetchManager : NSObject <NSURLSessionDownloadDelegate,NSURLSessionDataDelegate>

@property bool isDownloading;
@property NSURLSessionDownloadTask *download;
@property NSURLSessionDataTask *dataDownload;
@property (nonatomic, strong)NSURLSession *backgroundSession;
@property NSMutableArray *downloadQueue;
@property FileAccessManager *fileAccessManager;

@end

BackgroundFetchManager.m

初始化函数

-(id) init
{
    self = [super init];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"testConfiguration"];
    config.sessionSendsLaunchEvents = YES;
    config.discretionary = YES;
    self.backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    download = [NSURLSessionDownloadTask new];
    dataDownload = [NSURLSessionDataTask new];
    return self;
} 

数据任务

dataDownload = [self.backgroundSession dataTaskWithRequest:request];
[dataDownload setTaskDescription:@"Data task"];

委托数据下载(NSURLSessionDataTask)

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{

    completionHandler(NSURLSessionResponseAllow);
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSString *url = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"This is the response received %@",url);

//download is the NSURLSessionDownloadTask
    download = [self.backgroundSession downloadTaskWithURL:[NSURL URLWithString:url]];
    [download resume];

}

下载委托(NSURLSessionDownloadTask

这些是应用程序在后台时不会调用的

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    AppDelegate *a = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSURL *destinationURL = [fileAccessManager saveFile:a.downloadQueue[0] fromLocation:location]; // save file code
}


- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    // audio playing stuff

    if (![task.taskDescription isEqualToString:@"Data task"]) {
        NSLog(@"This is did complete with error %@", task );
        AppDelegate *a = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        if ([a.downloadQueue[0] isEqualToString:a.audioToBePlayed]) {
            NSDictionary* userInfo = @{@"file": a.downloadQueue[0]};
            [[NSNotificationCenter defaultCenter] postNotificationName:@"playThisStuff" object:nil userInfo:userInfo];


        }
//starts next download
        [a pop];
        isDownloading = false;
        if ([a.downloadQueue count] > 0) {
            isDownloading = true;
            [self downloadFile:a.downloadQueue[0]];
        }
    }        
}

简而言之,下载任务不会在数据任务完成后调用。 据我所知,NSURLSession 当配置为 backgroundsession 时,OS 负责下载,所以理想情况下它应该可以工作。我错过了什么吗?

问题源于 iOS 不允许您在应用程序处于后台时启动新任务。我相信这样做是为了防止应用程序不断触发新任务并使应用程序无限期地保持活动状态。

后台任务通常适合在任务进行时优雅地处理您的应用从前台到后台的转换。这就是您看到第一个任务完成但第二个任务没有完成的原因。

一种解决方法是在启动初始数据任务时从 OS 请求后台执行时间:

UIBackgroundTaskIdentifier backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

}];

这应该至少给您的应用几分钟的后台时间来启动第二个任务。在第二个任务中调用 -resume 之后,一定要调用 -endBackgroundTask:

遗憾的是,这不能保证您的所有文件都能下载。如果您发现 运行 超出后台时间,最好使用 Silent Push Notifications 唤醒您的应用程序并定期下载。