Android 利用WebViewJavascriptBridge 实现js和java的交互(一)
此文出自:http://blog.csdn.net/sk719887916/article/details/47189607,skay
按安卓开发眼下现状来说,开发人员大部分时间还是花在UI的屏幕适配上,使用原生控件开发成本已不是那么理想,鉴于非常多项目和ios基于一致的ui界面。至使安卓UI开发成本花费更大的代价,因此眼下结合Html5和原生控件是解决UI适配的一种非常好的选择。处于APP性能也会用java和native层进行结合。无论是哪种结合。事实上原理都几乎相同,仅仅要依照它的协议来,是非常easy的,今天我们仅对于Html和Java层结合。学习下WebViewJavascriptBridge。
已经熟悉了jsbridge的朋友直接移步:
《Android基于JsBridge封装的高效带载入进度的WebView》:http://blog.csdn.net/sk719887916/article/details/52402470
一 什么是webViewjavascripBridge?
WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,用作者的话来说就是实现java(ios为oc)和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得我们的开发更加灵活和安全。
二 为什么要用webViewjavascripBridge?
mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction");
4.4之后调用须要在调用方法增加增加@JavascriptInterface注解,假设代码无此申明,那么也就无法使得js生效,也就是说这样就能够避免恶意网页利用js对安卓client的窃取和攻击。
可是即使这样,我们非常多时候须要在js记载本地代码的时候,要做一些推断和限制,或者有可能也会做些过滤和对用户友好提示,因此JavascriptInterface也就无法满足我们的需求了,特此有大神就写出了WebViewJavascriptBridge框架。
三 怎么使用webViewjavascripBridge
1 将jsBridge.jar引入到我们的project
repositories {
// ...
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}2 WebView包需使用以上包的webView
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- button 演示Java调用web --> <Button android:id="@+id/button" android:layout_width="match_parent" android:text="@string/button_name" android:layout_height="48dp" /> <!-- webview 演示web调用Java --> <com.github.lzyzsd.jsbridge.BridgeWebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" > </com.github.lzyzsd.jsbridge.BridgeWebView> </LinearLayout>
3 Java代码
public class MainActivity extends Activity implements OnClickListener {
private final String TAG = "MainActivity";
BridgeWebView webView;
Button button;
int RESULT_CODE = 0;
ValueCallback<Uri> mUploadMessage;
static class Location {
String address;
}
static class User {
String name;
Location location;
String testStr;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (BridgeWebView) findViewById(R.id.webView);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
webView.setDefaultHandler(new DefaultHandler());
webView.setWebChromeClient(new WebChromeClient() {
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {
this.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {
this.openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
pickFile();
}
});
//载入本地网页
//webView.loadUrl("file:///android_asset/demo.html");
//载入server网页
webView.loadUrl("https://www.baidu.com");
//必须和js同名函数。注冊详细运行函数。相似java实现类。
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str ="这是html返回给java的数据:" + data;
// 比如你能够对原始数据进行处理
makeText(MainActivity.this, str, LENGTH_SHORT).show();
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
}
});
//模拟用户获取本地位置
User user = new User();
Location location = new Location();
location.address = "上海";
user.location = location;
user.name = "Bruce";
webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show();
}
});
webView.send("hello");
}
public void pickFile() {
Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooserIntent.setType("image/*");
startActivityForResult(chooserIntent, RESULT_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == RESULT_CODE) {
if (null == mUploadMessage){
return;
}
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
@Override
public void onClick(View v) {
if (button.equals(v)) {
webView.callHandler("functionInJs", "data from Java", new CallBackFunction() {
@Override
public void onCallBack(String data) {
// TODO Auto-generated method stub
Log.i(TAG, "reponse data from js " + data);
}
});
}
}
}
2 自定webVIewClientclass MyWebViewClient extends BridgeWebViewClient{
public MyWebViewClient(BridgeWebView webView) {
super(webView);
}
}mWebView.setWebViewClient(new MyWebViewClient(mWebView));
上面句话非常关键:
//必须和js函数同名。注冊详细运行回调函数,相似java实现类。
webView.registerHandler("submitFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String str ="这是html返回给java的数据:" + data;
// 比如你能够对原始数据进行处理
makeText(MainActivity.this, str, LENGTH_SHORT).show();
Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
}
});假设是webview刚開始就运行一段Java代码 ,能够通过webView.CallHandler()来实现 。
当然我们注冊的方法也要和js里面的方法名一致。
webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() {
@Override
public void onCallBack(String data) {
makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show();
}
});3 Html和js实现
html代码例如以下。效果图
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<title>
js调用java
</title>
</head>
<body>
<p>
<xmp id="show">
</xmp>
</p>
<p>
<xmp id="init">
</xmp>
</p>
<p>
<input type="text" id="text1" value="username(username)" />
</p>
<p>
<input type="text" id="text2" value="password" />
</p>
<p>
<input type="button" id="enter" value="发消息给Native" onclick="testClick();"
/>
</p>
<p>
<input type="button" id="enter1" value="调用Native方法" onclick="testClick1();"
/>
</p>
<p>
<input type="button" id="enter2" value="显示html" onclick="testDiv();" />
</p>
<p>
<input type="file" value="打开文件" />
</p>
</body>
</html>js代码
<script>
function testDiv() {
document.getElementById("show").innerHTML = document.getElementsByTagName("html")[0].innerHTML;
}
function testClick() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
//发送消息给java代码
var data = "name=" + str1 + ",pass=" + str2;
window.WebViewJavascriptBridge.send(
data
, function(responseData) {
document.getElementById("show").innerHTML = "repsonseData from java, data = " +responseData
}
);
}
function testClick1() {
var str1 = document.getElementById("text1").value;
var str2 = document.getElementById("text2").value;
//调用本地java方法
window.WebViewJavascriptBridge.callHandler(
'submitFromWeb'
, {'param': str1}
, function(responseData) {
document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
}
);
}
function bridgeLog(logContent) {
document.getElementById("show").innerHTML = logContent;
}//注冊事件监听
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
callback(WebViewJavascriptBridge)
},
false
);
}
}
//注冊回调函数,第一次连接时调用 初始化函数
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': 'Wee!'
};
console.log('JS responding with', data);
responseCallback(data);
});
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
});
})
</script>这段代码不难理解。我们对上面的id为enter的Button注冊了一个点击事件,点击后运行下面testClick()方法,依次类推,其它Button注冊事件相同,
当点击“发消息给Native”的按钮时,Js通过webWiew的jsBridage.send()发送一条数据给java层(密码和username)。同一时候在此用function()来运行应java层回调函数的。此demo中是把java返回的数据插入到"show"的div里面去。
testClick1():此方法中调用callHandler来调用Java代码的submitFromweb同名函数,能够结合上面的Activty的代码理解下。此函数调用我们已在java注冊实现好的
//必须和js同名函数。注冊详细运行函数,相似java实现类。webView.registerHandler("submitFromWeb", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { String str ="这是html返回给java的数据:" + data; // 比如你能够对原始数据进行处理 makeText(MainActivity.this, str, LENGTH_SHORT).show(); Log.i(TAG, "handler = submitFromWeb, data from web = " + data); function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5)); } });
java注冊Js函数如上面列子 。那么在js中注冊方法来注冊呢,
在js中我们相同能够直接注冊一个回调函数,通过 bridge.registerHandler()来注冊。接着调用 responseCallback(responseData)来返回数据给java代码的同名函数。f
也能够直接调用init()来指定网页首次载入上面注冊java代码。
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': 'Wee!'
};
console.log('JS responding with', data);
responseCallback(data);
});
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
});
})四 总结
尽管H5并不属于插件的一种。可是借助h5我能够方便的去更新一些运营活动。和某些须要常常须要更换UI的业务功能的地方,以上仅仅JSBridge的使用姿势,,以后再给大家解剖下JsBridge的内部实现。

浙公网安备 33010602011771号