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()");
webview和H5交互的更多相关文章
- Webview 与h5的交互
步骤:H5代码 <html> <head> <meta charset="UTF-8"> <title>交互Demo ...
- Android中WebView与H5的交互,Native与JS方法互调
项目中经常用到WebView与H5的交互,一个是H5调本地方法,一个是本地调H5方法,在此记录一下. 首先,启用JS支持 //启用js支持 webSettings.setJavaScriptEnabl ...
- Android WebView 基本设置与H5 交互
mWebView.setDrawingCacheEnabled(true); WebChromeClient webChromeClient = new WebChromeClient(); mWeb ...
- 客户端相关知识学习(十一)之Android H5交互Webview实现localStorage数据存储
前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebVie ...
- Android混合开发之WebView与Javascript交互
前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...
- Native与H5交互的一些解决方法
一. 原生代码中直接加载页面 1. 具体案例 加载本地/网络HTML5作为功能介绍页 2. 代码示例 //本地 -(void)loadLocalPage:(UIWebView*)webVi ...
- iOS JavaScriptCore与H5交互时出现异常提示
在利用JavaScriptCore与H5交互时出现异常提示: This application is modifying the autolayout engine from a background ...
- Android与H5交互(java与js的交互)
一.理论概述 1.js调用java方法 直接调用WebView的该方法就可以添加接口了,不过先要启动交互 // 启用javascript mWebView.getSettings().setJavaS ...
- android:如何通过chrome远程调试APP中的webView的h5代码
今天出现一个问题,在老板的Mate9 Pro上,我们APP的所有H5页面都是一片空白,但是在其他手机上都是好的,那么我们就怀疑是h5报错了,但是到底是什么错,无法得知,所以就想要可以像在pc的chro ...
随机推荐
- 【JDK命令行 一】手动编译Java源码与执行字节码命令合集(含外部依赖引用)
写作目标 记录常见的使用javac手动编译Java源码和java手动执行字节码的命令,一方面用于应对 Maven 和 Gradle 暂时无法使用的情况,临时生成class文件(使用自己的jar包):另 ...
- CSS的引入方式和复合选择器
CSS的引入方式 样式表 优点 缺点 范围 行内样式表 书写方便 结构样式混写 控制一个标签 内部样式表 部分结构和样式相分离 没有彻底 控制一个页面 外部样式表 完全实现结构和样式分离 需要引入 控 ...
- fragment textWatcher的设置位置
override fun onStart() { super.onStart() Log.d("------------", "1") val titleWat ...
- openresty 学习笔记三:连接redis和进行相关操作
openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...
- Fiddler抓包后转成jmeter脚本
Fiddler的安装及使用 1.安装:无特别需要注意事项 2.使用: (1)目前我使用的是Fiddler 4版本,打开页面如下 (2)如下图,在界面右侧找到Filters tabs,根据需要进行设置, ...
- .Net Core Api发布时报502.5 [The Application process failed to Start]问题的解决原因
碰到这样的错误,在网上找了很久很久.我自己在部署的时候已经把Core 部署需要的环境包在服务器安装好了.还会报这个错,然后在网上找的安装了一个系统补丁包!安装之后还是不行.最后我把服务器重启了一 ...
- 3D点云几何拟合
3D点云几何拟合 Supervised Fitting of Geometric Primitives to 3D Point Clouds 论文地址: http://openaccess.thecv ...
- GPU编程和流式多处理器(四)
GPU编程和流式多处理器(四) 3.2. 单精度(32位) 单精度浮点支持是GPU计算的主力军.GPU已经过优化,可以在此数据类型上原生提供高性能,不仅适用于核心标准IEEE操作(例如加法和乘法),还 ...
- ADAS系统长篇综述(下)
ADAS系统长篇综述(下) 四.ADAS架构设计的进化阶梯 前面谈到的产品的商业化推广渗透和产品的功能演进渗透,目的是让大家去概念化.当然,最后的赢家一定是实干者,能够在具体技术实现路径上进行深度耕耘 ...
- 嵌入式Linux的OTA更新,基础知识和实现
嵌入式Linux的OTA更新,第1部分-基础知识和实现 OTA updates for Embedded Linux, Fundamentals and implementation 更新的需要 一 ...