关于ios:后台下载期间未调用我的NSURLSessionDelegate方法

My NSURLSessionDelegate methods are not getting called during a background download

我正在尝试使用NSURLSession设置下载,该下载将在后台继续。
我有一个名为DownloadManager的单例类,该类构建NSURLSession并启动如下下载任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (id)init
{
    self = [super init];
    if (self) {
        self.queue = [[NSOperationQueue alloc] init];
        self.queue.maxConcurrentOperationCount = 1;

        // Initialize the background session.
        self.session = [self backgroundSession];
    }
    return self;
}

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.mycompany.myapp.BackgroundSession"];
        session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                delegate:self
                                           delegateQueue:self.queue];
    });
    return session;
}

- (void)startDownload:(Download *)download
{
    NSURL *remoteURL = ...
    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:remoteURL];
    [task resume];
}

我已经实现了NSURLSessionDelegateNSURLSessionDownloadDelegate方法,包括URLSessionDidFinishEventsForBackgroundURLSession:。另外,我的应用程序委托实现了application:handleEventsForBackgroundURLSession:completionHandler:

但是,当我在开始下载后按主屏幕按钮将应用程序移至后台时,所有下载委托方法都会停止触发,并且永远不会调用application:handleEventsForBackgroundURLSession:completionHandler:。下载会继续进行,如果我等待足够长的时间才能完成下载,那么当我将应用程序带回前台时,就会调用URLSession:downloadTask:didFinishDownloadingToURL:。这意味着我无法在后台进行任何后处理(例如,保存到核心数据,开始新的下载等)。

在需要的情况下,我尝试将\\'Background fetch \\'背景模式添加到我的plist中,并且尝试按照此答案中的建议更改用于创建NSURLSessionConfiguration背景配置的标识符。我在设置时是否犯了一个错误,还是我不应该能够在后台处理下载委托事件?


您不会看到在单个下载在后台完成时调用的下载委托事件,而是在重新启动应用程序后才看到的。例如,当所有下载成功完成时(调用handleEventsForBackgroundURLSession时)或手动重启应用程序时。

关于为什么您没有看到handleEventsForBackgroundURLSession的原因,我只能想到几种(公认的,不太可能)的可能性:

  • 请确保您的应用程序委托中handleEventsForBackgroundURLSession的签名是绝对正确的(大写,拼写等)。轻微的错字不会产生任何警告,但会导致其未被调用。所以应该是:

    1
    2
    3
    4
    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
    {
        // save the completionHandler here
    }
  • 您确定所有后台下载都已完成吗?如果其中之一由于某种原因挂起或失败,则将阻止触发后台会话的完成,并且由于仅在完成所有操作后才调用委托方法,因此将不会激活您的应用程序。我建议仔细检查所有下载是否已完成。

  • 您是否已检查设备的控制台? (如果转到Xcode " Organizer "的" Devices "部分,则可以看到此内容。)有时会有一些有趣的诊断错误消息,后台守护程序将为您记录这些错误消息。如果还没有,请检查一下。那里有很多有趣的东西。

  • 如果您通过SpringBoard手动终止该应用程序(双击物理主页按钮,按住应用程序图标直到其抖动,请单击红色的" x "),这将终止后台下载任务,因此您将\\不会收到所有下载已完成的通知。确保实现URLSession:task:didCompleteWithError:,以便可以看到此错误(和其他错误)。

    但是,如果我按照WWDC 2013视频"基础网络中的新增功能"中的说明以编程方式使该应用程序崩溃,或者如果该应用程序被系统终止,则后台下载将正确完成,并且将正确调用应用程序委托方法。

  • 只需考虑几个想法。


    我遇到了类似的问题,当应用程序在后台下载内容时,从未调用过AppDelegate中的application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void)

    结果证明我在URLSessionConfiguration中设置了sharedContainerIdentifier
    将这行从URLSessionConfiguration中删除后,所有内容都开始工作。

    1
    sessionConfiguration.sharedContainerIdentifier ="my.shared.group"