hybrid
?就是嵌入在客户端的H5
页面, 也就是咱们常说的webview
.它跟浏览器中的html
页面区别不大.由于大都是由webkit
渲染引擎渲染出来的.javascript
webkit
渲染引擎主要由下面几个部分组成html
js
引擎线程GUI
渲染线程http
线程异步事件处理都是经过Event Loop
. 因此webview
跟浏览器页面对于前端开发者来讲根本没啥区别。可是webview
是运行在Android
和IOS
系统里面,那它们之间是如何进行通讯的呢?下面我将以Android
为例来探究他们之间的通讯方式前端
在android
新建一个简单的项目java
建一个简单html
页面以下,放在android
项目的src/main/assets
目录里面jquery
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>shop</title>
</head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript">
</script>
<body>
<div>我是webview</div>
<div id="cs">测试JavascriptInterface</div>
</body>
<script>
let i = 0;
$("#cs").on("click", function(){
android.showToast("我是弹窗");
})
</script>
</html>
复制代码
载入webview
android
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 开始webview调试模式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
WebView webView = (WebView)findViewById(R.id.shop);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/shop.html");
}
复制代码
页面就出来了 git
hybrid
与Android
通讯方式JavascriptInterface
就是在js
上下文注入一个JavascriptInterface
.假设这个JavascriptInterface
名为AndroidIn
. 那么在webview
里面能够直接调用Android
github
android
代码web
WebView webView = (WebView)findViewById(R.id.shop);
webView.getSettings().setJavaScriptEnabled(true);
class JsInterface {
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
}
}
webView.addJavascriptInterface(new JsInterface(), "AndroidIn");
复制代码
html
代码json
<div>我是webview</div>
<div id="cs">测试JavascriptInterface</div>
</body>
<script>
let i = 0;
$("#cs").on("click", function(){
AndroidIn.showToast("我是弹窗");
})
</script>
复制代码
点击以后出现我是弹窗
onJsAlert
, onJsConfirm
, onJsPrompt
android
能够拦截js
调用警告框,输入框,和确认框
android
代码
WebView webView = (WebView)findViewById(R.id.shop);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("JsAlert")
.setMessage(message)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setCancelable(false)
.show();
return true;
}
});
复制代码
html
代码
<div>我是webview</div>
<div id="cs">测试JavascriptInterface</div>
</body>
<script>
let i = 0;
$("#cs").on("click", function(){
alert("我是弹窗");
})
</script>
复制代码
点击以后弹窗已经换成了原生的弹窗了
android
载入h5
文件的时候在地址上加一些参数
webView.loadUrl("file:///android_asset/shop.html?a=12&b=12");
复制代码
h5
页面经过href
连接能够拿到a,b
值
loadUrl
android
能够经过loadUrl
直接执行js
的方法 H5
代码
window.Bridge = {
callJS(){
alert("我是callJS")
}
}
复制代码
android
代码
webView.loadUrl("javascript:Bridge.callJS()");
复制代码
evaluateJavascript
跟上面差很少,只不过android 4.4
以上才能用
webView.evaluateJavascript("javascript:Bridge.callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为 Bridge.callJS返回的结果
}
});
复制代码
JsBridge
什么是Jsbridge
? JsBridge
并非Android
或者H5
直接就有的API
.它是一种经过上面五种通讯方式(遵循某种协议)来实现的一个双向通讯桥. 下面来实现一个简单的 JsBridge
callBack
惟一id
.客户端回调会告诉返回对应的id
来执行对应的callback
callNative
是H5
调用Android原生的方法,是经过JavascriptInterface
注入一个nativeBridge
来实现的.receiveNative
是Android原生调用H5
的方法,是经过webView.loadUrl("javascript:window.Bridge.receiveNative("")
来实现.你能调用我,我能调用你,而后经过某个协议(
id
).一个双工通讯就实现了
H5
代码以下
<body>
<div>我是webview</div>
<div id="cs">测试JavascriptInterface</div>
</body>
<script>
let cid = 0;
let callbacks = {};
window.Bridge = {
// 获取用户的登陆信息
getUserInfo(data = {}){
window.Bridge.callNative("getUserInfo", data)
},
// 获取网络状况
getNetInfo(data = {}){
window.Bridge.callNative("getNetInfo", data)
},
callNative: function(bridgeName, data) {
cid++;
if (data.onSuccess) {
callbacks[cid] = data.onSuccess;
}
nativeBridge.postMessage(JSON.stringify({
cid,
bridgeName: bridgeName,
data: data.params || {}
}));
},
receiveNative: function(msg) {
callbacks[msg.cid] && callbacks[msg.cid](msg);
if (msg.bridgeName != "getNetInfo") {
Reflect.deleteProperty(callbacks, msg.cid);
}
}
}
document.getElementById("cs").onclick = function(){
window.Bridge.getUserInfo({
params:{},
onSuccess(res){
alert(res.name)
}
})
}
</script>
复制代码
Android
代码以下
final WebView webView = (WebView)findViewById(R.id.h5_shop);
final Handler handler = new Handler(){
public void handleMessage(Message msg) {
if (msg.what == 1) {
webView.loadUrl("javascript:window.Bridge.receiveNative("+resObj.toString()+")");
}
}
};
webView.getSettings().setJavaScriptEnabled(true);
class JsInterface {
@JavascriptInterface
public void postMessage(String a) throws JSONException{
JSONObject jsonObj = new JSONObject(a);
String bridgeName = jsonObj.getString("bridgeName");
if ( bridgeName.equals("getUserInfo") ){
resObj.put("cid", jsonObj.get("cid"));
resObj.put("name", "leiwuyi");
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
}
}
webView.addJavascriptInterface(new JsInterface(), "nativeBridge");
webView.loadUrl("file:///android_asset/shop.html");
复制代码
点击以后效果以下
demo
地址以下github