webview和H5交互

由于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注册及发起事件

/// 配置bridge
function setupWebViewJavascriptBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement(‘iframe‘);
        WVJBIframe.style.display = ‘none‘;
        WVJBIframe.src = ‘https://__bridge_loaded__‘;
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }

/// callHandler    data为H5传递参数
setupWebViewJavascriptBridge(function (bridge) {
            let data = {‘title‘: title}
            bridge.callHandler(‘setTitle‘, data)
        })

/// registerHandler    data为源生传递参数
bridge.registerHandler("result", function (data, responseCallback) {
            result(data[‘opType‘], data[‘code‘], data[‘msg‘])
        })

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

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

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

  -runJavaScriptAlertPanelWithMessage:

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

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

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool
    {
        let  absoluteString = request.url!.absoluteString
		if (!absoluteString.contain(prefix)) {
			return true
		}else {              // do something
			return false
		}
    }

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

override func webViewDidStartLoad(_ webView: UIWebView) {
        super.webViewDidStartLoad(webView)

        /// 尽可能在较早的时间点插入该js代码
        writtenJSApi(webView: webView)
    }

func writtenJSApi(webView:UIWebView) {
        if  let filePath:String = Bundle.main.path(forResource: "jsapi", ofType: "js"){
            if let jsStr = try? NSString(contentsOfFile: filePath, encoding: String.Encoding.utf8.rawValue){
                webView.stringByEvaluatingJavaScript(from: jsStr as String)
            }
        }
    }

js主要代码

// 异步
 window.JSApi.asyncInvoke = function (apiname, pramaJsonString, callbackapi)
 {
 var apiPath = "https://asyncjsapi.com/" + encodeURIComponent(apiname + window.JSApi.pramaSplit + pramaJsonString + window.JSApi.pramaSplit + callbackapi);
 var iframe = document.createElement("iframe");
 iframe.setAttribute("src", apiPath);
 document.documentElement.appendChild(iframe);
 iframe.parentNode.removeChild(iframe);
 iframe = null;
 }

 // 同步
 window.JSApi.syncInvoke = function (apiname, pramaJsonString)
 {
 var apiPath = "https://syncjsapi.com/" + encodeURIComponent(apiname + window.JSApi.pramaSplit + pramaJsonString );
 var request = new XMLHttpRequest();
 if (request == null)
 {
 return {
 code: 1,
 errorMsg: "not support XMLHttpRequest",
 data: null
 };
 }

 var responseText = ""

 request.onreadystatechange = function ()
 {
 // alert("stateChange"+request.readyState+","+request.status)
 if (request.readyState == 4 && request.status == 200)
 {
 responseText = request.responseText;
 }
 else
 {
 responseText = ""
 }
 // alert(responseText)
 };
 // alert(apiname+"  2  request open    "+apiPath);
 request.open("GET", apiPath, false);
 request.send(null);

 console.log(responseText)

 return responseText
 }
 })();

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

class JsApiURLProtocol: URLProtocol, URLSessionDataDelegate, URLSessionTaskDelegate {

	override class func canInit(with request: URLRequest) -> Bool {

		if let strUrl:String = request.url?.absoluteString
        {
            if JsApiHelper.isSyncNativeApi(urlString: strUrl) {
                return true
            }
        }else {
        	return false
        }

	}

	override func startLoading() {
        let strUrl:String! = request.url!.absoluteString
        if JsApiHelper.isSyncNativeApi(urlString: strUrl) {
            // 调用同步jsapi
            let result: NSString = JsApiHelper.syncInvoke(urlString: strUrl! as NSString) as NSString
            let resultData: NSData = result.data(using: String.Encoding.utf8.rawValue)! as NSData
            var headerFields: [NSObject : AnyObject]? = [NSObject : AnyObject]()
            headerFields?.updateValue("*" as AnyObject, forKey: "Access-Control-Allow-Origin" as NSObject)

            let response: HTTPURLResponse = HTTPURLResponse(url: self.request.url!, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headerFields as? [String:String])!
            self.client!.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            self.client!.urlProtocol(self, didLoad: resultData as Data)
            self.client!.urlProtocolDidFinishLoading(self)
        }
    }

}

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

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

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

原文地址:https://www.cnblogs.com/xiaoerheiwatu/p/10004409.html

时间: 2024-09-28 06:24:52

webview和H5交互的相关文章

webview与h5交互

android webview与H5的交互 方法无响应 @SuppressLint({ "SetJavaScriptEnabled", "JavascriptInterface" }) protected void onStart() { // TODO Auto-generated method stub super.onStart(); webView = (WebView) findViewById(R.id.webView); String url = ge

Webview 与h5的交互

步骤:H5代码 <html> <head> <meta charset="UTF-8"> <title>交互Demo</title> <meta content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width" name="viewport"> </head> <b

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

前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebView没有开启LocalStorage存储.开启方法如下 首先得有Webview控件: 有人问我是不是需要写布局文件,不写行不行,现在我就告诉你们,不写没问题,需要写就写不写直接创建New一个也行. 下面我就介绍一个,我new一个Webview实现localStorage. WebView mywebV

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

一. 原生代码中直接加载页面 1.    具体案例 加载本地/网络HTML5作为功能介绍页 2.    代码示例 //本地 -(void)loadLocalPage:(UIWebView*)webView { NSString* htmlPath = [[NSBundle mainBundle]pathForResource:@"demo" ofType:@"html"]; NSString* appHtml =[NSString stringWithContent

iOS与H5交互的方案

iOS与H5交互的方案 纵观所有iOS与H5交互的方案,有以下几种: 第一种:有很多的app直接使用在webview的代理中通过拦截的方式与native进行交互,通常是通过拦截url scheme判断是否是我们需要拦截处理的url及其所对应的要处理的功能是什么.任意版本都支持. 第二种:iOS7之后出了JavaScriptCore.framework用于与JS交互,但是不支持iOS6,对于还需要支持iOS6的app,就不能考虑这个了.若需要了解,看最后的推荐阅读. 第三种:WebViewJava

iOS与H5交互

前提:在oc控制器中加载UIWebView,设置代理,遵守UIWebViewDelegate协议. 一.iOS调用JS方法 通过iOS调用JS代码实现起来比较方便直接调用UIWebView的方法- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script; 1.查询标签 // 查询标签      NSString *str = @"var word = document.getElementByI

iOS与H5交互遇到的坑

之前的博客写过使用<JavaScriptCore/JavaScriptCore.h>类来实现与H5的交互,但是在项目中还是遇到了一些不得不踩的坑.在这里将我遇到的问题以及参考网上几位大神的解决方案列举出来,如果有更好的办法,欢迎讨论指正.在阅读本博客前,请参阅我之前的<iOS与H5交互>. 一.在webView中加载H5界面,在此webView中的H5一级界面可以轻松实现oc与js方法互调,但如果在H5界面上进入二级界面,在二级界面中再使用之前方法来交互就会失效.如图:左图为H5一

Android和H5交互-基础篇

hybrid App开发也不是什么新鲜事了,其中native和h5之间的交互则是必不可少的.Android中是如何和H5交互的? 1.webView加载页面 我们都知道在Android中是通过webView来加载html页面的,根据HTML文件所在的位置不同写法也不同: //例如:加载assets文件夹下的test.html页面 mWebView.loadUrl("file:///android_asset/test.html") //例如:加载网页 mWebView.loadUrl(

如何使用AEditor制作一个简单的H5交互页demo

转载自:http://www.alloyteam.com/2015/06/h5-jiao-hu-ye-bian-ji-qi-aeditor-jie-shao/ 本教程演示如何使用AEditor制作一个简单的H5交互页demo: 交互页demo地址: 点击打开H5交互页demo AEditor访问地址: http://aeditor.alloyteam.com Step1:设置页面背景颜色 首先我们设置页面的背景颜色,右击舞台点击“设置背景”: 然后在背景颜色中填上色值rgb(38, 61, 10