9

Я использую NSURLSessionDownloadTask объекты на NSURLSession, чтобы пользователи могли загружать документы, когда приложение находится в фоновом режиме/заблокировано. Я также хочу сообщить пользователю, что отдельные загрузки завершены через локальное уведомление.Отправить локальное уведомление, когда загрузка завершена через NSURLSession/NSURLSessionDownloadTask

С этой целью я вызываю локальное уведомление в методе делегирования задачи загрузки -URLSession:downloadTask:didFinishDownloadingToURL:, однако мне интересно, может ли быть лучшее место для добавления кода, запускающего уведомление, поскольку способ его использования Apple объясняет, загрузка задача будет передана в систему, и из этого я получаю, что эти делегаты больше не будут вызываться делегатом задачи загрузки (или вскоре после этого), когда приложение зашифровывается.

Мой вопрос: Что является лучшим местом для добавления кода для запуска локальных уведомлений? Кто-нибудь имел какой-либо предыдущий опыт добавления такого рода функциональности в свое приложение?

+0

Некоторые вещи я замечаю экспериментировать с этим: Когда несколько файлов в очереди для загрузки уведомления либо объединяются, либо отправляются в конце всех загрузок, либо не все из них запускаются. Я также экспериментировал с добавлением кода запуска уведомления в '-application: handleEventsForBackgroundURLSession: completeHandler:', но это * кажется * (из тестов, которые я сделал до сих пор), чтобы запускать уведомление только один раз, а не для каждого документа, который был загружен. – Andrei

ответ

7

Ответа на ваш вопрос можно найти в Apple, документациях URL Loading System Programming Guide:

В прошивке, когда фоновая передача завершается или требует учетных данных, если ваше приложение больше не работает, IOS автоматически возобновится ваше приложения в фон и вызывает метод application:handleEventsForBackgroundURLSession:completionHandler: на объекте вашего приложения UIApplicationDelegate. Этот вызов предоставляет идентификатор сеанса, который запустил запуск вашего приложения. Ваше приложение должно сохранить этот обработчик завершения, создать фоновый объект с тем же идентификатором и создать сеанс с этим объектом конфигурации. Новый сеанс автоматически вновь связан с текущей фоновой деятельностью. Позже, когда сессия заканчивает последнюю задачу загрузки фона, она отправляет сеанс делегирует сообщение URLSessionDidFinishEventsForBackgroundURLSession:. Затем делегат сессии должен вызвать хранимый обработчик завершения.

Если какая-либо задача завершена в то время как ваше приложение было приостановлено, URLSession:downloadTask:didFinishDownloadingToURL: метод делегата затем вызывается с задачей и URL для вновь загруженного файла , связанный с ним.

Как вы видите, это намного сложнее, чем просто установить delegate объект. По методам делегата вы будете уведомлены, только если приложение находится в режиме переднего плана. В других случаях (приложение в фоновом режиме приложение прекращается) вам необходимо обработать методы AppDelegate, описанные в приведенной выше цитате.

Также Apple предоставляет example project, который показывает, как работать с фоновой загрузкой/загрузкой задач. Этот пример поможет вам найти место, где можно поставить код «Local Notification».

+0

Несмотря на то, что в документации говорится, что 'application: handleEventsForBackgroundURLSession: completionHandler' вызывается каждый раз, когда задача завершается, я обнаружил, что это не так, она фактически вызывается один раз, когда заканчивается весь сеанс. Есть идеи по этому поводу? – Andrei

+1

@ Andrei Он не говорит, что он вызывает каждый раз, когда задача завершена. В нем говорится, что этот метод будет вызываться, если ** приложение было прекращено **, когда задача завершена. Возможно, приложение было в фоновом режиме, когда все остальные задачи завершены. В этом случае этот метод будет вызываться только один раз. –

+0

спасибо за быстрый ответ. Любая идея, как мне следует выяснить, когда ** была завершена одна задача **? – Andrei

0

Как описано выше в Visput, этот метод будет вызываться после завершения загрузки. application:handleEventsForBackgroundURLSession:completionHandler:

Это произойдет, если вы используете NSURLSessionConfiguration класс с backgroundSessionConfiguraton. Возможно, вам не хватает этой части.

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.BGTransfer"]; 
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5; // To set the max concurrent connections 

Это подробно объясняется here.

-1

Как Предложил @Gautam Джейна и есть использовать backgroundSessionConfiguration для достижения ур objective.Below я приложил пример, надеюсь, это поможет вам

DownloadModel.h

#import "AppDelegate.h" 
@interface DownloadModel : NSObject<NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDownloadDelegate>{ 
NSString *resp; 
} 

+(instancetype)shared; 
-(NSURLSessionDownloadTask *) downloadTaskWithURL:(NSURL*)url ; 
@end 

DownloadModel. м

#import "DownloadModel.h" 
@interface DownloadModel() 
@property (strong,nonatomic) NSURLSession *downloadSession; 
@end 

@implementation DownloadModel 
+(instancetype)shared{ 
static dispatch_once_t onceToken; 
static DownloadModel *downloader=nil; 

dispatch_once(&onceToken, ^{ 

    downloader=[DownloadModel new]; 
}); 

return downloader; 

} 

-(id)init{ 
self=[super init]; 
if(self){ 

    NSURLSessionConfiguration *downloadConfig=[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"DownloadDemo"]; 
    //  downloadConfig.timeoutIntervalForRequest = 30; 
    //  downloadConfig.timeoutIntervalForResource = 30; 
    //  downloadConfig.HTTPMaximumConnectionsPerHost = 1; 
    //  downloadConfig.sessionSendsLaunchEvents=YES; 
    downloadConfig.allowsCellularAccess = YES; 
    downloadConfig.networkServiceType = NSURLNetworkServiceTypeBackground; 
    //  downloadConfig.discretionary = YES; 
    self.downloadSession=[NSURLSession sessionWithConfiguration:downloadConfig delegate:self delegateQueue:nil]; 
    [email protected]"Video Downloader"; 

} 

return self; 
} 

-(NSURLSessionDownloadTask *) downloadTaskWithURL:(NSURL*)url{ 
return [self.downloadSession downloadTaskWithURL:url]; 
} 

#pragma mark download delegate 

уведомление об использовании ИЛИ местное Нет tification в этом методе

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

[[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadFinish" object:downloadTask userInfo:nil]; 
} 

Для Прогресс Скачать

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

CGFloat progress=(CGFloat)totalBytesWritten/totalBytesExpectedToWrite; 

NSDictionary *[email protected]{@"progress":@(progress)}; 

[[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadProgress" object:downloadTask userInfo:userInfo]; 


} 



#pragma mark delegate 
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{ 
AppDelegate *appdelegate=[[UIApplication sharedApplication] delegate]; 

if(appdelegate.backgroundSessionCompletionHandler){ 
    appdelegate.backgroundSessionCompletionHandler(); 
    appdelegate.backgroundSessionCompletionHandler=nil; 
} 
} 
@end 

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate> 

@property (strong, nonatomic) UIWindow *window; 

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

@end 

AppDelegate.m

-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ 

self.backgroundSessionCompletionHandler=completionHandler; 

[DownloadModel shared]; 
} 

ViewController.m Вызов этого метода -(NSURLSessionDownloadTask *) downloadTaskWithURL:(NSURL*)url

- (void)viewDidLoad { 

//Add Notification observers to track download progress and call the above method 

[DownloadModel shared] downloadTaskWithURL:url]; 

} 

Не забудьте включить Фон Fetchenter image description here

+0

Вам не нужно добавлять «Background Fetch» ​​для загрузки фона. – mohamede1945

Смежные вопросы