序言
在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;/*** <pre>* Created by zhuguohui* Date: 2024/4/24* Time: 14:15* Desc:* </pre>*/
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() {}@JavascriptInterfacepublic void callProxy(String methodName,String param){Log.d("zzz", "callProxy() called with: methodName = [" + methodName + "], param = [" + param + "]");}}
调用
为了实现对原来网页中的js调用的无缝切换,需要在原来网页js执行之前,注入上面的内容。需要在WebViewClient 的onPageStarted 方法中执行
webView.setWebViewClient(new WebViewClient() {@Overridepublic void onPageStarted(WebView webView, String s, Bitmap bitmap) {super.onPageStarted(webView, s, bitmap);TrsJsProxy.rejectToWebView(webView);}}