[版权声明] 本站内容采用 知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆 (CC BY-NC-SA 3.0 CN) 进行许可。
部分内容和资源来自网络,纯学习研究使用。如有侵犯您的权益,请及时联系我,我将尽快处理。
如转载请注明来自: Broly的博客,本文链接: iOS定制NSURLProtocol实现离线缓存
iOS如果直接用UIWebView直接加载网页,这种方法实现网页浏览最简单,理论上是没什么问题的。然而实际生产开发中,会碰到需要问题,比如:
- 网页图片太多响应慢
- 手机网络不好响应慢
- 网页前端Javascript插件太多响应慢
- 服务器并发高压力大响应慢
- ......
很多问题都会导致网页加载响应慢。所以就引出本文的主题,利用离线缓存优化加载流程,提升用户体验,同时可以一定程度上分散服务器压力。
iOS提供了个非常强大的功能给我们 —— NSURLProtocol
其强大之处在于可以拦截请求,然后自定义Response返回给UIWebView!
实现步骤
- 添加一个webview
WebViewController.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// // WebViewController.h // demo // // Created by Broly on 16/4/20. // Copyright © 2016年 Broly. All rights reserved. // #import <UIKit/UIKit.h> @interface WebViewController : UIViewController @property (weak, nonatomic) IBOutlet UIWebView *webView; @end |
WebViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
// // WebViewController.m // demo // // Created by Broly on 16/4/20. // Copyright © 2016年 Broly. All rights reserved. // #import "WebViewController.h" #import "CustomURLProtocol.h" @interface WebViewController () <UIWebViewDelegate> @end @implementation WebViewController @synthesize webView = _webView; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // 重要!! 注册自定义的CustomURLProtocol [NSURLProtocol registerClass:[CustomURLProtocol class]]; self.webView.delegate = self; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // document目录下有个demo文件夹,放置缓存文件 NSString *path = [[paths objectAtIndex:0] stringByAppendingString:@"/demo"]; // 指定基础url路径 NSURL *baseURL = [NSURL fileURLWithPath:path]; NSString *htmlPath = [path stringByAppendingString:@"/index.html"]; NSString *htmlCont = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@", htmlPath); // 加载本地index.html,当然也可以加载远程网页 [self.webView loadHTMLString:htmlCont baseURL:baseURL]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ NSLog(@"shouldStartLoadWithRequest"); return YES; } - (void)webViewDidStartLoad:(UIWebView *)webView{ NSLog(@"webViewDidStartLoad"); } - (void)webViewDidFinishLoad:(UIWebView *)webView{ NSLog(@"webViewDidFinishLoad"); } - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error{ NSLog(@"didFailLoadWithError"); } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end |
2. 添加自定义的NSURLProtocol
CustomURLProtocol.h
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// // CustomURLProtocol.h // demo // // Created by Broly on 16/4/21. // Copyright © 2016年 Broly. All rights reserved. // #import <Foundation/Foundation.h> @interface CustomURLProtocol : NSURLProtocol @end |
CustomURLProtocol.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// // CustomURLProtocol.m // demo // // Created by Broly on 16/4/21. // Copyright © 2016年 Broly. All rights reserved. // #import "CustomURLProtocol.h" @implementation CustomURLProtocol + (BOOL)canInitWithRequest:(NSURLRequest *)request { return [[[request URL] scheme] isEqualToString:@"file"]; // 这里是重点,定义拦截的规则,比如以XXX结尾的,或者XXX开头的都可以 } + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { return request; } - (void) startLoading { // 这里可以自定义Response返回 id<NSURLProtocolClient> client = [self client]; NSURLRequest* request = [self request]; NSString *pathString = [[request URL] absoluteString]; NSString *fileName = [pathString lastPathComponent]; NSString *fileToLoad = nil; fileToLoad = [pathString substringFromIndex:7]; NSLog(@"%@\n%@", pathString, fileToLoad); NSData *data = [NSData dataWithContentsOfFile:fileToLoad]; NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:[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]; } - (void) stopLoading {} @end |