带有本地图像文件的iOS WebView远程HTML
以前也有类似的问题,但我永远找不到解决方案。
这是我的情况 - 我的UIWebView加载一个远程HTML页面。 网页中使用的图像在构建时已知。 为了加快页面加载速度,我想将图像文件打包到iOS应用程序中并在运行时替换它们。
[请注意,该html是远程的。 我总是从本地获取加载html和图像文件的答案 - 我已经完成了]
我得到的最接近的建议是在html页面和iOS应用程序中使用自定义url方案,例如myapp://images/img.png,使用NSURLProtocol子类截取myapp:// URL并将图像替换为本地图片。 理论上听起来不错,但我还没有遇到一个完整的代码示例来说明这一点。
我有Java背景。 我可以使用自定义内容提供程序轻松完成Android操作。 我相信iOS / Objective-C必须存在类似的解决方案。 我没有足够的Objective-C经验在短时间内自己解决问题。
任何帮助将不胜感激。
确定这里是一个例子如何继承NSURLProtocol和提供的图像(image1.png),其已经在包。 下面是子类的头,实现以及如何在viewController(不完整代码)和本地html文件(可以很容易地与远程交换)中使用它的例子。 我已经调用了自定义协议: myapp://
您可以在底部的html文件中看到。
并感谢您的问题! 我自己问了很长一段时间,弄清楚这一点的时间每秒都值得。
编辑:如果有人难以让我的代码在当前iOS版本下运行,请查看sjs的答案。 当我回答这个问题时,它正在工作。 他指出了一些有益的补充并纠正了一些问题,所以也给他一些道具。
这是它在我的模拟器中的外观:
MyCustomURLProtocol.h
@interface MyCustomURLProtocol : NSURLProtocol
{
NSURLRequest *request;
}
@property (nonatomic, retain) NSURLRequest *request;
@end
MyCustomURLProtocol.m
#import "MyCustomURLProtocol.h"
@implementation MyCustomURLProtocol
@synthesize request;
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSLog(@"%@", request.URL);
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
[response release];
}
- (void)stopLoading
{
NSLog(@"something went wrong!");
}
@end
MyCustomProtocolViewController.h
@interface MyCustomProtocolViewController : UIViewController {
UIWebView *webView;
}
@property (nonatomic, retain) UIWebView *webView;
@end
MyCustomProtocolViewController.m
...
@implementation MyCustomProtocolViewController
@synthesize webView;
- (void)awakeFromNib
{
self.webView = [[[UIWebView alloc] initWithFrame:CGRectMake(20, 20, 280, 420)] autorelease];
[self.view addSubview:webView];
}
- (void)viewDidLoad
{
// ----> IMPORTANT!!! :) <----
[NSURLProtocol registerClass:[MyCustomURLProtocol class]];
NSString * localHtmlFilePath = [[NSBundle mainBundle] pathForResource:@"file" ofType:@"html"];
NSString * localHtmlFileURL = [NSString stringWithFormat:@"file://%@", localHtmlFilePath];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:localHtmlFileURL]]];
NSString *html = [NSString stringWithContentsOfFile:localHtmlFilePath encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:html baseURL:nil];
}
file.html
<html>
<body>
<h1>we are loading a custom protocol</h1>
<b>image?</b><br/>
<img src="myapp://image1.png" />
<body>
</html>
尼克韦弗有正确的想法,但他的答案中的代码不起作用。 它也打破了一些命名约定,从不用NS
前缀命名自己的类,并遵循大写首字母缩略词(如标识符名称中的URL)的约定。 为了使这个容易遵循,我会坚持他/他的命名。
这些更改很微妙但很重要:丢失未分配的request
ivar,而是参考NSURLProtocol
提供的实际请求,它工作正常。
NSURLProtocolCustom.h
@interface NSURLProtocolCustom : NSURLProtocol
@end
NSURLProtocolCustom.m
#import "NSURLProtocolCustom.h"
@implementation NSURLProtocolCustom
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSLog(@"%@", self.request.URL);
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
[response release];
}
- (void)stopLoading
{
NSLog(@"request cancelled. stop loading the response, if possible");
}
@end
Nick代码的问题是NSURLProtocol
子类不需要存储请求。 NSURLProtocol
已经有了这个请求,你可以用方法-[NSURLProtocol request]
或者同名的属性来访问。 由于原始代码中的ivar request
从未被分配,所以它始终nil
(并且如果它被分配了,它应该在某处被释放)。 该代码不能也不行。
其次,我建议在创建响应之前读取文件数据,并将[data length]
作为预期的内容长度而不是-1。
最后, -[NSURLProtocol stopLoading]
不一定是错误,它只是意味着如果可能的话,你应该停止响应。 用户可能已取消它。
我希望我能正确理解你的问题:
1)加载远程网页...和
2)用app / build内的文件替换某些远程资产
对?
那么,我正在做的事情如下(由于Mobile Safari缓存限制为5MB,我将其用于视频,但我认为任何其他DOM内容应该同样工作):
•创建一个本地(用Xcode编译)带有样式标签的HTML页面,用于替换应用内/构建内容,设置为隐藏,例如:
<div style="display: none;">
<div id="video">
<video width="614" controls webkit-playsinline>
<source src="myvideo.mp4">
</video>
</div>
</div>
•在同一个文件中提供一个内容div,例如
<div id="content"></div>
•(在此使用jQuery)从远程服务器加载实际内容,并将本地(Xcode导入的资产)附加到目标div,例如
<script src="jquery.js"></script>
<script>
$(document).ready(function(){
$("#content").load("http://www.yourserver.com/index-test.html", function(){
$("#video").appendTo($(this).find("#destination"));
});
});
</script>
•将www文件(index.html / jquery.js / etc ...使用根级别进行测试)放入项目并连接到目标
•远程HTML文件(位于yourserver.com/index-test.html)有一个
<base href="http://www.yourserver.com/">
•以及目标div,例如
<div id="destination"></div>
•最后在您的Xcode项目中,将本地HTML加载到Web视图中
self.myWebView = [[UIWebView alloc]init];
NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self.myWebView loadHTMLString:content baseURL:baseURL];
对我来说,最好结合https://github.com/rnapier/RNCachingURLProtocol进行脱机缓存。 希望这可以帮助。 F
链接地址: http://www.djcxy.com/p/34749.html上一篇: iOS WebView remote html with local image files
下一篇: How to Get the Title of a HTML Page Displayed in UIWebView?