1.目的
在WebView控件中,如果页面中调用了javascript脚本console.log 方法,就调用一个Java方法.
2.默认实现方法
在Android的WebView控件中,有一个setChromeClient(WebChromeClient)方法,
此方法的参数是WebChromeClient对象,通过重载此对象中的onConsoleMessage方法就
可以达到此目的.看代码:
WebView webView = new WebView();webView.setWebChromeClient(new DefaultWebChromeClient);// 以上代码放在在Activity或则Fragment中的onCreate方法中private class DefualtWebChromeClient extends WebChromeClient { @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { String message = consoleMessage.message(); int lineNumber = consoleMessage.lineNumber(); String sourceID = consoleMessage.sourceId(); String messageLevel = consoleMessage.message(); Log.i("[WebView]", String.format("[%s] sourceID: %s lineNumber: %n message: %s", messageLevel, sourceID, lineNumber, message)); return super.onConsoleMessage(consoleMessage); } @Override public void onConsoleMessage(String message, int lineNumber, String sourceID) { Log.i("[WebView]", String.format("sourceID: %s lineNumber: %n message: %s", sourceID, lineNumber, message)); super.onConsoleMessage(message, lineNumber, sourceID); }}
第一个方法onConsoleMessage(ConsoleMessage consoleMessage)是新版本的android才有的方法,第二个方法是旧版本的.
第二个方法已经不推荐使用了,但是在旧版本的android中,仍然需要此方法.所以最好两个方法都实现.
3.问题
默认的实现在某些版本的手机中不好使,onConsoleMessage方法死活不被调用
4.解决方案
使用WebView的addJavascriptInterface方法:
// 首先,定一个类,叫什么名称都可以,但是里面的方法名必须与// Javascript的console中的方法名对应private class Console{ private static final String TAG="[WebView]"; public void log(String msg){ Log.i(TAG,msg); } // 还可以添加其他的方法,比如: warn,assert等等}// 然后,为WebView添加对应的接口webView.addJavascriptInterface(new Console, "console");
这个解决方案有一个不好的地方,就是输出的内容没有onConsoleMessage方法那么详细,比如行号,就没法输出.
所以,我们应该在onConsoleMessage好使的时候使用onConsoleMessage,不好使的时候在使用我们自定义的方式.
那么,如何来判断onConsoleMessage是否好使呢? 我们可以在程序初始化的时候,先在WebView中运行一下console.log,
如果onConsoleMessage运行了,就添加一个标记,表示默认的实现是好使的.
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 这些代码也可以放到onCreate方法中 this.webView = (WebView) layout.findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // Set WebChromeClient WebChromeClient webChromeClient = new TestConsoleMessageWebChromeClient(); // 先执行console.log,测试是否调用了onConsoleMessage webView.loadUrl("javascript:console.log('testConsoleMessage')"); if (((TestConsoleMessageWebChromeClient)webChromeClient).isConsoleMessageOK()){ // 这里额外使用了一个新的类 TestConsoleMessageWebChromeClient // 如果不适用TestConsoleMessageWebChromeClient,就需要在 // DefaultWebChromeClient中添加标记字段 consoleMessageOK, // 这样如果方法onConsoleMessage好使,那么每次都给consoleMessageOK赋值, // 这个有些多余,也影响性能. webChromeClient = new DefualtWebChromeClient(); }else{ // onConsoleMessage不好使,就使用这种方式,第二个参数值必须是"console" webView.addJavascriptInterface(new Console(), "console"); } webView.loadUrl("http://www.baidu.com"); return super.onCreateView(inflater, container, savedInstanceState);}// 当默认的onConsoleMessage不好使的时候使用的类private class Console { private static final String TAG = "[WebView]"; public void log(String msg) { Log.i(TAG, msg); } // 这里还可以添加其他方法console对象中有的方法,比如 assert}// 默认private class DefualtWebChromeClient extends WebChromeClient { @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { String message = consoleMessage.message(); int lineNumber = consoleMessage.lineNumber(); String sourceID = consoleMessage.sourceId(); String messageLevel = consoleMessage.message(); Log.i("[WebView]", String.format("[%s] sourceID: %s lineNumber: %n message: %s", messageLevel, sourceID, lineNumber, message)); return super.onConsoleMessage(consoleMessage); } @Override public void onConsoleMessage(String message, int lineNumber, String sourceID) { Log.i("[WebView]", String.format("sourceID: %s lineNumber: %n message: %s", sourceID, lineNumber, message)); super.onConsoleMessage(message, lineNumber, sourceID); }}// 用于测试onConsoleMessage是否调用的类private class TestConsoleMessageWebChromeClient extends WebChromeClient { private boolean consoleMessageOK = false; @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { this.consoleMessageOK = true; return super.onConsoleMessage(consoleMessage); } @Override public void onConsoleMessage(String message, int lineNumber, String sourceID) { this.consoleMessageOK = true; super.onConsoleMessage(message, lineNumber, sourceID); } public boolean isConsoleMessageOK() { return this.consoleMessageOK; }}