在打开网页就是之前需要注入一段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));
}