iOS 中 WebView、网络操作相关及键盘相关的几个关键类

WebView、网络操作相关及键盘相关的几个关键类

  • UIWebview的本地调用

    • 注入js:[webview stringByEvaluatingJavaScriptFromString:]
    • 本地调用,使用WebViewJavascriptBridge:- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler
  • WKWebView的本地调用

    • 注入js:[wkwebview evaluateJavaScript:]
    • 首先通过WKUserContentController -> addScriptMessageHandler: 以及 addUserScript: ,实现WKScriptMessageHandler响应脚本消息:- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 和 js的注入;
    • WKNavigationDelegate:跟踪网页加载进度,以及决定采取什么的处理策略;
    • WKUIDelegate:根据网页的行为展示本地的UI视图;
  • 自定义NSURLProtocol

    • NSURLProtocol能够让你去重新定义苹果的URL加载系统 (URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等,当URL Loading System使用NSURLRequest去获取资源的时候,它会创建一个NSURLProtocol子类的实例,你不应该直接实例化一个NSURLProtocol,NSURLProtocol看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。
    • 不管你是通过UIWebView, NSURLConnection 或者第三方库 (AFNetworking, MKNetworkKit等),他们都是基于NSURLConnection或者 NSURLSession实现的,因此你可以通过NSURLProtocol做自定义的操作。

      • 重定向网络请求
      • 忽略网络请求,使用本地缓存
      • 自定义网络请求的返回结果
      • 一些全局的网络请求设置
    • 子类化NSURLProtocol并注册

        //子类化
        @interface CustomURLProtocol : NSURLProtocol
        @end
      
        //注册
        - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
            //注册protocol
            [NSURLProtocol registerClass:[CustomURLProtocol class]];
            return YES;
        }
      
    • 实现Custom URLProtocol

      • +canInitWithRequest:这个方法主要是说明你是否打算处理对应的request,如果不打算处理,返回NO,URL Loading System会使用系统默认的行为去处理;如果打算处理,返回YES,然后你就需要处理该请求的所有东西,包括获取请求数据并返回给 URL Loading System。

          + (BOOL)canInitWithRequest:(NSURLRequest *)request
          {
            //只处理http和https请求
              NSString *scheme = [[request URL] scheme];
              if ( ([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
               [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame))
              {
                  //看看是否已经处理过了,防止无限循环
                  if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
                      return NO;
                  }
        
                  return YES;
              }
              return NO;
          }
        
    • +canonicalRequestForRequest:通常该方法你可以简单的直接返回request,但也可以在这里修改request,比如添加header,修改host等,并返回一个新的request,这是一个抽象方法,子类必须实现。

        + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
            NSMutableURLRequest *mutableReqeust = [request mutableCopy];
            mutableReqeust = [self redirectHostInRequset:mutableReqeust];
            return mutableReqeust;
        }
      
        +(NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request
        {
            if ([request.URL host].length == 0) {
                return request;
            }
      
            NSString *originUrlString = [request.URL absoluteString];
            NSString *originHostString = [request.URL host];
            NSRange hostRange = [originUrlString rangeOfString:originHostString];
            if (hostRange.location == NSNotFound) {
                return request;
            }
            //定向到bing搜索主页
            NSString *ip = @"cn.bing.com";
      
            // 替换域名
            NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
            NSURL *url = [NSURL URLWithString:urlString];
            request.URL = url;
      
            return request;
        }
      
    • +requestIsCacheEquivalent:toRequest:主要判断两个request是否相同,如果相同的话可以使用缓存数据,通常只需要调用父类的实现。

        + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b{
            return [super requestIsCacheEquivalent:a toRequest:b];
        }
      
    • -startLoading -stopLoading : 这两个方法主要是开始和取消相应的request,而且需要标示那些已经处理过的request。

        - (void)startLoading {
            NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
            //标示改request已经处理过了,防止无限循环
            [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
            self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
        }
      
        - (void)stopLoading {
            [self.connection cancel];
        }
      
    • NSURLConnectionDataDelegate方法,在处理网络请求的时候会调用到该代理方法,我们需要将收到的消息通过client返回给URL Loading System。

        - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
            [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        }
      
        - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
            [self.client URLProtocol:self didLoadData:data];
        }
      
        - (void) connectionDidFinishLoading:(NSURLConnection *)connection {
            [self.client URLProtocolDidFinishLoading:self];
        }
      
        - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
            [self.client URLProtocol:self didFailWithError:error];
        }
      
  • 自定义键盘 UITextInputDelegate 方法定义

      - (void)selectionWillChange:(nullable id <UITextInput>)textInput;
      - (void)selectionDidChange:(nullable id <UITextInput>)textInput;
      - (void)textWillChange:(nullable id <UITextInput>)textInput;
      - (void)textDidChange:(nullable id <UITextInput>)textInput;
    
  • 自定义键盘UIInputViewController的textDocumentProxy定义

      @protocol UITextDocumentProxy <UIKeyInput>
    
      @property (nullable, nonatomic, readonly) NSString *documentContextBeforeInput;
      @property (nullable, nonatomic, readonly) NSString *documentContextAfterInput;
    
      // An app can store UITextInputMode in its document context, when user switches to the document, the host will pass the inputMode as documentInputMode to the UIInputViewController,
      // which can switch to the inputMode and set primaryLanguage if it supports it.
      @property (nullable, nonatomic, readonly) UITextInputMode *documentInputMode NS_AVAILABLE_IOS(10_0);
    
      - (void)adjustTextPositionByCharacterOffset:(NSInteger)offset;
    
      @end
    
      //-----------------
    
      @protocol UIKeyInput <UITextInputTraits>
    
      #if UIKIT_DEFINE_AS_PROPERTIES
      @property(nonatomic, readonly) BOOL hasText;
      #else
      - (BOOL)hasText;
      #endif
      - (void)insertText:(NSString *)text;
      - (void)deleteBackward;
    
      @end
    

参考以上: iOS开发之--- NSURLProtocol

{{ message }}

{{ 'Comments are closed.' | trans }}