Cómo download files grandes en segundo plano utilizando AFNetworking 3.0 y presentar notifications locales cuando la session completa todas las tareas

Estoy intentando download un file de video grande en mi aplicación usando AFNetworking 3.0. No pude encontrar ningún documento específico sobre cómo download un file en segundo plano utilizando AFNetworking.

Sé que AFNetworking utiliza AFURLSessionManager y AFHTTPSessionManager que implementa todos los delegates de NSURLSession .

Lo que hice hasta ahora es, creó un backgroundSessionConfugaration y comenzó un file para download usando esto.

self.manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:bgDownloadSessionIdentifier]]; [self.manager downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil]; 

Cuando comienza la descarga, pongo mi aplicación en segundo plano. Lo que encontré hasta ahora es que la aplicación se ejecuta en segundo plano hasta 20 minutos y la descarga fue exitosa. Pero la aplicación: handleEventsForBackgroundURLSession en appDelegate no se llama, por lo que mi setDidFinishEventsForBackgroundURLSessionBlock tampoco recibe llamadas.

Quiero mostrar una notificación solo cuando se llama setDidFinishEventsForBackgroundURLSessionBlock .

Cuando inicializo al administrador usando esto. (en lugar de backgroundSessionConfiguration )

 self.manager = [AFHTTPSessionManager manager]; 

La aplicación sigue siendo capaz de download el file completo después de 20 minutos en segundo plano.

Mi problema es por qué la aplicación se ejecuta hasta 20 minutos y completó la descarga. Como ideal iOS debería matar a la aplicación después de 10 minutos. También por qué la aplicación: handleEventsForBackgroundURLSession no recibe llamadas después de la finalización de la session.

Ya me he referido a esta AFNetworking 2.0 y las transferencias de background , pero parece que no funciona para mí.

Los modos de background de las capacidades, ya sea ON u OFF, no afectan a nada en mi aplicación.

Por favor, ayúdenme o sugiérrenme qué estoy haciendo mal aquí.

He cargado el código de ejemplo aquí. https://www.dropbox.com/s/umwicuta2qzd3k1/RSNetworkKitExample.zip?dl=0

 AppDelegate.m -(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler { NSLog(@"===== background session completed in AppDelegate ===== "); if([identifier isEqualToString:bgDownloadSessionIdentifier]){ [RSDownloadManager shanetworkingManager].backgroundSessionCompletionHandler = completionHandler; } } 

================================================== ==

 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 shanetworkingManager].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 shanetworkingApplication] applicationIconBadgeNumber] + 1; [[UIApplication shanetworkingApplication] presentLocalNotificationNow:localNotification]; }; [[RSDownloadManager shanetworkingManager] 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); }]; } 

================================================== ==

 RSDownloadManager.h #import <Foundation/Foundation.h> #import "AFHTTPSessionManager.h" static NSString *bgDownloadSessionIdentifier = @"com.RSNetworkKit.bgDownloadSessionIdentifier"; @interface RSDownloadManager : NSObject @property (nonatomic, strong) AFHTTPSessionManager *manager; @property (nonatomic, copy) void (^backgroundSessionCompletionHandler)(void); +(instancetype)shanetworkingManager; -(NSURLSessionDownloadTask *)downloadInBackgroundWithURL:(NSString *)urlString downloadProgress:(void (^)(NSNumber *progress))progressBlock success:(void (^)(NSURLResponse *response, NSURL *filePath))completionBlock andFailure:(void (^)(NSError *error))failureBlock; @end 

================================================== ==

 RSDownloadManager.m @implementation RSDownloadManager #pragma mark - Singleton instance +(instancetype)shanetworkingManager { static RSDownloadManager *_downloadManager = nil; static dispatch_once_t token; dispatch_once(&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; } 

Este método de delegado no se llamará a veces,

  • Si la aplicación ya se está ejecutando cuando la tarea se completa.
  • aplicación terminada por el button de inicio.
  • Si no puede iniciar un NSURLSession de background con el mismo identificador.

Nota : esto se comporta de manera diferente en el simulador, así que verifique en el dispositivo real.

¿Por qué simplemente no reemplaza el bloque de notificación local al bloque de éxito en su descargaInBackgroundWithURL: downloadProgress: fucntion? Método en AppDelegate realmente no llamado. Y necesita registrar su notificación

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){ [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]]; } return YES; } 

Y para la notificación local, agregue date y zona horaria:

  UILocalNotification* localNotification = [[UILocalNotification alloc] init]; localNotification.alertBody = @"Download Complete!"; localNotification.alertAction = @"Background Transfer Download!"; [localNotification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]]; [localNotification setTimeZone:[NSTimeZone defaultTimeZone]]; //On sound localNotification.soundName = UILocalNotificationDefaultSoundName; //increase the badge number of application plus 1 localNotification.applicationIconBadgeNumber = [[UIApplication shanetworkingApplication] applicationIconBadgeNumber] + 1; [[UIApplication shanetworkingApplication] presentLocalNotificationNow:localNotification]; 

Ahora funciona. Aclamaciones.