移動(dòng)技術(shù)發(fā)展了七八年漱牵,開(kāi)發(fā)人員永遠(yuǎn)有個(gè)跨平臺(tái)的夢(mèng)戳杀。從最開(kāi)始的 Web App 被人詬病體驗(yàn)差,ReactNative卡乾,Weex 等技術(shù)又有很多難以平復(fù)的坑翼悴,包括現(xiàn)在的 Flutter 也有很多問(wèn)題待解決,跨平臺(tái)的夢(mèng)想很美好,現(xiàn)實(shí)卻總有這樣那樣的瑕疵鹦赎。移動(dòng)開(kāi)發(fā)發(fā)展到今天谍椅,我認(rèn)為最好的跨平臺(tái)技術(shù)還是 H5 + Native 的混合開(kāi)發(fā)模式。隨著前端技術(shù)的飛速發(fā)展古话,如今可以依靠各種技術(shù)和工具對(duì)前端進(jìn)行優(yōu)化雏吭,使其在移動(dòng)端的體驗(yàn)更接近原生水平。
我們?cè)谧龌旌祥_(kāi)發(fā)(Hybrid App)時(shí)陪踩,絕對(duì)繞不開(kāi) JavaScript 與 Native(iOS & Android)之間的交互問(wèn)題≌让牵現(xiàn)在主流的交互框架有 JsBridge,它可能是最早的 Android 與 JavaScript 橋接庫(kù)肩狂,該庫(kù)優(yōu)點(diǎn)是接口簡(jiǎn)單摘完,不用往 HTML 中引入額外的 js 文件,缺點(diǎn)是只支持 Android傻谁,同一個(gè)項(xiàng)目還要為 iOS 尋找一個(gè)對(duì)應(yīng)的橋接庫(kù)孝治,另一個(gè)問(wèn)題是對(duì)交互接口沒(méi)有管理,大多數(shù)情況下我們把接口都寫(xiě)到一個(gè) Activity 中的审磁,造成代碼堆積谈飒,接口不易維護(hù)。近幾年還有一個(gè)比較好的橋接庫(kù)是 DSBridge-Android态蒂,這個(gè)庫(kù)相比 JsBridge 的優(yōu)勢(shì)是支持 Android 與 iOS步绸,接口支持以類(lèi)的方式管理,但是使用時(shí)需要往 HTML 中引入一個(gè) js 文件吃媒,其實(shí)現(xiàn)方式是繼承了 WebView瓤介,所以使用時(shí)要使用其改造后的 DWebView,我本人不喜歡這種對(duì) WebView 的侵入方式赘那。
我在其兩個(gè)庫(kù)的基礎(chǔ)之上又造了一個(gè)輪子刑桑,這就是 WebViewJsBridge-Android,它首先支持 Android 與 iOS 兩個(gè)端募舟,接口與 JsBridge 相似祠斧,同樣支持以類(lèi)的方式管理交互接口,同樣需要引入一個(gè) js 文件(在 1.1.0 版本中可以不引用這個(gè) js 文件)拱礁,沒(méi)有使用繼承 WebView 這種侵入方式實(shí)現(xiàn)功能琢锋。
以下是 WebViewJsBridge-Android 的使用文檔供大家參考:
WebViewJsBridge-Android
WebViewJsBridge-Android 是 HTML5 和 WebView 之間用于通訊的工具庫(kù)。
WebViewJsBridge-iOS:https://github.com/al-liu/WebViewJsBridge-iOS
它的特點(diǎn)是跨平臺(tái)呢灶,支持 iOS吴超,Android,JavaScript鸯乃,接口統(tǒng)一鲸阻,簡(jiǎn)單易用。工具庫(kù)的實(shí)現(xiàn)對(duì) WebView 無(wú)侵入性。使用以類(lèi)的方式來(lái)管理通信的接口鸟悴,每個(gè)接口的實(shí)現(xiàn)類(lèi)對(duì)應(yīng)唯一的命名空間陈辱,如 ui.alert,ui 對(duì)應(yīng)一個(gè)實(shí)現(xiàn)類(lèi)的命名空間细诸,alert 是該實(shí)現(xiàn)類(lèi)的一個(gè)實(shí)現(xiàn)方法沛贪。在 1.1.0 版本中, H5 可以不引入 hcJsBridge.js 文件震贵。
下面這張圖幫助理解它們之間的關(guān)系:
系統(tǒng)版本要求
支持 API 19利赋,Android4.4及以上的系統(tǒng)版本。
安裝
Gradle
compile 'com.lhc:webviewjsbridge:1.1.0'
引入 WebViewJsBridge 的 js 文件
在 html 中 <script>引入 hcJsBridge.js</script>
屏歹。
注意: 1.1.0 版本 H5 可以不引入 hcJsBridge.js 文件隐砸,但使用方法有少許差異之碗,后面有介紹蝙眶。
Example 的說(shuō)明
example 模塊中提供完整使用示例,包括基礎(chǔ)的調(diào)用演示和進(jìn)階用法褪那,如幽纷,調(diào)用相機(jī)拍攝一張圖片,使用 okhttp
發(fā)起一個(gè) GET 請(qǐng)求博敬。
使用方法
初始化原生的 WebViewJsBridge 環(huán)境
// WebView 要開(kāi)啟 JavaScriptEnabled
webSettings.setJavaScriptEnabled(true);
mJsBridge = WebViewJsBridge.newInstance(mMainWebView);
如果 H5 不引入 hcJsBridge.js友浸,則還需要在 onPageFinished 中調(diào)用 injectWebViewJavascript 方法
mMainWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mJsBridge.injectWebViewJavascript();
}
});
原生注冊(cè)接口實(shí)現(xiàn)類(lèi)供 HTML5 調(diào)用
mJsBridge.addJsBridgeApiObject(new UIApiImpl(), "ui");
mJsBridge.addJsBridgeApiObject(new RequestApiImpl(weakReference), "request");
UIApiImpl 的實(shí)現(xiàn)類(lèi):
public class UIApiImpl {
private static final String TAG = "UIApiImpl";
@JavascriptInterface
public void alert(JSONObject data, ResponseHandler<String> responseHandler){
responseHandler.complete("native api alert'callback.");
}
// 實(shí)現(xiàn)類(lèi)支持四種方法簽名:
// 有參數(shù),有回調(diào)
@JavascriptInterface
public void test1(String data, ResponseHandler<String> responseHandler){
responseHandler.complete("response data");
}
// 有參數(shù)偏窝,無(wú)回調(diào)
@JavascriptInterface
public void test2(JSONObject data){
Log.d(TAG, String.format("Js native api:test2, data is:%s", data.toString()));
}
// 無(wú)參數(shù)收恢,無(wú)回調(diào)
@JavascriptInterface
public void test3(){
Log.d(TAG, "Js native api:test3");
}
// 無(wú)參數(shù),有回調(diào)
@JavascriptInterface
public void test4(ResponseHandler<String> responseHandler){
responseHandler.complete("response data");
}
}
原生調(diào)用 HTML5 接口
mJsBridge.callHandler("test1", "test1 data", new ResponseHandler() {
@Override
public void complete(Object responseData) {
Log.d(TAG, String.format("test1 callback data is:%s", responseData));
}
});
初始化 HTML5 的 WebViewJsBridge 環(huán)境
如果 H5 引入 hcJsBridge.js祭往,則使用下面的方式引入伦意。
<!DOCTYPE html>
<html>
<head>
...
<script src="./hcJsBridge.js"> </script>
</head>
...
</html>
如果 H5 不引入 hcJsBridge.js,則使用下面這個(gè)方法注冊(cè)接口硼补。
// 在這個(gè) window._hcJsBridgeInitFinished 全局函數(shù)中等待 bridge 初始化完成驮肉,然后注冊(cè)接口,初始調(diào)用已骇。
window._hcJsBridgeInitFinished = function(bridge) {
bridge.registerHandler("test1", function(data, callback) {
callback('callback native,handlename is test1');
})
bridge.callHandler('ui.test3');
}
HTML5 注冊(cè)接口供原生調(diào)用
hcJsBridge.registerHandler("testCallJs", function(data, callback) {
log('Native call js ,handlename is testCallJs, data is:', data);
callback('callback native, handlename is testCallJs');
})
HTML5 調(diào)用原生接口
var data = {foo: "bar"};
hcJsBridge.callHandler('ui.alert', data, function (responseData) {
log('Js receives the response data returned by native, response data is', responseData);
})
開(kāi)啟 debug 日志
開(kāi)啟 debug 日志离钝,將打印一些調(diào)用信息,輔助排查問(wèn)題褪储。debug 日志默認(rèn)不開(kāi)啟卵渴。
mJsBridge.enableDebugLogging(true);
License
WebViewJsBridge-Android 使用 MIT license 發(fā)布,查看 LICENSE 詳情鲤竹。