IOS、Android与H5通信-JsBridge原理(总结)
H5和原生app(ios,android)交互的载体基本都是基于Webview,可以把Webview看作是一个性能打八折的移动浏览器。
ios调用Javascript
简单说下这几种:WKWebView 、UIWebView、JavaScriptCore
WKWebView:苹果在ios8之后也引入了专门负责处理网页视图的框架WebKit,Webkit是啥,接触过H5、chrome的肯定都知道。chrome使用的也是基于webkit内核的Chromium引擎。WKWebView优点很多,支持更多H5特性,刷新效率及内置手势等,更加强大,性能也更优,不一一列举,如果大家app不需要兼容7及以下版本,不需要拦截一些请求,直接解析本地一些文件,建议使用WKWebView。
UIWebView:较老webview,第一代。其中stringByEvaluatingJavaScriptFromString方法提供了OC与js交互的能力。
JavaScriptCore(ios7及以后版本)。JavaScriptCore框架是webkit重要组成部分,主要是对JS进行解析和提供执行环境,Javascript的虚拟机,有点类似v8引擎,我自己这么理解:)正是它为ios提供了执行JavaScript代码的能力。ReactNative应该都是通过JavaScriptCore去解析的(自己猜测)。
微信小程序的逻辑层也是由JavaScriptCore作为运行环境。
Javascript 调用 ios(oc、swift)原理:
目前兼顾兼容性、比较成熟的方案还是通过拦截URL的方式。
UIWebView的特性,在UIWebView内发起的所有网络请求,都可以在Native层被捕捉到。
利用这一特性,就可以在UIWebView内发起一个自定义的网络请求,一般格式:jsbridge://method?参数1=value1&参数2=value2
于是在UIWebView中,只要发现是jsbridge://开头的url,就不进行内容的加载,而是执行相应的逻辑处理。
嵌入webview的h5中的js一般是通过动态创建隐藏iframe标签,赋值上文提到的链接给src,iframe不会引起页面调转、刷新。
主要代码:
var src= \'jsbridge://method?参数1=value1&参数2=value2\';
var iframe = document.createElement(\'iframe\');
iframe.style.display = \'none\';
iframe.src = src;
document.body.appendChild(iframe);
//再删除
iframesetTimeout(function() {
iframe.remove();
}, 50);
Android和Javascript互相调用
Android WebView也是基于WebKit引擎的一个组件,Android的Webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了Chrome。
这个组件功能非常强大,除了具有一般View的属性和设置外,还可以对url请求、页面加载、渲染、页面交互进行强大的处理。
Android调用JS代码的方法主要有2种:
1、WebView的loadUrl
2、WebView的evaluateJavascript
JS调用Android代码的方法主要有3种:
1、WebView的addJavascriptInterface进行对象映射(低版本Android4以下好像有一些安全问题,本人没有验证)
2、WebViewClient 的 shouldOverrideUrlLoading 方法回调拦截 url
3、WebChromeClient 的onJsAlert、onJsConfirm、onJsPrompt方法回调拦截JS对话框alert()、confirm()、prompt() 消息
一般常用onJsPrompt、prompt进行回调拦截
JSBridge是Native代码与JS代码的通信桥梁
设计一个jsbridge主要分几大步骤:
第一步:设计出一个Native与JS交互的全局中间对象
第二步:JS如何调用Native
第三步:Native如何得知api被调用
第四步:分析url-参数和回调的格式
第五步:Native如何调用JS
第六步:H5中api方法的注册以及格式
结合场景运用:
运用场景描述:在H5端点击页面的发送按钮通知APP打开微信分享功能,交互写在发送事件函数中,调起微信分享功能由app端操作
//给到app的json参数
let jsonData = {
reload: this.$route.query.no_reload ? false : true, //true需要重新加载返回列表页,false不需要(根据需求定)
title: \'上门试驾邀请\', // 分享标题
desc: \'邀请您试驾体验xxxx\', // 分享描述
link: \'https://xxxxx\', // 分享链接
imgUrl: \'\', // 分享图标
}
判断设备
device() { let u = window.navigator.userAgent; //android终端 let isAndroid = u.indexOf(\'Android\') > -1 || u.indexOf(\'Adr\') > -1; //ios终端 let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); return {android: isAndroid, ios: isiOS} },
JS与IOS交互方式一:WKScriptMessageHandler
WKWebView有一个内容交互控制器,该对象提供了通过JS向WKWebView发送消息的途径。需要设置MessageHandler,大家把这个功能简称为MessageHandler。
IOS具体实现参考:链接
这里只说js调用
/ window.webkit.messageHandlers.<name>.postMessage(<messageBody>) // 这个name就是设置MessageHandler的第一个参数,与IOS约定的方法名 // messageBody 必须是json格式,为空时传null window.webkit.messageHandlers.ShareContract.postMessage(jsonData);
JS与IOS交互方式二:WebViewJavascriptBridge交互 拦截url做事件处理,如果要传参数,不建议用这种
//模拟 h5页面在app端的跳转
let data = \'{"type": "basisTongji", "url":"\' + "https://xxxx/basisTongji.html" + "}";
window.WebViewJavascriptBridge.javaScrpitRresponseJson(data);
Android端交互
冒号前面区分是什么功能,冒号后面是接收的参数
window.location.href = "ShareContract:" + JSON.stringify(jsonData);
运用场景二:登录失效的情况下,通知APP端,需要跳转到登录页面
- exit:true是和安卓约定的功能名及参数
- logout 是和IOS约定的方法名,注意当值为空的时候,需要传null,不能什么都不写,不然会走代理。。。
let deviceP = device()
if (deviceP.android) {
window.location.href = "exit:true"
}
if (deviceP.ios) {
//ios 交互
window.webkit.messageHandlers.logout.postMessage(null);
}