Android SDK注入JS至WebView时,Cordova8 SystemWebView的setWebViewClient异常
解决Cordova 8下WebView注入JavaScript的问题
我太懂你遇到的这个坑了——在普通Android WebView上顺顺当当的JS注入逻辑,到了Cordova 8的org.apache.cordova.engine.SystemWebView直接失效。核心问题就出在这个WebView子类重写了setWebViewClient()方法,它强制要求使用自家的SystemWebViewClient子类,你直接塞自定义的WebViewClient要么被拒绝,要么会冲掉Cordova的原有逻辑,两边都乱套。
下面给你两个靠谱的解决方案:
方案一:顺着Cordova的规则来——继承SystemWebViewClient
既然Cordova卡着必须用它的WebViewClient子类,那我们就按它的规矩办,继承SystemWebViewClient包装原有逻辑,再插进去自己的注入代码:
// 假设你已经通过枚举UI拿到了目标SystemWebView实例 SystemWebView cordovaWebView = (SystemWebView) targetWebView; // 自定义WebViewClient,继承Cordova的SystemWebViewClient class CustomCordovaWebClient extends SystemWebViewClient { private final SystemWebViewClient originalClient; private final String injectScript; public CustomCordovaWebClient(SystemWebEngine engine, SystemWebViewClient originalClient, String injectScript) { super(engine); this.originalClient = originalClient; this.injectScript = injectScript; } @Override public void onPageFinished(WebView view, String url) { // 先执行Cordova原有Client的onPageFinished,保证应用原有功能正常 if (originalClient != null) { originalClient.onPageFinished(view, url); } // 执行你的JS注入 view.evaluateJavascript(injectScript, null); // 别忘了调用父类方法 super.onPageFinished(view, url); } } // 获取Cordova原来的WebViewClient SystemWebViewClient originalClient = cordovaWebView.getSystemWebViewClient(); // 创建自定义Client并设置 CustomCordovaWebClient customClient = new CustomCordovaWebClient( cordovaWebView.getEngine(), originalClient, "console.log('注入的JS代码执行啦');" ); cordovaWebView.setWebViewClient(customClient);
这个方案的好处是完全兼容Cordova的原有逻辑,不会破坏Cordova应用的正常运行,属于最稳妥的做法。
方案二:用动态代理Hook原有WebViewClient
如果不想替换整个WebViewClient,也可以用反射+动态代理的方式,在原有Client的onPageFinished方法执行前后插入你的注入逻辑:
WebView targetWebView = ...; // 你的目标WebView实例 WebViewClient originalClient = targetWebView.getWebViewClient(); final String injectScript = "console.log('注入的JS代码执行啦');"; // 创建动态代理对象 WebViewClient proxyClient = (WebViewClient) Proxy.newProxyInstance( WebViewClient.class.getClassLoader(), new Class[]{WebViewClient.class}, (proxy, method, args) -> { // 先执行原Client的方法 Object result = method.invoke(originalClient, args); // 判断是否是onPageFinished方法 if ("onPageFinished".equals(method.getName()) && args.length == 2) { WebView view = (WebView) args[0]; // 执行JS注入 view.evaluateJavascript(injectScript, null); } return result; } ); // 设置代理后的Client targetWebView.setWebViewClient(proxyClient);
⚠️ 注意:如果Cordova的setWebViewClient方法做了严格的类型校验(比如只允许SystemWebViewClient实例),这个方案会抛出IllegalArgumentException,此时优先选方案一。
额外小提醒
- 尽量用
evaluateJavascript()代替loadUrl("javascript:..."),前者是Android 4.4+的推荐方式,更安全还支持回调。 - 如果要注入的JS代码很长,建议把代码放在assets目录,读取后再注入,避免字符串拼接的麻烦。
内容的提问来源于stack exchange,提问作者leon karabchesvky
相关产品推荐
相关产品推荐

