当用户关闭应用程序并且任务仍处于活动状态时,NSURLSessionDownloadTask 不会删除文件

Posted

技术标签:

【中文标题】当用户关闭应用程序并且任务仍处于活动状态时,NSURLSessionDownloadTask 不会删除文件【英文标题】:NSURLSessionDownloadTask not deleting the file when the app is closed by the user and the task was still active 【发布时间】:2015-07-28 16:49:29 【问题描述】:

我有一个NSURLSession 和一个NSURLSessionDownloadTask 配置为在后台下载文件,如果用户取消下载任务,所有数据都被删除并且文件正在使用的存储空间被释放,但如果应用程序从多任务坞站关闭,下载任务终止并给出错误,但没有删除数据,文件的临时数据仍在占用存储空间并且永远不会被释放。我需要做什么才能释放空间?

这是我的NSURLSession 配置和错误处理:

- (NSURLSession *)backgroundSession 
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^

        NSURLSessionConfiguration *configuration;
        if ([[UIDevice currentDevice].systemVersion hasPrefix:@"7"]) configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.visyon.pr"];
        else configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.visyon.pr"];
        configuration.sessionSendsLaunchEvents =YES;

        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

    );
    return session; 


- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 


if (error == nil) 
    NSLog(@"Task: %@ completed successfully", task );
 else 
   // [self hideActivity];
   // [self showAlertBoxErrorDownload];
    NSLog(@"Task: %@ completed with error: %@, %lu", task, [error localizedDescription], (long)error.code);

    self.downloadTask = nil; 

【问题讨论】:

用户取消下载时,你如何删除数据? 嗨,MikeAtNobel,它会被自动删除,我不需要做任何事情。当用户触摸按钮取消时,我调用[NSURLSessionDownloadTask cancel] 应用强制退出时是否调用? 否未取消,这是关闭应用程序之前的任务下载 ID:<__NSCFBackgroundDownloadTask: 0x146d2f990> taskIdentifier: 2 然后我在任务仍在下载时关闭应用程序,当我再次打开应用程序时出现下一个错误:Task: <__NSCFBackgroundDownloadTask: 0x135e24460> taskIdentifier: 3 completed with error: unsupported URL, 18446744073709550614 无法调用“[NSURLSessionDownloadTask cancel]”,因为该应用程序处于后台并且离多任务处理坞很近。 【参考方案1】:

好的,经过10多天的尝试和失败,我找到了解决方案,首先有两种情况,用户关闭应用,后台有活动下载,请注意这种情况下载任务永远不会被恢复。

场景 1. 当用户关闭应用但仍处于活动状态时,- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 被调用,用于下载的临时文件直接进入应用的临时目录,在本例中为 - (void)applicationWillTerminate:(UIApplication *)application被调用,但下载任务的委托首先被调用。解决方案是这种情况下是实现代码每次打开app时清理临时目录或者让ios清理临时文件夹,这里解释一下iOS什么时候清理临时文件:

When does iOS clean the local app ./tmp directories?

场景 2. 当用户在后台模式下关闭应用程序时,应用程序被终止,下次打开应用程序时,- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 被调用,用于下载的临时文件存储在 NSCachesDirectory在下一个目录中:

var/mobile/Containers/Data/Application/CA21-B6E8-3305A39/Library/Caches/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/CFNetworkDownload_M5o8Su.tmp

下次有新下载时,临时文件将移动到应用程序的临时目录。

这里的解决方案是在- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 启动后立即执行代码以从Caches/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/ 中删除所有临时文件。

这是从NSCachesDirectory删除临时文件的代码:

    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[path stringByAppendingPathComponent:@"/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/"] error:nil];
    for (NSString *string in array) 
        [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:[NSString stringWithFormat:@"/com.apple.nsurlsessiond/Downloads/com.xxx.xxx/%@",  string]] error:nil];
    

但是因为它只适用于这种情况,所以最好在每次启动时实现代码来清理应用程序的临时目录,或者让 iOS 清理临时文件夹,这样它就适用于这两种情况。

下面是如何清理应用临时目录的代码:

NSString *path = NSTemporaryDirectory();
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
for (NSString *string in array) 
    [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil];

【讨论】:

终于找到了解决方案。谢谢@user1241006。我的 iOS 应用程序出现了一些问题。 :) @ajeet sharma 欢迎,请不要忘记为帖子投票【参考方案2】:

第一点是如果您使用后台配置类型配置 nsurlsession。如果用户杀死应用程序,那么这种类型的会话直到运行。 第二点,如果要清除空间,则需要停止该会话并手动编写代码以从 tmp 文件夹中删除临时文件。

更改会话配置类型。

【讨论】:

这是 borderline 一个可以接受的答案。您是否有机会为您在回答中提出的一些观点添加更多细节?如何停止会话?您有删除临时文件的手动代码示例吗?会话配置类型应该更改为什么,为什么?【参考方案3】:

AppDelegate 中有一个名为- (void)applicationWillTerminate:(UIApplication *)application 的方法。您可以尝试从那里拨打[NSURLSessionDownloadTask cancel];;或者尝试设置一个标志,以在应用关闭时向应用指示正在下载,并在下次打开应用时删除数据。

【讨论】:

- (void)applicationWillTerminate:(UIApplication *)application 在您从多任务处理坞关闭应用程序时没有接到电话。 对不起,我应该抓到那个的。由于应用程序在关闭时处于后台,因此不会调用该方法。查看 Apple 的文档 (developer.apple.com/library/ios/documentation/iPhone/Conceptual/…) 似乎表明在这种状态下可能没有处理数据的标准方法。您可能需要找出一种自定义方法来确定下载位置中的数据是否良好。

以上是关于当用户关闭应用程序并且任务仍处于活动状态时,NSURLSessionDownloadTask 不会删除文件的主要内容,如果未能解决你的问题,请参考以下文章

春季安全删除用户 - 会话仍处于活动状态

尽管用户未连接到服务器,但用户仍处于联机状态。并且无法重新连接到服务器

需要在android中每分钟运行一个后台任务

当应用程序处于活动状态时,iOS 处理推送通知点击

如何防止模态盒关闭?

当用户/选项卡/浏览器处于非活动状态时 JavaScript 播放声音