前言
之前使用UIWebView
或者WKWebView
加载本地CSS
JS
时候直接:
// html 为其他途径获取到的 html 字符串
NSURL *baseURL = [NSURL URLWithString:[NSBundle mainBundle].bundlePath];
[_webView loadHTMLString:html baseURL:baseURL];
设置一下 baseURL
就能轻松加载到相对路径下的CSS
JS
资源文件.
但是这次却遇到了比较特殊的情况:
正文
问题
所谓的特殊情况就是这次我拿到的html
是由Markdown
转换过来的html
字符串,本身包含有完整的URL
信息.比如这样的内容.
// img 标签
<img src="http://img.google.com/image.png">
// 其他引入的 css, js 等
<script src="http://cdn.google.com/keymaster.min.js" type="text/javascript"></script>
<link href="http://cdn.google.com/prism.css" rel="stylesheet" type="text/css" />
在这种情况下:
既有相对路径,又有完整
URL
的时候.
设置了baseURL
就会导致这些有完整URL
的图片
,JS
,CSS
等内容不能够正常加载.
解决办法
思路
- 把所有的相对路径都补充成完整的
URL
. - 通过
NSURLProtocol
来拦截请求并替换内容达到需求目的.
做法
此处不介绍NSURLProtocol
用法,直接说解决办法:
如果原来资源文件的相对路径为/jquery.js
.
那么现在把相对路径的路径全部补全为http://cdn.zhk1024.com/jquery.js
.
此时URL
的host
则为cdn.zhk1024
(此处host
可以根据自己情况来写).
则在+ (BOOL)canInitWithRequest:
方法内过滤host
为cdn.zhk1024
的所有请求,此类请求都是需要拦截的对象.
此处补全的 host
必须是在应用内没有使用过的域名
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([request.URL.host isEqualToString:@"cdn.zhk1024"]) {
// 此处返回 YES, 则该请求会进入 - (void)startLoading 方法
return YES;
}
return NO;
}
然后在- (void)startLoading
方法内对拦截下来的请求进行处理
此处主要是通过判断URL
等能够区分出请求的特征来分别加载资源文件(CSS
JS
等),然后把数据提交给 URL加载系统 (URL Loading System).
- (void)startLoading {
id <NSURLProtocolClient> client = [self client];
NSURLRequest *request = self.request;
NSString *path = [[request URL] absoluteString];
NSString *fileToLoad = nil;
if ([path isEqualToString:@"http://cdn.zhk1024/reset.css"]) {
fileToLoad = [[NSBundle mainBundle] pathForResource:@"reset" ofType:@"css"];
}
....
其他判断此处省略
....
// 加载本地文件的数据
NSData *data = [NSData dataWithContentsOfFile:fileToLoad];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:[NSDictionary dictionary]];
[client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[client URLProtocol:self didLoadData:data];
[client URLProtocolDidFinishLoading:self];
}
到此我们要做的事情就做完了,其他全部交给UIWebView
即可.
此处之所有没有写WKWebView
是因为WKWebView
和NSURLSession
如果使用NSURLProtocol
的话需要一些特殊设置.
而WKWebView
支持NSURLProtocol
更是需要使用一些私有 API
,一方面是苹果审核问题,另一方面是私有 API
稳定性没有保障.
因此最终选择了UIWebView
.
网友评论