前言
本篇讲解Java
代码和Javascript
代码的相互调用以及JS
代码在Java
中是如何动态的注入WebView
中。一些通用配置在第一部分中说明。
一、Java 调用 JS 中函数
1.添加权限(这里使用资源目录下写好的html文件)
<uses-permission android:name="android.permission.INTERNET"/>
2.webView配置
...
// 省略掉findView..webview
mWebView.getSettings().setJavaScriptEnabled(true);
3.利用webView
的loadUrl()
方法调用JS中函数
注意调用的函数前面添加javascript:
...
btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 调用JS中无参数的函数
mWebView.loadUrl("javascript:javacalljs()");
mWebView.loadUrl("javascript:javacalljswith(\"JAVA调用了JS的有参函数\")");
}
});
...
二、JS 调用 Java 中方法
1.添加js的回调接口
第一个参数是接收回调的类,这里写成当前的类,接下来会在当前类中添加被js
调用的方法。obj
为别名,和js
中保持一致。
mWebView.addJavascriptInterface(this, "obj");
2.java中添加被js调用的方法。
<font color="red">注意一定不要忘记添加@JavascriptInterface</font>这里的方法和web.html中的window.obj.localMethods('Incoming parameters')
保持一致。
...
@JavascriptInterface
public void localMethods(String arg) {
Log.i(TAG, "This method is called!");
Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
}
三、(重点)Java 中动态注入 JS
1.注入JS方法
这里注入时机是onPageFinished()
后;注入的JS是一个alert
为例。
public class JsInjectionActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(mInsideWebViewClient);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(JsInjectionActivity.this, "obj");
mWebView.loadUrl("file:///android_asset/web.html");
...
}
private class InsideWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
super.onPageFinished(view, url);
}
}
}
...
注意:以上注入的js
包含一个alert
,写完后可能会发现alert
没有弹出来。这时要去检查myWebView.setWebChromeClient(new WebChromeClient());
是否设置了。
2.(重点)注入的js导致的问题或可能出现的问题
- 注入
js
可能会导致加载的html5
页面总是一直在加载中,加载很慢或干脆加载不出来,这个问题不是针对所有的html5
可能在某些网页上会遇到这个问题; - 注入JS后回调函数没有执行到;
解决方法:
@Override
protected void onPause(){
super.onPause();
mWebView.pauseTimers();
if(isFinishing()){
mWebView.loadUrl("about:blank");
setContentView(new FrameLayout(this));
}
}
@Override
protected void onResume(){
super.onResume();
mWebView.resumeTimers();
}
调用webView.loadUrl("about:blank");
该方法使得webView只回执一个白色背景,并且释放之前加载页面时使用的资源,并停止之前javascript的执行。
pauseTimers
, onPause
停止解析,javascript
执行等操作.区别是 onPause
只作用于调用它的WebView,而 pauseTimers 作用于当前应用中所有的WebView
resumeTimers
, onResume
恢复解析,javascript
执行等操作.区别是 onResume
只作用于调用它的WebView
,而 resumeTimers
作用于当前应用中所有的WebView。
3.当压缩后的JS注入到webView中时,注入没有生效
我的解决方式:
把JS
格式化后或是非压缩状态注入成功,不知道别人有没有遇到过类似问题,或者是其它原因,这里有疑问,如果有遇到相同问题的,欢迎一起交流。
在线js格式化,缩进方式选择:4个空格缩进
http://tool.oschina.net/codeformat/js
四、完整代码
完整代码,不包含js注入遇到的问题部分,自行加入。
1. web.html
文件
文件路径:..src/main/assets/web.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
<script type="text/javascript">
function javacalljs(){
document.getElementById("content").innerHTML = "<br>JAVA调用了JS的无参函数";
}
function javacalljswith(arg){
document.getElementById("content").innerHTML = ("<br>"+arg);
}
</script>
</head>
<body>
HTML 内容显示 <br/>
<h1>
<div id="content">内容显示</div>
</h1>
<br/>
<input type="button" value="点击调用java代码" onclick="window.obj.localMethods('Incoming parameters')"/><br/>
</body>
</html>
2. JsInjectionActivity.java
文件
public class JsInjectionActivity extends Activity {
private static final String TAG = JsInjectionActivity.class.getSimpleName();
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_invoke_js1 = (Button) findViewById(R.id.btn_invoke_js1);
Button btn_invoke_js2 = (Button) findViewById(R.id.btn_invoke_js2);
mWebView = (WebView) findViewById(R.id.webview);
InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(mInsideWebViewClient);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(JsInjectionActivity.this, "obj");
mWebView.loadUrl("file:///android_asset/web.html");
btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mWebView.loadUrl("javascript:javacalljs()");
}
});
btn_invoke_js2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mWebView.loadUrl("javascript:javacalljswith(\"JAVA调用了JS的有参函数\")");
}
});
}
@JavascriptInterface
public void localMethods(String arg) {
Log.i(TAG, "This method is called!");
Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
}
private class InsideWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
super.onPageFinished(view, url);
}
}
}
最后
不懂得地方欢迎私信我,我会在第一时间给予回复,如阅读中发现写错的地方,欢迎纠正。