Android WebView注入js 掉入缓存大坑

3,333 阅读2分钟

在打开网页就是之前需要注入一段JS,之前一直ok,直到运维换了一个部署方案之后就不行了。现象很奇怪,只有第一次打开才能注入成功,之后都不行。第一反应就是被缓存了, 事实上确实是。

(注入方案是重写 shouldInterceptRequest 方法,拦截web请求,然后在html中插入js。)

debug之后,发现网页的原始请求在第一次被拦截注入之后,再打开就不会再回调shouldInterceptRequest,自然也就无法拦截。缓存问题好解决,当时这么想着。webview各种各样的缓存全部关掉,一通操作,发现没用,还是老问题。

翻看日志,发现原来是Service Worker。create-react-app脚手架创建的项目,会自动生成 registerServiceWorker.js 用来做缓存,然后就悲剧了,没找到任何关闭这个的方法。于是root模拟器,看了下data/data/app_webview目录。

Service Worker里面就是缓存的内容,关闭浏览器的时候手动去删掉这个目录,可以解决这个问题,但是似乎不是每次都生效,极其奔溃。

最后曲线救国,采用另外一种插入方法,调用一段js注入。这样就可以不用只拦截html的请求,网页打开过程中任何一个请求拦截到就可以进行注入。

private void injectScriptFile(WebView view) {
        String js = "Your JS";
        byte[] buffer = js.getBytes();
        String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);

        view.post(() -> view.loadUrl("javascript:(function() {" +
                "var parent = document.getElementsByTagName('head').item(0);" +
                "var script = document.createElement('script');" +
                "script.type = 'text/javascript';" +
                // Tell the browser to BASE64-decode the string into your script !!!
                "script.innerHTML = window.atob('" + encoded + "');" +
                "parent.appendChild(script)" +
                "})()"));
    }

注意如果js长度短可以使用loadUrl,如果js很大,会报错

Refusing to load URL as it exceeds 2097152 characters

那你需要使用evaluateJavascript,Android4.4+引入的方法

private void injectScriptFile(WebView view) {
        String js = jsInjectorClient.assembleJs(view.getContext(), "%1$s%2$s");
        byte[] buffer = js.getBytes();
        String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);

        view.post(() -> view.evaluateJavascript("javascript:(function() {" +
                "var parent = document.getElementsByTagName('head').item(0);" +
                "var script = document.createElement('script');" +
                "script.type = 'text/javascript';" +
                // Tell the browser to BASE64-decode the string into your script !!!
                "script.innerHTML = window.atob('" + encoded + "');" +
                "parent.appendChild(script)" +
                "})()", null));
    }