在Android开发中,可以通过webView的addJavascriptInterface方法注入一个对象到网页中。但是随着开发的需求越来越多。这个对象身上的方法也越来越多。这个对象对应的java类,体积越来越大,不利于维护。为了在不影响之前代码的基础上。把之前的方法调用,比如 api1.methodA(paramB) 的形式通过js中的代理功能转化为 api2.callProxy(‘methodA’,paramB) 的形式。
这样在api2对应的java类中就可以使用反射或者其他方法,动态的查找需要调用的本地方法。就可以将原来api1对应的类拆解,利于后期维护.
对应的js代码
(function () {
try {
const originalObject = {
};
const handler = {
get(target, property, receiver) {
// 这里可以拦截所有对属性的访问,包括方法
console.log(`Accessing property: ${property}`);
// 检查属性是否存在
if (!(property in target)) {
// 如果方法不存在,创造它,保存起来
target[property] = function (param) {
if (typeof (window['trsAppJsBridgeProxy']) == 'object') {
window['trsAppJsBridgeProxy'].callProxy(property, param);
}
console.log("调用方法,名称为" + property + " 参数为:" + param);
}
}
return target[property];
}
};
// 使用Proxy创建一个新对象,它将对原始对象的所有操作委托给handler
const proxyObject = new Proxy(originalObject, handler);
window.trsAppJSBridge = proxyObject;
console.log("注入trsAppJSBridge成功");
return true;
} catch (e) {
console.log("注入trsAppJSBridge失败,error=" + e);
return false;
}
})()
对应的java代码
package com.trs.nmip.common.ui.base.web;
import android.util.Log;
import android.webkit.JavascriptInterface;
import com.tencent.smtt.sdk.WebView;
/**
*
* Created by zhuguohui
* Date: 2024/4/24
* Time: 14:15
* Desc:
*
*/
public class TrsJsProxy {
private static final String injectJS = "(function () {\n" +
" \n" +
" try {\n" +
" const originalObject = {\n" +
"\n" +
" };\n" +
"\n" +
" const handler = {\n" +
" get(target, property, receiver) {\n" +
" // 这里可以拦截所有对属性的访问,包括方法 \n" +
" console.log(`Accessing property: ${property}`);\n" +
"\n" +
" // 检查属性是否存在 \n" +
" if (!(property in target)) {\n" +
" // 如果方法不存在,创造它,保存起来 \n" +
" target[property] = function (param) {\n" +
" if (typeof (window['trsAppJsBridgeProxy']) == 'object') {\n" +
" window['trsAppJsBridgeProxy'].callProxy(property, param);\n" +
" }\n" +
" console.log(\"调用方法,名称为\" + property + \" 参数为:\" + param);\n" +
" }\n" +
"\n" +
" }\n" +
" return target[property];\n" +
" }\n" +
" };\n" +
"\n" +
" // 使用Proxy创建一个新对象,它将对原始对象的所有操作委托给handler \n" +
" const proxyObject = new Proxy(originalObject, handler);\n" +
"\n" +
" window.trsAppJSBridge = proxyObject;\n" +
"\n" +
" console.log(\"注入trsAppJSBridge成功\");\n" +
" return true;\n" +
" } catch (e) {\n" +
" console.log(\"注入trsAppJSBridge失败,error=\" + e);\n" +
" return false;\n" +
" }\n" +
"})()\n";
private static final String NAME = "trsAppJsBridgeProxy";
public static void rejectToWebView(WebView webView) {
webView .evaluateJavascript(injectJS, s -> {
Log.i("zzz", "onReceiveValue: s="+ s);
webView.addJavascriptInterface(new TrsJsProxy(),NAME);
});
}
public TrsJsProxy() {
}
@JavascriptInterface
public void callProxy(String methodName,String param){
Log.d("zzz", "callProxy() called with: methodName = [" + methodName + "], param = [" + param + "]");
}
}
为了实现对原来网页中的js调用的无缝切换,需要在原来网页js执行之前,注入上面的内容。需要在WebViewClient 的onPageStarted 方法中执行
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView webView, String s, Bitmap bitmap) {
super.onPageStarted(webView, s, bitmap);
TrsJsProxy.rejectToWebView(webView);
}
}