Enstringment arrière-plan NSURLSession téléversements

Quelqu'un at-il réussi à enstringr les téléchargements d'arrière-plan NSURLSession?

J'essaye de download un énorme file video dans des pièces de 5 Mo en utilisant le téléchargement en arrière-plan de NSURLSession. Les téléchargements doivent être en ordre. Le tout fonctionne bien au premier plan. J'utilise AFNetwoking pour cela, et c'est un téléchargement en plusieurs parties. Mais lorsque l'application est en arrière-plan, le premier élément est bien chargé et démarre le second en arrière-plan (dans setDidFinishEventsForBackgroundURLSessionBlock de AFURLSessionManager). Mais il s'arrête brusquement (ma meilleure estimation est dans 30 secondes, car une application réveillée en arrière-plan a une durée de vie maximale de 30 secondes) et rien ne se passe. Je m'attendais à ce que la deuxième session se termine en arrière-plan et appelle le troisième, un comportement en string, mais cela ne semble pas fonctionner.

J'ai essayé d'append toutes les parties du file à un seul NSURLSession en une fois avec un HTTPMaximumConnectionsPerHost = 1 – cela fonctionne bien et télécharge le file complet en parties. Mais les parties du file sont choisies dans un ordre random, c'est-à-dire que la partie 1 est téléchargée, puis la partie 5, la partie 3, la partie 10, etc. J'ai essayé d'append ceci dans un NSOperationQueue avec la dépendance entre les opérations et ceci semble gâcher le tout – le téléchargement ne fonctionne pas du tout.

Je sais que le file video peut être téléchargé en tant que file unique en arrière-plan, mais le server s'attend à cela dans des pièces de 5 Mo. Par conséquent, je suppose que ma seule option est d'enstringr les chargements, ou d'append toutes les parties à un NSURLSession, mais assurez-vous qu'ils sont toujours téléchargés dans l'ordre où ils sont ajoutés.

Toute aide serait appréciée.

Mon code:

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSSsortingng ssortingngWithFormat:@"%d", rand()]]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:config]; config.HTTPMaximumConnectionsPerHost = 1; [manager setDidFinishEventsForBackgroundURLSessionBlock:^(NSURLSession *session) { dispatch_async(dispatch_get_main_queue(), ^{ // Call the completion handler to tell the system that there are no other background transfers. // completionHandler(); [self upload]; }); }]; } - (IBAction)start:(id)sender { [self upload]; } -(void) upload { NSSsortingng *filePath = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"mp4"]; AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer]; NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:@"234", @"u", @"Sample.mp4", @"f",nil]; NSMutableURLRequest *request = [serializer multipartFormRequestWithMethod:@"POST" URLSsortingng:urlSsortingng parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { [formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath] name:@"data" fileName:@"Sample.mp4" mimeType:@"video/mp4" error:nil]; } error:nil]; __block NSSsortingng *tempMultipartFile = [NSTemporaryDirectory() ssortingngByAppendingPathComponent:@"Test"]; tempMultipartFile = [tempMultipartFile ssortingngByAppendingSsortingng:[NSSsortingng ssortingngWithFormat:@"%d", rand()]]; NSURL *filePathtemp = [NSURL fileURLWithPath:tempMultipartFile]; __block NSProgress *progress = nil; [serializer requestWithMultipartFormRequest:request writingStreamContentsToFile:filePathtemp completionHandler:^(NSError *error) { NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePathtemp progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { NSLog(@"Request--> %@.\n Response --> %@ \n%@", request.URL.absoluteSsortingng ,responseObject, error? [NSSsortingng ssortingngWithFormat:@" with error: %@", [error localizedDescription]] : @""); //Lets us know the result including failures [[NSFileManager defaultManager] removeItemAtPath:tempMultipartFile error:nil]; }]; [uploadTask resume]; [manager setTaskDidSendBodyDataBlock:^(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { NSLog(@"uploading"); }]; }]; } 

Eh bien, j'ai finalement contacté Apple pour get des éclaircissements sur le téléversement d'arrière-plans – Ce n'est pas possible dans iOS.NSURLSession a un limiteur de débit qui empêche les applications d'exécuter des tâches chaînées en arrière-plan comme expliqué dans https://forums.developer.apple. com / thread / 14854 . Au lieu de cela, Apple propose des transferts par lots ou d'autres options telles que https://forums.developer.apple.com/thread/14853 . L'autre chose que je demandais était de order les multiples tâches dans la queue de téléchargement – c.-à-d. Forcer NSURLSession à charger des tâches dans l'ordre dans lequel elles sont ajoutées. Comme indiqué par dgatwood , l'utilisation d'un NSOperationQueue n'est pas possible et Apple a également mentionné la même chose.Comme mentionné par eskimo dans le courrier de réponse "NSURLSession ne garantit pas pour exécuter vos requests dans l'ordre et il n'y a aucun moyen d'appliquer cela." Donc je suis à peu près laissé l'option less sur mon problème original.

Une NSOperationQueue disparaît lorsque votre application le fait, ce qui n'est pas trop long après que vous l'ayez mise en arrière-plan. Donc ça ne va pas très bien fonctionner.

Au lieu de cela, stockez une list des files restants à download, dans l'ordre, soit dans un file sur le disque ou dans NSUserDefaults , en fonction de vos preferences personnelles. Ensuite, utilisez une tâche de téléchargement dans une session en arrière-plan pour démarrer la première tâche. Quand il se termine, si votre application n'est pas en cours d'exécution, elle devrait automatiquement être relancée en arrière-plan pour gérer datatables.

Pour prendre en charge ce comportement, dans votre application: handleEventsForBackgroundURLSession: completionHandler: méthode, recréez la session d'arrière-plan comme vous l'avez fait à l'origine et stockez le gestionnaire d'achèvement.

Peu de time après, vos methods de délégué pour la request doivent être appelées comme si votre application était toujours en cours d'exécution lorsque le téléchargement a été terminé. Entre autres choses, ces methods peuvent fournir à votre application datatables de réponse du server, l'object de réponse (pour vérifier le code d'état), etc.

Lorsque vous obtenez l'appel de délégué didCompleteWithError (qui est nul en cas de succès, IIRC), si le transfert a échoué, réessayez ou quoi que ce soit. Si cela a réussi, commencez à download le suivant et mettez à jour votre list de files sur le disque.

Dans les deux cas, lorsque la méthode ** URLSessionDidFinishEventsForBackgroundURLSession: ** de votre délégué de session est appelée, appelez le gestionnaire que vous avez stocké précédemment, comme suit:

 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ storedHandler(); }]; 

En appelant le gestionnaire d'achèvement, vous dites au operating system que vous n'avez pas besoin de continuer à fonctionner.

Rincez, répétez.

Si votre application est toujours en cours d'exécution à la fin de la requête, tout se passe comme décrit ci-dessus, sauf que vous n'obtenez pas l' application: handleEventsForBackgroundURLSession: completionHandler: ou URLSessionDidFinishEventsForBackgroundURLSession: calls, ce qui signifie que vous ne devez pas stocker le gestionnaire de fin ou appeler.

Voir le Guide de programmation de session URL pour plus de détails.