UIWebView/NSURLProtocol - заполнитель для недоступных внешних активов в автономном режиме
Мое приложение - электронная книга для просмотра книг на iPhone/iPad. У пользователя есть возможность загрузить книгу, которую мы сохраняем на устройстве в виде файла.epub (заархивированный контент) - это позволяет просматривать книгу в автономном режиме. Содержание страницы в HTML.
Некоторые ресурсы, такие как видео, не включены в этот контент.epub. Когда пользователь переходит на такую страницу, я должен обнаружить внешний ресурс, который не находится в.ePub, и отобразить простой заполнитель с текстом "Этот контент недоступен, когда не подключен".
Эти видео могут быть встроены в HTML-тег iFrame или тег объекта.
Прямо сейчас у нас есть класс, который наследуется от абстрактного класса NSURLProtocol, и я использую его для выполнения этого требования. У меня есть реализация для этих 3 методов:
+ (BOOL) canInitWithRequest:(NSURLRequest *)request
- (void)startLoading
- (void) sendResponse:(NSData *)data mimetype:(NSString *)mimetype url:(NSURL *)url
Моя проблема сейчас заключается в том, что у меня есть простой.png, который показывает "Этот контент недоступен, когда в автономном режиме", но это некрасиво, потому что иногда площадь iFrame меньше, чем изображение. Как я масштабирую это, чтобы соответствовать? Или есть лучший подход? Это не должно быть изображение, пока я могу показать это сообщение, что контент недоступен. Мой текущий код в методе startLoading:
- (void) startLoading
{
…
NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] bundlePath],@"PxeReaderResources.bundle"];
NSString *pathToPlaceholder = [NSString stringWithFormat:@"%@/%@",bundlePath,@"OfflinePlaceholder.png"]; //my placeholder image
NSLog(@"Path to placeholder is: %@", pathToPlaceholder);
data = [[NSFileManager defaultManager] contentsAtPath:pathToPlaceholder];
…
[self sendResponse:data mimetype:@"application/octet-stream" url:self.request.URL];
}
- (void) sendResponse:(NSData *)data mimetype:(NSString *)mimetype url:(NSURL *)url
{
NSDictionary *headers = @{@"Content-Type" : mimetype, @"Access-Control-Allow-Origin" : @"*", @"Cache-control" : @"no-cache"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headers];
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
}
Спасибо за любые предложения.
2 ответа
Я смог отправить простой пользовательский тег html вместо внешнего ресурса. Вот кодекс - надеюсь, это кому-нибудь поможет. ПРИМЕЧАНИЕ: весь этот код находится в моем пользовательском классе, который наследуется от NSURLProtocol
#define EXTERNAL_REQUEST_KEY @"ExternalRequest"
+ (BOOL) canInitWithRequest:(NSURLRequest *)request
{
NSString* filePath = [[PxePlayer sharedInstance] getBaseURL]; //gets base path to the epub zipped folder
if ([Reachability isReachable])
{
return filePath != nil && [@"file" caseInsensitiveCompare:request.URL.scheme] == NSOrderedSame;
}
else
{
if ([request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme isEqualToString:@"http"]) //these schemes won't work if offline
{
[NSURLProtocol setProperty:@YES forKey:EXTERNAL_REQUEST_KEY inRequest:(NSMutableURLRequest*)request]; //marking those request so that we will only provide placeholder for these requests
}
return filePath != nil && ([@"file" caseInsensitiveCompare:request.URL.scheme] == NSOrderedSame ||
[@"https" caseInsensitiveCompare:request.URL.scheme] == NSOrderedSame ||
[@"http" caseInsensitiveCompare:request.URL.scheme] == NSOrderedSame);
}
}
- (void) startLoading
{
...
if ([NSURLProtocol propertyForKey:EXTERNAL_REQUEST_KEY inRequest:self.request])
{
custMimeType = @"text/html";
data = [self prepareDataForPlaceholderForExternalAsset];
}
...
if (data)
{
//Now ready to send the placeholder as custom response
[self sendResponse:data mimetype:custMimeType url:self.request.URL];
}
}
//method to create a simple div tag as NSData
- (NSData*) prepareDataForPlaceholderForExternalAsset
{
NSString *placeholder =
@"<div style=\"background-color:#efefef; border:1px solid #999999; text-align:center; width:100%; height:100%\"> \
<font font-family=\"Helvetica Neue\" font-weight=\"Medium\" size=\"5\" color=\"#b3b3b3\"> \
<div style=\"display:inline-block; margin-top:5%\"> \
This content is unavailable when offline or printing \
</div> \
</font> \
</div>";
return [placeholder dataUsingEncoding:NSUTF8StringEncoding];
}
- (void) sendResponse:(NSData *)data mimetype:(NSString *)mimetype url:(NSURL *)url
{
NSDictionary *headers = @{@"Content-Type" : mimetype, @"Access-Control-Allow-Origin" : @"*", @"Cache-control" : @"no-cache"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headers];
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
}
Вместо того чтобы пытаться перехватить загрузку ресурсов, вы можете использовать (внедрить) JavaScript для обхода DOM, ища эти теги object / iframe и заменяя их своим симпатичным сообщением "Не доступно в автономном режиме". Вы, вероятно, сделаете это после загрузки страницы или попытаетесь проанализировать и изменить HTML-код перед его передачей в WebView.