您的位置:首页 > 移动开发 > Android开发

Android中WebView与JS的交互

2016-07-22 16:58 411 查看
上家公司的主打产品是一个游戏社交类应用,里边有一套用户等级系统和一套付费系统。由于这个两套系统的界面不是固定的,而且支持的状态也根据用户的等级而有所不同,有时还需要根据节日或者当前推广的内容进行动态的调整。所以采用了webview加载页面的方式来实现。当然就免除不了会有Android原生方法与JS方法互相调用的情况。这里通过一个简单的例子阐述互调的实现方法,还有注意事项。

实现

1 定义一个提供方法给JS调用的类

final class TaskInterface {

private Context context;

public TaskInterface(Context context) {
this.context = context;
}

@JavascriptInterface
public void showString(final String message) {
handler.post(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(
context);
builder.setTitle(getString(R.string.app_name));
builder.setMessage(message);
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
});
}

@JavascriptInterface
public void showNum(final int num) {
handler.post(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(
context);
builder.setTitle(getString(R.string.app_name));
builder.setMessage("js传递给android的参数为:" + num);
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
});
}

@JavascriptInterface
public void showJsonString(final String object) {
handler.post(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(
context);
builder.setTitle(getString(R.string.app_name));
JSONObject jsonObject;
try {
jsonObject = new JSONObject(object);
builder.setMessage("name的值为:"
+ jsonObject.getString("name") + "||||"
+ "age的值为:" + jsonObject.getString("age"));
} catch (JSONException e) {
e.printStackTrace();
}
builder.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
}
});
}
}


这里定义了三个供JS调用的方法,需要为每个方法添加@JavascriptInterface:因为安全问题,在Android4.2以上版本,JS只能访问带有 @JavascriptInterface注解的Java函数

2 将该类的实例注入到WebView中

WebSettings webSettings = webView.getSettings();
// 需要与JS交互,必须先设置为true
webSettings.setJavaScriptEnabled(true);
// 将提供方法给JS调用的实例注入到WebView中
// Task:可以理解为JS使用该实例的一个标识
webView.addJavascriptInterface(new TaskInterface(this), "Task");


3 在JS调用Android提供的方法

// 有两种常用调用形式
javascript:Task.showString('传递简单字符串')
window.Task.showNum(324343)


4 WebView调用JS的方法

// callJsMethod()为JS定义的方法
webView.loadUrl("javascript:callJsMethod()");


JS调用Android方法可传递的参数类型

<!DOCTYPE html>
<html>
<head>
<title>Android与JS互调</title>
</head>
<body>
<h1 align="center">Android与JS互调</h1>
<script>
function callJsMethod(){
document.getElementById("div").innerHTML+="<br\>这是android调用js方法动态添加的内容";
}
</script>

<p></p>
<h3>Android调用JS动态添加的标签</h3>
<p></p>
<div onclick="window.Task.showNum(324343)"><u>js调用android方法:传递整形数据</u></div>
<p></p>
<div onclick="javascript:Task.showString('传递简单字符串')"><u>js调用android方法:传递简单字符串</u></div>
<p></p>
<div onclick="act.showObject()"><u>js调用android方法:传递json格式字符串</u></div>
<p></p>
<div onclick="window.Task.showString('js调用android方法的另一种形式:window.Task.showDialog')"><u>js调用android方法的另一种形式</u></div>
<p></p>

<p></p>
<h3>Android调用JS动态添加的标签</h3>
<div id="div"/>

</body>
<script>

var act = {
showObject:function(){
var params = {
"name": "jacky",
"age": 123456
};
params = JSON.stringify(params);
javascript:Task.showJsonString(params);
}
};
</script>
</html>


该html文件给出了三种格式:

整形数据,可以直接获取到

字符串,也可以获取到

复杂数据:拼装成Json格式,再调用JS的方法转换成字符串后返回

3 总结

调用的过程中,经常会遇到没有正确调用的情况。但由于又没有错误的提示,难免会给调试增加难度。这里给出几点遇到过的坑:

1 4.2以上的系统需要增加@JavascriptInterface注解

2 JS调用的Android方法,内部的实现需要放在主线程进行

3 JS调用Java函数时,传递的参数格式有误也会导致调用不正常

4 官方文档

其实,官方对于一些常用的api都会有详细的说明或者解释,我们可以多查看这些说明,对于我们的开发有很大的帮助。这是给出addJavascriptInterface方法的官方说明。其实挺详细,对于一般的用法都有说明

/**
* Injects the supplied Java object into this WebView. The object is
* injected into the JavaScript context of the main frame, using the
* supplied name. This allows the Java object's methods to be
* accessed from JavaScript. For applications targeted to API
* level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
* and above, only public methods that are annotated with
* {@link android.webkit.JavascriptInterface} can be accessed from JavaScript.
* For applications targeted to API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below,
* all public methods (including the inherited ones) can be accessed, see the
* important security note below for implications.
* <p> Note that injected objects will not
* appear in JavaScript until the page is next (re)loaded. For example:
* <pre>
* class JsObject {
*    {@literal @}JavascriptInterface
*    public String toString() { return "injectedObject"; }
* }
* webView.addJavascriptInterface(new JsObject(), "injectedObject");
* webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
* webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
* <p>
* <strong>IMPORTANT:</strong>
* <ul>
* <li> This method can be used to allow JavaScript to control the host
* application. This is a powerful feature, but also presents a security
* risk for apps targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or earlier.
* Apps that target a version later than {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
* are still vulnerable if the app runs on a device running Android earlier than 4.2.
* The most secure way to use this method is to target {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
* and to ensure the method is called only when running on Android 4.2 or later.
* With these older versions, JavaScript could use reflection to access an
* injected object's public fields. Use of this method in a WebView
* containing untrusted content could allow an attacker to manipulate the
* host application in unintended ways, executing Java code with the
* permissions of the host application. Use extreme care when using this
* method in a WebView which could contain untrusted content.</li>
* <li> JavaScript interacts with Java object on a private, background
* thread of this WebView. Care is therefore required to maintain thread
* safety.
* </li>
* <li> The Java object's fields are not accessible.</li>
* <li> For applications targeted to API level {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* and above, methods of injected Java objects are enumerable from
* JavaScript.</li>
* </ul>
*
* @param object the Java object to inject into this WebView's JavaScript
*               context. Null values are ignored.
* @param name the name used to expose the object in JavaScript
*/
public void addJavascriptInterface(Object object, String name) {
checkThread();
mProvider.addJavascriptInterface(object, name);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: