title: How to download large file in background using AFNetworking 3.0 and present local notification when session completes all the tasks
body: <p>I am trying to download large video file in my application using AFNetworking 3.0. 
  I couldn't find any specific document regarding how to download file in background using AFNetworking.</p>
  
  <p>I know AFNetworking uses <strong>AFURLSessionManager</strong> and <strong>AFHTTPSessionManager</strong> which itself implements all the delegates of <strong>NSURLSession</strong>.</p>
  
  <p>What I did so far is, created a <strong>backgroundSessionConfugaration</strong> and started a file to download using this.</p>
  
  <pre><code>self.manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:bgDownloadSessionIdentifier]];
  
  [self.manager downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil];
  </code></pre>
  
  <p>When download starts, I put my application in background. What I found so far is app is running in background till 20 mins and download was successful. But <strong>application:handleEventsForBackgroundURLSession</strong> in appDelegate is not called, so my <strong>setDidFinishEventsForBackgroundURLSessionBlock</strong> is also not getting called.</p>
  
  <p>I want to show a notification only when <strong>setDidFinishEventsForBackgroundURLSessionBlock</strong> is called.</p>
  
  <p>When I initialise manager using this. (instead of <strong>backgroundSessionConfiguration</strong>)</p>
  
  <pre><code>self.manager = [AFHTTPSessionManager manager];
  </code></pre>
  
  <p>Still app is able to download entire file after 20 mins in background.</p>
  
  <p>My problem is why application is running till 20 mins and completed the download. As ideally iOS should kill the app after 10 mins. Also why <strong>application:handleEventsForBackgroundURLSession</strong> is not getting called after session completion.</p>
  
  <p>I've already referred this <a href="https://stackoverflow.com/questions/21350125/afnetworking-2-0-and-background-transfers">AFNetworking 2.0 and background transfers</a>, but it seems not working for me.</p>
  
  <p><strong>Background Modes</strong> from capabilities is either ON or OFF doesn't affect anything in my application.</p>
  
  <p>Please help me or suggest me what I am doing wrong here.</p>
  
  <p>I've uploaded the example code here. 
  <a href="https://www.dropbox.com/s/umwicuta2qzd3k1/RSNetworkKitExample.zip?dl=0" rel="nofollow noreferrer">https://www.dropbox.com/s/umwicuta2qzd3k1/RSNetworkKitExample.zip?dl=0</a></p>
  
  <pre><code>AppDelegate.m
  
  -(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
  
    NSLog(@"===== background session completed in AppDelegate ===== ");
  
    if([identifier isEqualToString:bgDownloadSessionIdentifier]){
        [RSDownloadManager sharedManager].backgroundSessionCompletionHandler = completionHandler;
    }
  }
  </code></pre>
  
  <p>====================================================</p>
  
  <pre><code>ViewController.m
  
  
  - (IBAction)downloadVideoInBackground:(id)sender {
  
    NSString *videoURL = @"http://videos1.djmazadownload.com/mobile/mobile_videos/Tum%20Saath%20Ho%20(Tamasha)%20(DJMaza.Info).mp4";
  
   [RSDownloadManager sharedManager].backgroundSessionCompletionHandler = ^{
  
      NSLog(@"===== background session completed in ViewController ===== ");
  
      UILocalNotification* localNotification = [[UILocalNotification alloc] init];
      localNotification.alertBody = @"Download Complete!";
      localNotification.alertAction = @"Background Transfer Download!";
  
      //On sound
      localNotification.soundName = UILocalNotificationDefaultSoundName;
  
      //increase the badge number of application plus 1
      localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
  
      [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
  
  };
  
    [[RSDownloadManager sharedManager] downloadInBackgroundWithURL:videoURL downloadProgress:^(NSNumber *progress) {
  
       NSLog(@"Video download progress %.2f", [progress floatValue]);
  
    } success:^(NSURLResponse *response, NSURL *filePath) {
  
       NSLog(@"Video download completed at Path %@", filePath);
  
    } andFailure:^(NSError *error) {
  
       NSLog(@"Error in video download %@", error.description);
    }];
  
  }
  </code></pre>
  
  <p>====================================================</p>
  
  <pre><code>RSDownloadManager.h
  
  
  #import &lt;Foundation/Foundation.h&gt;
  #import "AFHTTPSessionManager.h"
  
  static NSString *bgDownloadSessionIdentifier = @"com.RSNetworkKit.bgDownloadSessionIdentifier";
  
  @interface RSDownloadManager : NSObject
  
  @property (nonatomic, strong) AFHTTPSessionManager *manager;
  
  @property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void);
  
  +(instancetype)sharedManager;
  
  -(NSURLSessionDownloadTask *)downloadInBackgroundWithURL:(NSString *)urlString downloadProgress:(void (^)(NSNumber *progress))progressBlock success:(void (^)(NSURLResponse *response, NSURL *filePath))completionBlock andFailure:(void (^)(NSError *error))failureBlock;
  
  @end
  </code></pre>
  
  <p>====================================================</p>
  
  <pre><code>RSDownloadManager.m
  
  
  @implementation RSDownloadManager
  
  #pragma mark - Singleton instance
  +(instancetype)sharedManager
  {
     static RSDownloadManager *_downloadManager = nil;
     static dispatch_once_t token;
  
     dispatch_once(&amp;token, ^{
  
       if (!_downloadManager) {
          _downloadManager = [[self alloc] init];
       }
    });
     return _downloadManager;
  }
  
  #pragma mark - Init with Session Configuration
  
  -(void)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
     self.manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
  
     //self.manager = [AFHTTPSessionManager manager];
  }
  
  
  #pragma mark- Handle background session completion
  
  - (void)configureBackgroundSessionCompletion {
    typeof(self) __weak weakSelf = self;
  
    [self.manager setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession *session) {
  
       if (weakSelf.backgroundSessionCompletionHandler) {
           weakSelf.backgroundSessionCompletionHandler();
           weakSelf.backgroundSessionCompletionHandler = nil;
       }
    }];
  }
  
  
  #pragma mark- download in background request Method
  
  -(NSURLSessionDownloadTask *)downloadInBackgroundWithURL:(NSString *)urlString downloadProgress:(void (^)(NSNumber *))progressBlock success:(void (^)(NSURLResponse *, NSURL *))completionBlock andFailure:(void (^)(NSError *))failureBlock {
  
    /* initialise session manager with background configuration */
  
    if(!self.manager){
       [self initWithSessionConfiguration:[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:bgDownloadSessionIdentifier]];
    }
  
    [self configureBackgroundSessionCompletion];
  
    /* Create a request from the url */
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
  
    NSURLSessionDownloadTask *downloadTask = [self.manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
  
       if(progressBlock) {
           progressBlock ([NSNumber numberWithDouble:downloadProgress.fractionCompleted]);
       }
  
   } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
  
       NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
       return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
  
   } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
  
      if(error) {
          if(failureBlock) {
              failureBlock (error);
          }
      }
      else {
          if(completionBlock) {
              completionBlock (response, filePath);
          }
      }
  
   }];
  
    [downloadTask resume];
  
    return downloadTask;
   }
  </code></pre>