iOS基础补完计划--前端交互I--协议拦截

iOS基础补完计划--前端交互I--协议拦截_第1张图片
寻找遗失的未来 (11).jpg

从时间线来看、分为三个阶段。

  • 协议拦截

  • JavaScriptCore(iOS 7.0)

  • WKWebView(iOS 8.0)

本文主要针对协议拦截进行探究


协议拦截

  • 最原始的交互方式。
  • 所有的操作都针对webView。(拦截代理、让webView执行js语句)。
  • js调用oc:通过webView代理方法、拦截网页的重定向请求。判断是否需要调用oc方法。
  • oc调用js:通过webView直接执行js语句的方法、直接调用js方法(等于在浏览器控制台中直接执行js语句)。
  • 既然是拦截网页发起的url定向。为了更标准的约定接口、我们有必要认识一下NSURL。

  NSURL * baseUrl = [NSURL URLWithString:@"myhttps://kirito:123:[email protected]:8080"];
  NSURL * url = [NSURL URLWithString:@"pathstr1?query1=1&query2=2&user=123#asd" relativeToURL:baseUrl];
  
  NSLog(@"absoluteURL--%@",url.absoluteURL);//绝对NSurl
  NSLog(@"absoluteString--%@",url.absoluteString);//绝对url字符串
  NSLog(@"scheme--%@",url.scheme);//协议
  NSLog(@"user--%@",url.user);//用户名
  NSLog(@"password--%@",url.password);//密码
  NSLog(@"baseUrl--%@",url.baseURL);//根目录、只有在通过跟目录生成的url中才会体现
  NSLog(@"resourceSpecifier--%@",url.resourceSpecifier);//资源说明符
  NSLog(@"relativeString--%@",url.relativeString);//相对路径(带参数)、如果没有baseUrl。则全部显示
  NSLog(@"relativePath--%@",url.relativePath);//相对路径、不带参数
  NSLog(@"host--%@",url.host);//主机域名
  NSLog(@"port--%@",url.port);//端口
  NSLog(@"query--%@",url.query);//参数
  NSLog(@"fragment--%@",url.fragment);//锚点、可以在网站打开时候直接移动至此

打印结果:

  absoluteURL--myhttps://kirito:123:[email protected]:8080/pathstr1?query1=1&query2=2&user=123#asd
  absoluteString--myhttps://kirito:123:[email protected]:8080/pathstr1?query1=1&query2=2&user=123#asd
  scheme--myhttps
  user--kirito
  password--123:123456
  baseUrl--myhttps://kirito:123:[email protected]:8080
  resourceSpecifier--pathstr1?query1=1&query2=2&user=123#asd
  relativeString--pathstr1?query1=1&query2=2&user=123#asd
  relativePath--pathstr1
  host--www.baidu.com
  port--8080
  query--query1=1&query2=2&user=123
  fragment--asd

现在我们已经知道一个URL中各部分的作用以及如何获取。
那么、一个正规的至少我们需要三点(WebViewJavascriptBridge也是如此设计、有时间我再把jsBridge的原理总结一下)。

  • scheme:区分正常的https请求。进入下一步判断。
  • host:希望调用我们的方法。
  • query:需要传递的参数。
  • 注意这里的host在真正的后台服务器中并不代表方法、别出去胡侃的时候被人笑话......
    如此、我们可以将一个url简化成:(当然你也可以随意约定成任何格式、只要你有办法截取出相应的参数。)
   AppScheme://showAlert?提示&这是一个js发起的方法&ok
  • js调用OC:

只需要正常一个url定向。
  弹窗

OC中的操作:
在webView代理中拦截并解析url、根据需要不同情况调用不同方法并传入相应参数。

  - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
      NSURL * url = [request URL];
      NSString * scheme = [url scheme];
    
      //比对scheme是否是需要app进行处理
      if ([scheme isEqualToString:@"appscheme"]) {
      //获得方法名
      NSString * host = [url host];
      NSString * queryStr = [[url query] stringByRemovingPercentEncoding];
      //获得参数
      NSArray * queryArr = [queryStr componentsSeparatedByString:@"&"];
  
      if ([host isEqualToString:@"shouAlert"]) {
          //你也可以做个防止越界的容错
          [self showAlertWithTitle:queryArr[0] message:queryArr[1] cancelBtnTitle:queryArr[2]];
      }
  
      return NO;
      }
      return YES;
  }
  
  - (void)showAlertWithTitle:(NSString *)title message:(NSString *)message cancelBtnTitle:(NSString *)cancelBtnTitle {
      UIAlertController * alert = [[UIAlertController alloc]init];
      alert.title = title;
      alert.message = message;
      UIAlertAction * action = [UIAlertAction actionWithTitle:cancelBtnTitle style:UIAlertActionStyleDefault handler:nil];
      [alert addAction:action];
      [self presentViewController:alert animated:YES completion:nil];
  }

效果:


iOS基础补完计划--前端交互I--协议拦截_第2张图片
屏幕快照 2017-12-14 下午4.24.07.png
  • oc调用js:

先在js中约定一个js方法备用
  
oc中极为简单

webView为我们提供了一个方法

- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

这个方法就相当于在浏览器的console中直接输入一段js代码。


iOS基础补完计划--前端交互I--协议拦截_第3张图片
屏幕快照 2017-12-14 下午4.58.23.png

放到OC中去执行的话:

  - (void)btnClick {
      [self.webView stringByEvaluatingJavaScriptFromString:@"showPrompt('123','321')"];
  }
iOS基础补完计划--前端交互I--协议拦截_第4张图片
屏幕快照 2017-12-14 下午4.59.28.png

我们甚至可以完全不借助js文件、干脆自己写一段js扔进去执行。

  function showPrompt(msg,placeholder) {
      prompt(msg,placeholder);
  }
  
  showPrompt('123','321');

去掉换行

 function showPrompt(msg,placeholder) { prompt(msg,placeholder); } showPrompt('123','321');

放到btn的点击事件中(记得去掉原js中的方法):

  - (void)btnClick {
      [self.webView stringByEvaluatingJavaScriptFromString:@"function showPrompt(msg,placeholder) { prompt(msg,placeholder); } showPrompt('123','321');"];
  }
iOS基础补完计划--前端交互I--协议拦截_第5张图片
屏幕快照 2017-12-14 下午5.05.09.png
效果没有丝毫的变化、可见stringByEvaluatingJavaScriptFromString方法本质上就是暴露给iOS的webView控制台。

WebViewJavascriptBridge

WebViewJavascriptBridge实际上也是拦截协议进行交互。但是他将自身作为一个‘桥’、两端只要向桥对象注册/调用方法。就可以进行交互了。那么、这个桥是如何建立的、其原到底理如何呢?
仔细研究了一下发现字蛮多。所以单开了一贴。
《传送门》

你可能感兴趣的:(iOS基础补完计划--前端交互I--协议拦截)