• 关于离线缓存webView的新方法NSURLProtocol


    博文转发自:http://blog.sina.com.cn/s/blog_6291e42d0102v0hf.html

    对于目前UIWebView的离线缓存方式主要有如下几种:

     
    1.HTML5 , Manifest
    最开始我的想法是使用HTML5中的离线存储功能,也就是分析Manifest文件来存储和更新部分资源文件。但是经过实践发现,UIWebView根本不支持HTML5,他只实现了Webkit中页面渲染的那一部分。所以要实现缓存必须要另辟蹊径。

    2.NSURLCache
      尽管在官方的说明文档里面说到NSURLCache和NSCachedURLResponse可以用于缓存,但经我测试好像仅仅只能用于加载本地某些资源文件
    ,而且还有大小的限制(好像根据iphone的版本不同而不同,最小是25KB吧),比如图片和JS代码, 而对于整体的页面无法进行加载。而且经过测试也没有感觉加载速度有明显的提高,我用的缓存策略是NSURLRequestReturnCacheDataElseLoad(可能是没有读取本地的缓存文件?),离线模式下也无法加载(可能是baseURL的关系?)
     
    另外做一点引申,对于动态获取数据的页面,我们不需要缓存的那些请求,只要过滤掉就可以了。
    先新建一个文件,把所有不需要缓存的请求的URL写在一个文件里,就象HTML5的 Cache Manifest那样。
    然后需要使用缓存的时候读取这个文件,并在重写的- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request  这个方法内对请求进行判断,如果是属于这个文件内的,比如web service的请求就直接返回,其他的就继续处理。

    3.ASIHTTPRequest,ASIDownloadCache  和 ASIWebPageRequest
       首先我得说,这确实是个很好的框架,使用起来确实很方便,但是对于缓存这个问题,好像也跟第二点提到的效果差不多,加载速度没有明显的提升,离线模式下也无法加载。这是实现的代码:
     
    4.NSURLProtocol

    由于UIWebView无法实现离线缓存,因此想利用Archieve机制来实现文件形式的离线缓存机制。同时,由于NSURLRequest每一次对链接的请求,都将触发NSURLProtocol的回调,因此对NSURLProtocol合理应用可以很好的达到离线缓存的目的。

     

    一、NSURLProtocol与NSURLProtocolClient简介:

        首先,我先介绍一下NSURLProtocol与NSURLProtocolClient:

        NSURLProtocol是一组方法,其中苹果文档是这样描述的:

     

        NSURLProtocol is an abstract class which provides the basic structure for performing protocol-specific loading of URL data.

     

        它是一个抽象类,为载入URL的data的一些特定协议提供基础的结构。要实现它里面的函数就必须继承它,因此小Potti将在后面创建一个MWURLProtocol类继承它,并实现它其中的一系列函数。

        而NSURLProtocol其中有个成员就是NSURLProtocolClient的一个实例。因为NSURLProtocol是由一系列的回调函数构成的(注册函数除外),而要对URL的data进行各种操作时就到了调用NSURLProtocolClient实例的时候了,这就实现了一个钩子,去操作URL data。

       NSURLProtocol有以下一系列的回调方法:

     

    - (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id )client;

    + (BOOL)canInitWithRequest:(NSURLRequest *)request;

    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;

    - (void)startLoading;

    - (void)stopLoading;

     

       其中canInitWithRequest是询问是否处理该请求的回调,如果不处理则后面所有函数都不会再调用。startLoading和stopLoading是分别对于loading开始从网页上抓取数据,从网页上抓取完数据的回调。其中startLoading称为我们可以重点利用的函数。

     

      NSURLProtocolClient主要有以下方法:

     

    - (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;

     

    - (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

     

    - (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

     

       其中wasRedirectedToRequest是重定向函数,cachedResponseIsValid是对cached的操作,didReceiveResponse是受到Response时的调用处理函数, didLoadData是load完数据时的调用,而后面的大致也与函数题目意思一样。而这些函数有个好处就是通通只需要我们调用它,系统就会做对应的事情,重载它也可以,不过一般不用这么麻烦。

       看到这些函数是不是想到了NSURLConnectionDataDelegate中的回调呢?哈哈,其实小Potti将在后面对2者有一个很好的结合。

     

    NSURLProtocol离线缓存的要点:

     

    1、尽早注册你的URLProtocol(application:didFinishLaunchingWithOptions:)。


    2、NSURLProtocol是NSURLConnection的handler。NSURLConnection的每个请求都会去便利所有的Protocols,并询问你能处理这个请求么(canInitWithRequest: )。如果这个Protocol返回YES,则第一个返回YES的Protocol会来处理这个connection。Protocols的遍历是反向的,也就是最后注册的Protocol会被优先判断。


    3、 当你的handler被选中了,connection就会调用–> initWithRequest:cachedResponse:client:,紧接着会调用–>startLoading。然后你需要负责回调:–>URLProtocol:didReceiveResponse:cacheStoragePolicy:,有些则会调用:–>URLProtocol:didLoadData:, 并且最终会调用–>URLProtocolDidFinishLoading:。你有没有发现这些方法和NSURLConnection delegate的方法非常类似——这绝非偶然!


    4、当online的情况下,RNCachingURLProtocol只是负责将请求转发给一个新的NSURLConnection,并且拷贝一份结果给原来的connection。offline时, RNCachingURLProtocol就会从磁盘里载入先前的结果,并将这些数据发回给连接。整个过程只有区区200行代码(不包含Reachability)。


    5、这里还有一个有趣的问题,就是当RNCachingURLProtocol创建了一个新的NSURLConnection的,即新的connection也会去找一个handler。 如果RNCachingURLProtocol说可以处理,那么就死循环了。怎么解决呢?通过添加自定义HTTP Header(X-RNCache)来标记这个请求,告诉RNCachingURLProtocol不要再处理这个请求。


    6、它可以响应所有的connection,所以你可能需要修改canInitWithRequest:来 选择你要缓存的数据。

     

    另外:并发请求或复杂网络请求的缓存请使用MKNetworkKit(我们也在一个项目中使用了这个类库,非常轻量快捷是ASI的很不错的替代品)。

    1
  • 相关阅读:
    ionic2项目中实现md5加密
    ionic2中使用极光IM的WebSDK实现即时聊天
    react-native清除android项目缓存的命令
    在react-native项目中使用iconfont自定义图标库
    ionic2中使用videogular2实现m3u8文件播放
    vue-video-player集成videojs-contrib-hls实现.m3u8文件播放
    react组件生命周期
    在vue2中隐藏elementUI的tab栏
    Spark2.1.0——Spark初体验
    Spark2.1.0——运行环境准备
  • 原文地址:https://www.cnblogs.com/fantasy3588/p/5448223.html
Copyright © 2020-2023  润新知