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