1.在WebView中使用JavaScript
Android提供了一个很强大的WebView控件用来处理Web网页,而在网页中JavaScript又是一个很举足轻重的脚本。因此,使用WebView时经常会涉及到Android代码和JavaScript代码的交互。
实现Java和js交互通常只需要以下几步:
①WebView开启JavaScript脚本执行。
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
②WebView设置供JavaScript调用的交互接口。
③客户端和网页端编写调用对方的代码。
2.JavaScript调用Android中的方法
比如,可以用JavaScript代码调用Android代码中的方法,来展现一个对话框,而不是使用JS中的alert()方法。
在JS和Android代码间绑定一个新的接口,需要调用addJavascriptInterface()方法。该方法参数传入一个Java对象实例和一个字符串,该字符串是一个名字(interface name,注意此接口不是通常所说的那个用来实现的接口,而是传入的这个对象在JS中的别名),在JS代码中用此名字调用该Java对象的方法。
addJavascriptInterface()方法可以让JS代码控制宿主程序,这是一个非常有力的特性,但是同时也存在一些安全问题,因为进一步JS代码可以通过反射访问到注入对象的公有域。攻击者可能会在HTML和JavaScript中包含了有威胁性的代码。所以Android 4.1,API 17开始,只有被JavascriptInterface注解标识的公有方法可以被JS代码访问。
另外,因为JS代码和Java对象在这个WebView所私有的后台线程交互,所以还需要注意线程安全性问题。
注意,与JS代码绑定的的这个Java对象运行在另一个线程中,与创建它的线程不是一个线程。而且这个Java对象的域是不可访问的。
//自定义的Android代码和JavaScript代码之间的桥梁类
public class WebAppInterface {
Context mContext;
WebAppInterface(Context c) {
mContext = c;
}
// 如果target>=API 17,则需要加上如下注解
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_LONG).show();
}
}
然后将这个类和WebView中的JS代码绑定:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android"); //给这个对象起的别名叫“Android”
这样就创立了一个接口名,叫“Android”,运行在WebView中的JS代码可以通过这个名字调用WebAppInterface类中的showToast()方法:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
3.Android调用JavaScript代码
这个还比较简单,需要调用的时候只需要一行代码:
myWebView.loadUrl("javascript:myFunction()");
其中myFunction()是JS函数。
注意:如果JavaScript函数是带参数的,那么调用时要特别注意。
比如下面这个JS函数,在原来内容上加入一行:
function writeLine(string) {
console.log("Write a new Line");
document.getElementById("content").inn erHTML += string + "<br />";//在content标签段落加入新行
}
其中content是自定义的标签,html中有一个段落是:<p id="content"></p>
那么在Android代码中调用这个writeLine()函数时,需要传入一个字符串参数,比如想要传入一个叫name的String:
myWebView.loadUrl("javascript:writeLine('"+name+"')");//JS代码要是带参数
注意:双引号中的函数名一定不要写错。
4.使用举例
①Android端代码:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final WebView myWebView = (WebView) findViewById(R.id.myWebView);
WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new JsInteration(), "control");
myWebView.setWebChromeClient(new WebChromeClient() {});
myWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
testMethod(myWebView);
}
});
myWebView.loadUrl( "file:///android_asset/js_java_interaction.html");
}
private void testMethod(WebView webView){
String call = "javascript:sayHello()";
call = "javascript:alertMessage(\"" + "content" + "\")";
call = "javascript:toastMessage(\"" + "content" + "\")";
call = "javascript:sumToJava(1,2)";
webView.loadUrl(call);
}
public class JsInteration {
@JavascriptInterface
public void toastMessage(String message){
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
@JavascriptInterface
public void onSumResult(int result) {
Log.i(LOGTAG, "onSumResult result=" + result);
}
}
}
②前端网页代码:
<html>
<script type="text/javascript">
function sayHello() {
alert("Hello")
}
function alertMessage(message) {
alert(message)
}
function toastMessage(message) {
window.control.toastMessage(message)
}
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
</script>
Java-Javascript Interaction In Android
</html>
③JS调用Java
调用格式为window.jsInterfaceName.methodName(parameterValues),此例中使用的是control作为注入接口名称。
function toastMessage(message) {
window.control.toastMessage(message)
}
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
④Java调用JS
webView调用js的基本格式为:webView.loadUrl(“javascript:methodName(parameterValues)”)
1)调用js无参无返回值函数:
String call = "javascript:sayHello()";
webView.loadUrl(call);
2)调用js有参无返回值函数:
String call = "javascript:alertMessage(\"" + "content" + "\")"; //注意对于字符串作为参数值需要进行转义双引号。
webView.loadUrl(call);
3)调用js有参数有返回值的函数
Android在4.4之前并没有提供直接调用js函数并获取值的方法,所以在此之前,常用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。
第一步:Java调用js代码:
String call = "javascript:sumToJava(1,2)";
webView.loadUrl(call);
第二步:js函数处理,并将结果通过调用java方法返回
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
第三步:Java在回调方法中获取js函数返回值
@JavascriptInterface
public void onSumResult(int result) {
Log.i(LOGTAG, "onSumResult result=" + result);
}
Android 4.4之后使用evaluateJavascript即可。这里展示一个简单的交互示例。
先提供一个具有返回值的js方法:
function getGreetings() {
return 1;
}
java代码里用evaluateJavascript方法调用:
private void testEvaluateJavascript(WebView webView) {
webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.i(LOGTAG, "onReceiveValue value=" + value);
}
});
}
输出结果:
I/MainActivity( 1432): onReceiveValue value=1
注意:
①上面限定了结果返回结果为String,对于简单的类型会尝试转换成字符串返回,对于复杂的数据类型,建议以字符串形式的json返回。
②evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。
全部评论