WebView控件中的onConsoleMessage方法不被調用

1.目的

在WebView控件中,若是頁面中調用了javascript腳本console.log 方法,就調用一個Java方法.javascript

 

2.默認實現方法

在Android的WebView控件中,有一個setChromeClient(WebChromeClient)方法,java

此方法的參數是WebChromeClient對象,經過重載此對象中的onConsoleMessage方法就android

能夠達到此目的.看代碼:web

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纔有的方法,第二個方法是舊版本的.ide

第二個方法已經不推薦使用了,可是在舊版本的android中,仍然須要此方法.因此最好兩個方法都實現.性能

 

3.問題

默認的實如今某些版本的手機中很差使,onConsoleMessage方法死活不被調用測試

 

4.解決方案

使用WebView的addJavascriptInterface方法:this

// 首先,定一個類,叫什麼名稱均可以,可是裏面的方法名必須與
// 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方法那麼詳細,好比行號,就無法輸出.code

因此,咱們應該在onConsoleMessage好使的時候使用onConsoleMessage,很差使的時候在使用咱們自定義的方式.orm

那麼,如何來判斷onConsoleMessage是否好使呢? 咱們能夠在程序初始化的時候,先在WebView中運行一下console.log,

若是onConsoleMessage運行了,就添加一個標記,表示默認的實現是好使的.

@Override
public 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;
    }
}
相關文章
相關標籤/搜索