Как возобновить загрузку с помощью MKNetworkKit в случае сбоя сети

Якобы MKNetworkKit поддерживает возобновление прерванных загрузок, но не совсем понятно, как это можно сделать. В другом потоке разработчик говорит, что он работает, если сервер отправляет заголовки Range.

Как отменить или приостановить загрузку MKNetworkKit iOS?

Однако, насколько я понимаю, именно клиент отправляет заголовки Range. Я ожидаю, что библиотека увидит, сколько было загружено, а затем запросит соответствующий диапазон. Я не вижу места в коде, который делает это.

Метод

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

действительно проверяет, был ли указан Range, но, похоже, на самом деле нет никакого кода, выполняющего определение.

Кто-нибудь заставил MKNetworkKit возобновить загрузку после сбоя сети?

1 ответ

Помимо функции freezable, которая, как я понимаю, не работает для GET, в стандартном MKNetworkKit нет способа возобновить загрузку. Однако небольшая модификация позволяет возобновить загрузку, которая была остановлена

beginBackgroundTaskWithExpirationHandler

или

operationFailedWithError

это требует сохранения downloadDataSize в другое свойство, скажем, resumeDownloadedDataSize, и предоставление этого доступа вызывающему объекту с помощью уведомления, такого как

NSDictionary *resumeDownloadedDataSizeDetails = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithLong:self.resumeDownloadedDataSize], @"resumeDownloadedDataSize", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kMKNetworkOperationEndBackgroundTaskWithExpirationHandler object:self userInfo:resumeDownloadedDataSizeDetails];

(определите kMKNetworkOperationEndBackgroundTaskWithExpirationHandler в MkNetworkKit.h)

Установите для resumeDownloadedDataSize значение 0, где операция завершается без ошибок или прерываний, и установите равным downloadDataSize, когда вы хотите продолжить.

Затем добавьте

if (self.resumeDownloadedDataSize !=0) {

            NSString* range = @"bytes=";
            range = [range stringByAppendingString:[[NSNumber numberWithLong:self.resumeDownloadedDataSize] stringValue]];
            range = [range stringByAppendingString:@"-"];

            [[self request] setValue:range forHTTPHeaderField:@"Range"];
}

в

-(void) start

Этот код в начале

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    if (self.downloadedDataSize == 0) {
        // This is the first batch of data
        // Check for a range header and make changes as neccesary
        NSString *rangeString = [[self request] valueForHTTPHeaderField:@"Range"];
        if ([rangeString hasPrefix:@"bytes="] && [rangeString hasSuffix:@"-"]) {
            NSString *bytesText = [rangeString substringWithRange:NSMakeRange(6, [rangeString length] - 7)];
            self.startPosition = [bytesText integerValue];
            self.downloadedDataSize = self.startPosition;
        }
    }  

Теперь работает для моего добавленного смещения, так как клиент запросил диапазон.

Я также добавил

@property (assign, nonatomic) NSUInteger resumeDownloadedDataSize;

в заголовочный файл, чтобы я мог установить его из других представлений.

Теперь в вашем вызывающем объекте вы можете прослушать уведомление

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMKNetworkOperationEndBackgroundTaskWithExpirationHandler:) name:kMKNetworkOperationEndBackgroundTaskWithExpirationHandler object:nil]; 

проверьте это для вас и перезапустите операцию, установив диапазон.

- (void) didMKNetworkOperationEndBackgroundTaskWithExpirationHandler: (NSNotification*) notification
{
    if ([[notification object] isEqual:downloadOperation]) {
        resumeDownloadedDataSize = [notification.userInfo objectForKey:@"resumeDownloadedDataSize"];
        bDownloadOperationCancelled=YES;
    }
}

Поскольку я использую это для загрузки большого файла, срок действия обработчика истекает, и я перезапускаю операцию, когда возвращаюсь на передний план.

if (bDownloadOperationCancelled) {
        NSLogDebug(@"DownloadOperationCancelled restarted");
        [self doFileDownload];
        bDownloadOperationCancelled=NO;
}

где

- (void) doFileDownload
{
    downloadOperation = [ApplicationDelegate.downloadEngine downloadVideoFile:authDownloadURLString toFile:downloadPath withOffset:resumeDownloadedDataSize];
(Your code for handling completion blocks etc)
…

}

Последнее, что нужно сделать, это убедиться, что в вашем движке вы добавляете YES

[op addDownloadStream:[NSOutputStream outputStreamToFileAtPath:filePath append:YES]];

Таким образом, резюме добавляет в файл.

Просто чтобы прояснить ситуацию, я использую AWS CloudFront, и это поддерживает использование заголовков диапазона, когда данные хранятся в S3.

Похоже, это работает для меня. Я уверен, что есть более элегантные способы сделать это.

Другие вопросы по тегам