什么是hybrid
?
就是嵌入在客户端的H5
页面, 也就是我们常说的webview
.它跟浏览器中的html
页面区别不大.因为大都是由webkit
渲染引擎渲染出来的.
webkit
渲染引擎主要由下面几个部分组成
js
引擎线程GUI
渲染线程- 定时器线程
- 异步
http
线程 - 事件触发线程
异步事件处理都是通过Event Loop
. 所以webview
跟浏览器页面对于前端开发者来说根本没啥区别。但是webview
是运行在Android
和IOS
系统里面,那它们之间是如何进行通信的呢?下面我将以Android
为例来探究他们之间的通信方式
先搭建环境
第一步
在android
新建一个简单的项目
第二步
建一个简单html
页面如下,放在android
项目的src/main/assets
目录里面
<!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
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");
}
页面就出来了
hybrid
与Android
通信方式
第一种 JavascriptInterface
就是在js
上下文注入一个JavascriptInterface
.假设这个JavascriptInterface
名为AndroidIn
. 那么在webview
里面可以直接调用Android
android
代码
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
代码
<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>
点击之后弹窗已经换成了原生的弹窗了
第三种 URL参数
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