Android WebView和JavaScript交互
现在移动应用几乎都是 Hybrid App(混合模式移动应用)是指介于web-app、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”。
而hybrid的实现关键在于打通Java和JavaScript之间的交互。
在Android开发中我们是使用WebView控件来加载HTML页面的,WebView默认为我们提供了让Java和HTML页面中JavaScript脚本交互的能力。
1 Java调用JavaScript
java调用JavaScript非常简单,只需要执行下面代码即可。
mWebView.loadUrl("javascript:methodName(parameterValues)");
不过其中还需要注意几个细节,我们先来看个例子,然后再介绍需要注意的地方。
IDE:Android Studio
先写一个H5的页面test.html,把它放在了assets资源文件下
<!DOCTYPE HTML>
<head>
<title>java调用JavaScript</title>
</head>
<!--提供给java调用的方法-->
<script type="text/javascript"/>
function alertMessage(message) {
alert(message)
}
</script>
</HTML>
xml布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/id_linearlayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/id_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="alertMessage"/>
<WebView
android:id="@+id/id_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"></WebView>
</LinearLayout>
Activity代码:
public class MyWebView extends AppCompatActivity {
private WebView mWebView;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_web_view);
mWebView = (WebView) findViewById(R.id.id_webview);
mButton = (Button) findViewById(R.id.id_button);
loadURL();
}
private void loadURL() {
mWebView.setWebViewClient(new WebViewClient());//此方法可以在webview中打开链接而不会跳转到外部浏览器
mWebView.setWebChromeClient(new WebChromeClient());//各种内容的渲染需要使用webviewChromClient去实现,比如alert()方法
mWebView.loadUrl("file:///android_asset/test.html");
}
private void initEvents() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mWebView.loadUrl("javascript:alertMessage(\""+"Message"+"\")");//注意转义字符
}
});
}
//重写onKeyDown,当浏览网页,WebView可以后退时执行后退操作。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
需要注意的是setWebViewClient(new WebViewClient())和setWebChromeClient(new WebChromeClient())方法。
- setWebViewClient(new WebViewClient())可以在webview中打开链接而不会跳转到外部浏览器
- setWebChromeClient(new WebChromeClient())方法可以给WebView设置一个WebChromeClient,各种内容的渲染需要使用webviewChromClient去实现,比如alert()方法,如果这个方法没写不会有alert()方法的效果。
点击按钮之后效果
02.jpg2 JavaScript调用Java
WebView提供了一个名为WebSettings的工具类实现让Webview中的JavaScript脚本调用android应用的Java方法,实现方式很简单。
- 调用与WebView关联的WebSettings实例的setJavaScriptEnabled方法使能调用的功能
- 调用WebView的addJavaScriptInterface方法将应用中的Java对象暴露给JavaScript
- 在JavaScript脚本中调用暴露的Java对象的方法
增加H5页面代码
<!DOCTYPE HTML>
<head>
<title>h5</title>
</head>
<!--调用java方法-->
<body>
<input type="button" value=" 打印Log" onclick=" javaObject.printLog('printLog');">
<input type="button" value=" 显示Toast" onclick=" javaObject.showToast();">
</body>
<!--提供给java调用的方法-->
<script type="text/javascript"/>
function alertMessage(message) {
alert(message)
}
</script>
</HTML>
我们新建提供给JavaScript调用的Java类javaObject
public class javaObject {
private Context context;
private final String TAG = "javaObjectLog";
public javaObject(Context context) {
this.context = context;
}
public void printLog(String mes){
Log.i(TAG, mes);
}
public void showToast(){
Toast.makeText(context, "Toast", Toast.LENGTH_SHORT).show();
}
}
增加Activity代码
public class MyWebView extends AppCompatActivity {
private WebView mWebView;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_web_view);
mWebView = (WebView) findViewById(R.id.id_webview);
mButton = (Button) findViewById(R.id.id_button);
loadURL();
initEvents();
}
private void initEvents() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mWebView.loadUrl("javascript:alertMessage(\""+"Message"+"\")");
}
});
}
private void loadURL() {
mWebView.setWebViewClient(new WebViewClient());//此方法可以在webview中打开链接而不会跳转到外部浏览器
mWebView.setWebChromeClient(new WebChromeClient());//各种内容的渲染需要使用webviewChromClient去实现,比如alert()方法
WebSettings webSettings = mWebView.getSettings();//
webSettings.setJavaScriptEnabled(true);//
mWebView.loadUrl("file:///android_asset/test.html");
mWebView.addJavascriptInterface(new javaObject(this), "javaObject");//把javaObject类对象暴露给JavaScript
}
//重写onKeyDown,当浏览网页,WebView可以后退时执行后退操作。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
03.jpg
这种方法是官方提供的,但是却存在极大地安全隐患,所以从Android 4.2开始,Google就修复了这个漏洞,所以如果你测试机是4.2以上你会发现并没有成功调用暴露的方法。我们想要安全的使用上面的方法,唯一需要改动的就是对暴露给JavaScript调用的方法添加@JavascriptInterface注解。修改如下:
public class javaObject {
private Context context;
private final String TAG = "javaObjectLog";
public javaObject(Context context) {
this.context = context;
}
@JavascriptInterface
public void printLog(String mes){
Log.i(TAG, mes);
}
@JavascriptInterface
public void showToast(){
Toast.makeText(context, "Toast", Toast.LENGTH_SHORT).show();
}
}
输出结果
04.jpg 05.png