zoukankan      html  css  js  c++  java
  • Customizing UIWebView requests with NSURLProtocol

    Whether you are creating your own web browser on iOS or just displaying some custom, locally generated HTML,UIWebView can become a source of lots of frustration, mostly related to its (perceived) lack of basic customization options.

    Today, we are going to open the pandora’s box and dive into theFoundation’s URL Loading System to customize every requestUIWebView sends.

    UIWebView uses the NSURLConnection class for every request (actually, the NSURLConnection class was originally written for the first release of Safari, that’s why they are so tied together). And every NSURLConnection request is intercepted and treated accordingly either by the cache or other custom protocol handlers. By creating a custom protocol handler (using NSURLProtocol), we can intercept, match and customize every request sent by UIWebView.

    For today’s example, let’s say that we want our UIWebView on iOS to be seen as a Chrome Desktop browser running on Windows. According toUserAgentString.com the current Chrome user agent is:

    Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.2 Safari/537.36

    So let’s start by creating a subclass of NSURLProtocol:

    #import <Foundation/Foundation.h>
     
    @interface ChromeBrowserURLProtocol : NSURLProtocol
     
    @end
     
    @interface ChromeBrowserURLProtocol ()
    @property (nonatomic, strong) NSURLConnection *connection;
     
    @end
     
    @implementation ChromeBrowserURLProtocol
     
    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
       if ([NSURLProtocol propertyForKey:@“UserAgentSet” inRequest:request] != nil)
          return NO;
     
       return YES;
    }

    Whenever the URL Loading system receives a new request, it queries every available protocol handler to determine who can handle that request. Here we use a helper method from NSURLProtocol, called+propertyForKey:inRequest:. This method queries for a custom property that can be applied on any NSMutableURLRequest. On our example, we look for “UserAgentSet”. If the user agent has been set, pass this along. Otherwise, let’s deal with this.

    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
    {
       return request;
    }
     
    - (void)startLoading
    {
       NSMutableURLRequest *newRequest = [self.request mutableCopy];
     
       // Here we set the User Agent
       [newRequest setValue:@"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.2 Safari/537.36 Kifi/1.0f" forHTTPHeaderField:@"User-Agent"];
     
       [NSURLProtocol setProperty:@YES forKey:@"UserAgentSet" inRequest:newRequest];
     
       self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
    }

    On -startLoading, we create a mutableCopy of our request and change the User Agent. We must set the “UserAgentSet” property here with +setProperty:forKey:inRequest:, so we know to pass this request along in the future. After that, we just initiate a new NSURLConnection with the request.

    - (void)stopLoading
    {
       [self.connection cancel];
    }
     
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
       [self.client URLProtocol:self didLoadData:data];
    }
     
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
       [self.client URLProtocol:self didFailWithError:error];
       self.connection = nil;
    }
     
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
       [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
    }
     
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
       [self.client URLProtocolDidFinishLoading:self];
       self.connection = nil;
    }
     
    @end

    These are the delegates for the NSURLConnection class, and we must pass them along to our inner client object, contained inside NSURLProtocol.

    Then, we must register this protocol on you App Delegate’s -(BOOL)application:didFinishLaunchingWithOptions:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [NSURLProtocol registerClass:[ChromeBrowserURLProtocol class]];
    ...

    And that’s it!

    Of course this only scratches the surface on what can be done with NSURLProtocol. You can create your own caching mechanism, track redirects (with -connection:willSendRequest:redirectResponse:response:), sign requests, mock HTTP responses for testing and a lot more.

    转自:http://eng.kifi.com/customizing-uiwebview-requests-with-nsurlprotocol/

  • 相关阅读:
    关于自己主动化部署
    浅析概率中的频率学派观点和贝叶斯学派观点
    使用javascript实现浏览器全屏
    扩展BootstrapTable的treegrid功能
    jQuery Validate验证框架详解
    将数据库返回的ResultSett转换成List装Map形式的方法(ResultSetToList)
    在maven项目结构下对于Resources目录下文件的存取
    原生sql的各种问题
    nutz 自定义sql的使用
    (转)微服务架构 互联网保险O2O平台微服务架构设计
  • 原文地址:https://www.cnblogs.com/mumoozhu/p/4595671.html
Copyright © 2011-2022 走看看