AFNetworking 2.0.0在后台下载。

6
我正在使用'AFNetworking','2.0.0'来下载数据。
我需要下载大文件。当用户锁定屏幕或按下主屏幕按钮时,它应该暂停(或在后台继续下载),如果我返回到应用程序,则应该恢复下载。
另外,我需要显示下载进度。
我搜索了很多例子,但没有找到任何关于'AFNetworking','2.0.0'的内容。
我创建的应用程序适用于iOS版本6.0+,因此无法使用AFHTTPSessionManagerAFURLSessionManager

也许你可以在这里找到解决方案:https://dev59.com/F2jWa4cB1Zd3GeqPuMsr - Weizhi
3个回答

3

若要在 iOS 7 或更高版本上下载背景中的内容,我使用 NSURLSession 和它的 NSURLSessionDownloadTask

打开 ProjectNavigator->YourProject->YourTarget->Capabilities(选项卡)->Background Modes 中的 BackgroundMode enter image description here

在您的 AppDelegate 方法 - (BOOL)application:(UIApplication* )application didFinishLaunchingWithOptions:(NSDictionary* )launchOptions 中添加一个用于 NSURLSessin 的初始化器,代码如下:

    NSURLSessionConfiguration *sessionConfiguration;
    NSString *someUniqieIdentifierForSession = @"com.etbook.background.DownloadManager";
    if ([[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] firstObject] integerValue] >= 8) {
//This code for iOS 8 and greater
        sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:someUniqieIdentifierForSession];
    } else {
this code for iOS 7
        sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:someUniqieIdentifierForSession];
    }
    sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
    self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                 delegate:self
                                            delegateQueue:[NSOperationQueue mainQueue]];

当然,别忘了使用以下代码声明session属性:
@property (nonatomic, strong) NSURLSession session;

还需添加完成处理程序属性(如果您希望在应用程序终止或崩溃后获取后台下载进程的回调,则需要此属性):

@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();

在AppDelegate中添加委托方法:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{

    NSError *error;
    NSFileManager *fileManager = [NSFileManager defaultManager];

    NSString *destinationFilename = downloadTask.originalRequest.URL.lastPathComponent;
    NSURL *destinationURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:destinationFilename];

    if ([fileManager fileExistsAtPath:[destinationURL path]]) {
        [fileManager removeItemAtURL:destinationURL error:nil];
    }
    [fileManager copyItemAtURL:location
                         toURL:destinationURL
                         error:&error];
}

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (error != nil) {
        NSLog(@"Download completed with error: %@", [error localizedDescription]);
    }
    else{
        NSLog(@"Download finished successfully.");
}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

    if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
        NSLog(@"Unknown transfer size");
    }
    else{
        NSLog(@"progress = %lld Mb of %lld Mb", totalBytesWritten/1024/1024, totalBytesExpectedToWrite/1024/1024);
    }
}

-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    ETBAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    // Check if all download tasks have been finished.
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {

        if ([downloadTasks count] == 0) {
            if (appDelegate.backgroundTransferCompletionHandler != nil) {
                // Copy locally the completion handler.
                void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;

                // Make nil the backgroundTransferCompletionHandler.
                appDelegate.backgroundTransferCompletionHandler = nil;

                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    // Call the completion handler to tell the system that there are no other background transfers.
                    completionHandler();

                    // Show a local notification when all downloads are over.
                    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
                    localNotification.alertBody = @"All files have been downloaded!";
                    [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
                }];
            }
        }
    }];
}


//Background download support (THIS IMPORTANT METHOD APPLICABLE ONLY IN YOUR AppDelegate.m FILE!!!)
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    self.backgroundTransferCompletionHandler = completionHandler;
}

声明你的类(例如在AppDelegate.h文件中)符合协议NSURLSessionDelegate,像这样:

@interface AppDelegate : UIResponder <UIApplicationDelegate, NSURLSessionDelegate>

然后在某个地方添加下载任务:

NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[NSURL URLWithString:urlString]];
task.taskDescription = [NSString stringWithFormat:@"Downloading file %@", [urlString lastPathComponent]];
[task resume];

当您的应用程序在终止后重新启动时,您的会话将被恢复并触发委托方法。同样,如果您的应用程序从后台唤醒到前台,您的应用程序委托方法也将被触发。


1
当您的应用程序进入后台时,请暂停/停止下载操作;当它回到前台时,请在NSOperation队列中恢复您已暂停的下载操作。
阅读下面的代码可能会有所帮助:
        AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:filePath shouldResume:YES];




        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            //handel completion
            [operations removeObjectForKey:audioItem.filename];

        }failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            //handel failure
                    operation = [operations objectForKey:audioItem.filename];
                    [operation cancel];
                    [operations removeObjectForKey:audioItem.filename];
                    if (error.code != NSURLErrorCancelled) {
                        [self showErrorAlert];
                        NSLog(@"Error: %@", error);
                    }




        }];


    [operation setProgressiveDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) {
            //handel progress
            NSNumber *progress = [NSNumber numberWithFloat:((float)totalBytesReadForFile / (float)totalBytesExpectedToReadForFile)];
            float progress=progress.floatValue;
            [self performSelectorOnMainThread:@selector(updateProgressBar:) withObject:[NSArray arrayWithObjects:audioItem, progress, nil] waitUntilDone: YES];

        }];

        [operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{
            // TODO: Clean up operations
            NSLog(@"App has been in background too long, need to clean up any connections!");
        }];

        [operations setValue:operation forKey:@"key"]; // store the NSOperation for further use in application to track its status.
        [downloadQueue addOperation:operation];//here downloadQueue is NSOperationQueue instance that manages NSOperations.

要暂停下载操作,请使用以下内容:

[operation pause];

使用此类行以恢复:

[operation resume];

"operations"是什么? - Siriss
这里的“operations”是NSMutableDictionary,将文件名存储为键,NSOperation对象作为值。 - Sandeep Ahuja

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接