Java
JavaScript
Android

AndroidのWebView側だけの対応でJavascriptイベントをフックしてaddJavascriptInterfaceで設定したJSメソッドを呼び出す

はじめに

皆様も参画中のプロジェクトでWebページを編集する権限がなく、どうしてもWebView側でjsやアプリの動作などをカスタマイズしなければならない場合があると思います。
この記事は前述のような方やWebフロントエンジニアに協力を仰げない方々向けのメモです。
(僕の場合は、非協力的なWebフロントエンジニアの対応に四苦八苦し、結局Android側アプリで対応することにorz)

やり方

例えばjsのhistoryオブジェクトはpopStateイベントリスナーを追加することにより、UrlLoadingを検知できます。
今回は、popStateイベントを利用して、WebViewに登録したJavascriptInterfaceのメソッドを呼び出してみたいと思います。

SampleActivity.java
// Javascriptを有効に。
mWebView.getSettings().setJavaScriptEnabled(true);
// JavascriptInterfaceを追加!
mWebView.addJavascriptInterface(new JSObject(mWebView), "injectedObj");

mWebView.setWebViewClient( new WebViewClient(){
            // ページにフック用のイベントリスナーを追加する。
            // popStateはpushStateのあとに呼ばれる。
            @Override
            public void onPageFinished(WebView view, String url) {
                mWebView.loadUrl("javascript:window.addEventListener('popState', function (event) { injectedObj.screentype('me') }, false)");
            }
        });
mWebView.loadUrl(mUrl);
JSObject.java
public class JSObject {
    private WebView mWebView;

    public JSObject(WebView webView) {
        this.mWebView = webView;
    }
    // popStateイベント発火したら呼ばれる
    @JavascriptInterface
    public String screentype(String str) {
        Log.d("xxx", "hook " + str);
        return "false";
    }
}

これで自由にWebページをフックできるようになりました。どんどんWebページをハックして、自由にカスタマイズしていきましょう!