由于H5的灵活多变,动态可配的特点,也为了避免冗长 的审核周期,H5页面在app上的重要性正日益突显。

iOS应用于H5交互的控件主要是UIWebView及WKWebView

WKWebView是14年随iOS8推出的,很好的解决了UIWebView加载速度慢,内存占用大的问题

WebViewJavaScriptBridge是一款轻量级的框架,使用它结合wkwebview能十分方便的实现源生与H5的交互

  webviewJavaScrptBridge的基本使用

  1.初始化需bind视图  [WebViewJavaScriptBridge bridgeForWebView:]

  2.设置代理  [self.bridge setWebViewDelegate:self]

  3.注册方法  

  [self.bridge registerHandler:@"click" handler:^(id data, WVJBResponseCallback responseCallback) {

NSDictionary *dic = (NSDictionary *)data;

[weakSelf responseJSWithData:(NSDictionary *)dic];

 }];

  click是方法名,handler是H5发起调用后传回的回调,该闭包第一个H5页面传递过来的参数,第二个是callBack对象

  4.调用方法  

  [self.bridge callHandler:event data:data responseCallback:^(id responseData) {

NSLog(@"responseData:%@",responseData);

}];

  event是方法名,源生直接发起回调,data是传递的参数,callBack是h5收到事件后传回的回调

  webviewJavaScriptBridge的精髓就是方法3,4的交替使用,使得源生调h5,h5调源生变的异常简单,两者之间的链接仅仅靠一个方法名,收方register后,发起方callHandler就能实现一条消息的有效传递,具体实现细节可细究其源码  webviewJavaScriptBridge

  现在来探究下H5端如何使用bridge注册及发起事件

  1. /// 配置bridge
  2. function setupWebViewJavascriptBridge(callback) {
  3. if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
  4. if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
  5. window.WVJBCallbacks = [callback];
  6. var WVJBIframe = document.createElement('iframe');
  7. WVJBIframe.style.display = 'none';
  8. WVJBIframe.src = 'https://__bridge_loaded__';
  9. document.documentElement.appendChild(WVJBIframe);
  10. setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
  11. }
  12.  
  13. /// callHandler data为H5传递参数
  14. setupWebViewJavascriptBridge(function (bridge) {
  15. let data = {'title': title}
  16. bridge.callHandler('setTitle', data)
  17. })
  18.  
  19. /// registerHandler data为源生传递参数
  20. bridge.registerHandler("result", function (data, responseCallback) {
  21. result(data['opType'], data['code'], data['msg'])
  22. })

  可见在H5端使用bridge完成消息的收发页十分方便。webviewJavaScriptCoreBridge的配置,是在H5页面生成一个iframe节点,传递消息时插入这个节点,结束后移除这个节点,以此来实现源生到H5的一次消息传递。

WKNavigationDelegate  使用wkwebview进行一次网络请求中的各种事件回调

WKUIDelegate   主要用于处理H5中的alert弹窗事件

  -runJavaScriptAlertPanelWithMessage:

UIWebView,尽管该视图已经被WKWebview取代,但市面上大多数应用框架仍然使用的是webview,并且其更接近底层,具有深究价值

UIWebview通常是通过拦截request,根据指定url中的参数,来实现H5端事件的调用

  1. func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool
  2. {
  3. let absoluteString = request.url!.absoluteString
  4. if (!absoluteString.contain(prefix)) {
  5. return true
  6. }else {
                  // do something
  7. return false
  8. }
  9. }

返回false则拦截请求,截取url中所带参数,根据需求做相应处理。通常为封装方法间的调用,会插入一段js代码。

  1. override func webViewDidStartLoad(_ webView: UIWebView) {
  2. super.webViewDidStartLoad(webView)
  3.  
  4. /// 尽可能在较早的时间点插入该js代码
  5. writtenJSApi(webView: webView)
  6. }
  7.  
  8. func writtenJSApi(webView:UIWebView) {
  9. if let filePath:String = Bundle.main.path(forResource: "jsapi", ofType: "js"){
  10. if let jsStr = try? NSString(contentsOfFile: filePath, encoding: String.Encoding.utf8.rawValue){
  11. webView.stringByEvaluatingJavaScript(from: jsStr as String)
  12. }
  13. }
  14. }

js主要代码

  1. // 异步
  2. window.JSApi.asyncInvoke = function (apiname, pramaJsonString, callbackapi)
  3. {
  4. var apiPath = "https://asyncjsapi.com/" + encodeURIComponent(apiname + window.JSApi.pramaSplit + pramaJsonString + window.JSApi.pramaSplit + callbackapi);
  5. var iframe = document.createElement("iframe");
  6. iframe.setAttribute("src", apiPath);
  7. document.documentElement.appendChild(iframe);
  8. iframe.parentNode.removeChild(iframe);
  9. iframe = null;
  10. }
  11.  
  12. // 同步
  13. window.JSApi.syncInvoke = function (apiname, pramaJsonString)
  14. {
  15. var apiPath = "https://syncjsapi.com/" + encodeURIComponent(apiname + window.JSApi.pramaSplit + pramaJsonString );
  16. var request = new XMLHttpRequest();
  17. if (request == null)
  18. {
  19. return {
  20. code: 1,
  21. errorMsg: "not support XMLHttpRequest",
  22. data: null
  23. };
  24. }
  25.  
  26. var responseText = ""
  27.  
  28. request.onreadystatechange = function ()
  29. {
  30. // alert("stateChange"+request.readyState+","+request.status)
  31. if (request.readyState == 4 && request.status == 200)
  32. {
  33. responseText = request.responseText;
  34. }
  35. else
  36. {
  37. responseText = ""
  38. }
  39. // alert(responseText)
  40. };
  41. // alert(apiname+" 2 request open "+apiPath);
  42. request.open("GET", apiPath, false);
  43. request.send(null);
  44.  
  45. console.log(responseText)
  46.  
  47. return responseText
  48. }
  49. })();

可以看出,异步方法依然是在页面创建iframe,先插入后删除的方式;同步方法是利用ajax,创建了一个http请求,并监听request的状态,当status为200时,返回信息给H5。同步方法的拦截是在urlProtocol里面

  1. class JsApiURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {
  2.  
  3. override class func canInit(with request: URLRequest) -> Bool {
  4.  
  5. if let strUrl:String = request.url?.absoluteString
  6. {
  7. if JsApiHelper.isSyncNativeApi(urlString: strUrl) {
  8. return true
  9. }
  10. }else {
  11. return false
  12. }
  13.  
  14. }
  15.  
  16. override func startLoading() {
  17. let strUrl:String! = request.url!.absoluteString
  18. if JsApiHelper.isSyncNativeApi(urlString: strUrl) {
  19. // 调用同步jsapi
  20. let result: NSString = JsApiHelper.syncInvoke(urlString: strUrl! as NSString) as NSString
  21. let resultData: NSData = result.data(using: String.Encoding.utf8.rawValue)! as NSData
  22. var headerFields: [NSObject : AnyObject]? = [NSObject : AnyObject]()
  23. headerFields?.updateValue("*" as AnyObject, forKey: "Access-Control-Allow-Origin" as NSObject)
  24.  
  25. let response: HTTPURLResponse = HTTPURLResponse(url: self.request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headerFields as? [String:String])!
  26. self.client!.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
  27. self.client!.urlProtocol(self, didLoad: resultData as Data)
  28. self.client!.urlProtocolDidFinishLoading(self)
  29. }
  30. }
  31.  
  32. }

caninit方法中return true表示进行请求,否则拦截请求。startLoading方法中创建相应的response返回给js中的request,注意finishLoading,否则容易造成死循环。

UIWebview调用H5就相当简单了,一句代码搞定

  webView.stringByEvaluatingJavaScript(from: "javascript:window.goBack()");

webview和H5交互的更多相关文章

  1. Webview 与h5的交互

    步骤:H5代码   <html>   <head>   <meta charset="UTF-8">   <title>交互Demo ...

  2. Android中WebView与H5的交互,Native与JS方法互调

    项目中经常用到WebView与H5的交互,一个是H5调本地方法,一个是本地调H5方法,在此记录一下. 首先,启用JS支持 //启用js支持 webSettings.setJavaScriptEnabl ...

  3. Android WebView 基本设置与H5 交互

    mWebView.setDrawingCacheEnabled(true); WebChromeClient webChromeClient = new WebChromeClient(); mWeb ...

  4. 客户端相关知识学习(十一)之Android H5交互Webview实现localStorage数据存储

    前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebVie ...

  5. Android混合开发之WebView与Javascript交互

    前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...

  6. Native与H5交互的一些解决方法

    一. 原生代码中直接加载页面 1.    具体案例 加载本地/网络HTML5作为功能介绍页 2.    代码示例 //本地 -(void)loadLocalPage:(UIWebView*)webVi ...

  7. iOS JavaScriptCore与H5交互时出现异常提示

    在利用JavaScriptCore与H5交互时出现异常提示: This application is modifying the autolayout engine from a background ...

  8. Android与H5交互(java与js的交互)

    一.理论概述 1.js调用java方法 直接调用WebView的该方法就可以添加接口了,不过先要启动交互 // 启用javascript mWebView.getSettings().setJavaS ...

  9. android:如何通过chrome远程调试APP中的webView的h5代码

    今天出现一个问题,在老板的Mate9 Pro上,我们APP的所有H5页面都是一片空白,但是在其他手机上都是好的,那么我们就怀疑是h5报错了,但是到底是什么错,无法得知,所以就想要可以像在pc的chro ...

随机推荐

  1. Module not found: Error: Can't resolve 'less-loader' in ' xxx' (Day_40)

    1. 错误代码: 2. 解决方法: 删除项目文件夹下的node_modules文件夹 执行npm install命令

  2. MyBatis的Example如何按条件排序(Day_35)

    MyBatis的Example如何按条件进行排序? 背景:有时我们在使用mybatis example 进行查询时,需要进行相应的业务排序.本博客以下图为例 @Override public List ...

  3. CSS定位特性

    CSS属性书写顺序 布局定位属性:display / position / float / clear / visibility / overflow 自身属性:width / height / ma ...

  4. 201871030136-颜静 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    ​ 项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST/ 这个作业要求链接 https://www.cnblogs.com/nwnu- ...

  5. CVPR2020:利用图像投票增强点云中的三维目标检测(ImVoteNet)

    CVPR2020:利用图像投票增强点云中的三维目标检测(ImVoteNet) ImVoteNet: Boosting 3D Object Detection in Point Clouds With ...

  6. 与现代传感器的接口:轮询ADC驱动程序

    与现代传感器的接口:轮询ADC驱动程序 Interfacing with modern sensors: Polled ADC drivers 我们研究了在现代嵌入式应用程序中,开发人员应该如何创建一 ...

  7. 『言善信』Fiddler工具 — 8、Fiddler检查器(Inspectors)详解

    目录 1.请求报文内容 2.响应报文内容 3.响应报文中Transformer选项说明 Inspectors意思是检查器.Inspectors可以使用多种方式,查看请求的请求报文和响应报文相关信息. ...

  8. [源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架

    [源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架 目录 [源码解析] 深度学习分布式训练框架 horovod (5) --- 融合框架 0x00 摘要 0x01 架构图 ...

  9. 如何开启O2优化

    O2环境会使你的程序跑的特别快,然而大多数正式考试都不能开O2 然而平时做有些题强制开O2,会出现在本机运行正确,但是交上去RE的情况,这时你就要开O2了. 例如在本机运行时会有下标为-但可以运行,而 ...

  10. 浅谈.Net Core中使用Autofac替换自带的DI容器

    为什么叫 浅谈 呢?就是字面上的意思,讲得比较浅,又不是不能用(这样是不对的)!!! Aufofac大家都不陌生了,说是.Net生态下最优秀的IOC框架那是一点都过分.用的人多了,使用教程也十分丰富, ...