Closed CLovinr closed 8 years ago
我把你的代码改了一下,用起来会更加灵活:(你可以参考一下) new MyInjectedChromeClient(new JsCallJava.InjectObj("myjs.ui", MyJs.class), new JsCallJava.InjectObj("myjs.ui2", MyJs2.class,MyJs3.class,MyJs4.class));
package cn.pedant.SafeWebViewBridge;
import android.text.TextUtils; import android.webkit.WebView; import android.util.Log;
import com.google.gson.Gson;
import org.json.JSONArray; import org.json.JSONObject;
import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap;
public class JsCallJava { private final static String TAG = "JsCallJava"; private final static String RETURN_RESULT_FORMAT = "{\"code\": %d, \"result\": %s}"; private HashMap<String, Method> mMethodsMap; /////<private String mInjectedName;>///// private String mPreloadInterfaceJS; private Gson mGson;
/////< public static class InjectObj { String namespace; Class<?>[] interfaceClasses; public InjectObj(String namespace, Class<?>... interfaceClasses) { if (TextUtils.isEmpty(namespace)) { throw new RuntimeException("namespace can not be null!"); } this.namespace = namespace; this.interfaceClasses = interfaceClasses; } } /////> public JsCallJava(InjectObj... injectObjs) { try { mMethodsMap = new HashMap<String, Method>(); StringBuilder sbuilder = new StringBuilder("javascript:"); for (InjectObj injectObj : injectObjs) { injectOne(sbuilder, injectObj); } mPreloadInterfaceJS = sbuilder.toString(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("init js error:" + e.getMessage()); } } private void injectOne(StringBuilder sbuilder, InjectObj injectObj) { String mInjectedName = injectObj.namespace; StringBuilder sb = new StringBuilder("(function(b){console.log(\"");/////去掉前面的javascript:////// sb.append(mInjectedName); sb.append( " initialization begin\");var a={"); sb.append("namespace:\"").append(mInjectedName).append("\",");//////添加一个namespace/////// sb.append("queue:[],callback:function(){var d=Array.prototype.slice.call" + "(arguments,0);var c=d.shift();var e=d.shift();this.queue[c].apply(this,d);if(!e){delete " + "this.queue[c]}}};"); //////////////< for (Class<?> c : injectObj.interfaceClasses) { searchClass(sb, c); } StringBuilder namespaces = new StringBuilder(); { StringBuilder temp = new StringBuilder(); String[] ss = injectObj.namespace.split("\\."); for (String s : ss) { if ("".equals(s)) { continue; } else { temp.append(".").append(s); namespaces.append("b").append(temp).append("=").append("b").append(temp).append("||{};"); } } } ///////////> sb.append("function(){var f=Array.prototype.slice.call(arguments,0);if(f.length<1){throw\""); sb.append(mInjectedName); sb.append( " call error, message:miss method name\"}var e=[];for(var h=1;h<f.length;h++){var c=f[h];var " + "j=typeof c;e[e.length]=j;if(j==\"function\"){var d=a.queue.length;a.queue[d]=c;" + "f[h]=d}}var g=JSON.parse(prompt(JSON.stringify({method:f.shift(),types:e,args:f"); sb.append(",namespace:a.namespace");/////////加入namespace///////// sb.append("})));if(g" + ".code!=200){throw\""); sb.append(mInjectedName); sb.append( " call error, code:\"+g.code+\", message:\"+g.result}return g.result};Object.getOwnPropertyNames" + "(a).forEach(function(d){var c=a[d];if(typeof c===\"function\"&&d!==\"callback\")" + "{a[d]=function(){return c.apply(a,[d].concat(Array.prototype.slice.call(arguments,0)))" + "}}});"); sb.append(namespaces);//////////加入,如:b.ui={};b.ui.abc={}; sb.append("b.").append(mInjectedName); sb.append("=a;console.log(\""); sb.append(mInjectedName); sb.append(" initialization end\")})(window);"); ///////// sbuilder.append(sb); //////// } private void searchClass(StringBuilder sb, Class<?> c) { /////个人建议还是用getMethods,这样可以不用把所有的static函数都挤在一个类里,而可以把一部分放在父类中.////// Method[] methods = c.getMethods(); for (Method method : methods) { String sign; if (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (sign = genJavaMethodSign( method)) == null) { continue; } mMethodsMap.put(sign, method); sb.append(String.format("a.%s=", method.getName())); } } private String genJavaMethodSign(Method method) { String sign = method.getName(); Class[] argsTypes = method.getParameterTypes(); int len = argsTypes.length; if (len < 1 || argsTypes[0] != WebView.class) { Log.w(TAG, "method(" + sign + ") must use webview to be first parameter, will be pass"); return null; } for (int k = 1; k < len; k++) { Class cls = argsTypes[k]; if (cls == String.class) { sign += "_S"; } else if (cls == int.class || cls == long.class || cls == float.class || cls == double.class) { sign += "_N"; } else if (cls == boolean.class) { sign += "_B"; } else if (cls == JSONObject.class) { sign += "_O"; } else if (cls == JsCallback.class) { sign += "_F"; } else { sign += "_P"; } } return sign; } public String getPreloadInterfaceJS() { return mPreloadInterfaceJS; } public String call(WebView webView, String jsonStr) { if (!TextUtils.isEmpty(jsonStr)) { try { JSONObject callJson = new JSONObject(jsonStr); String mInjectedName = callJson.getString("namespace");//////得到namespace/////// String methodName = callJson.getString("method"); JSONArray argsTypes = callJson.getJSONArray("types"); JSONArray argsVals = callJson.getJSONArray("args"); String sign = methodName; int len = argsTypes.length(); Object[] values = new Object[len + 1]; int numIndex = 0; String currType; values[0] = webView; for (int k = 0; k < len; k++) { currType = argsTypes.optString(k); if ("string".equals(currType)) { sign += "_S"; values[k + 1] = argsVals.isNull(k) ? null : argsVals.getString(k); } else if ("number".equals(currType)) { sign += "_N"; numIndex = numIndex * 10 + k + 1; } else if ("boolean".equals(currType)) { sign += "_B"; values[k + 1] = argsVals.getBoolean(k); } else if ("object".equals(currType)) { sign += "_O"; values[k + 1] = argsVals.isNull(k) ? null : argsVals.getJSONObject(k); } else if ("function".equals(currType)) { sign += "_F"; values[k + 1] = new JsCallback(webView, mInjectedName, argsVals.getInt(k)); } else { sign += "_P"; } } Method currMethod = mMethodsMap.get(sign); // 方法匹配失败 if (currMethod == null) { return getReturn(jsonStr, 500, "not found method(" + sign + ") with valid parameters"); } // 数字类型细分匹配 if (numIndex > 0) { Class[] methodTypes = currMethod.getParameterTypes(); int currIndex; Class currCls; while (numIndex > 0) { currIndex = numIndex - numIndex / 10 * 10; currCls = methodTypes[currIndex]; if (currCls == int.class) { values[currIndex] = argsVals.getInt(currIndex - 1); } else if (currCls == long.class) { //WARN: argsJson.getLong(k + defValue) will return a bigger incorrect number values[currIndex] = Long.parseLong(argsVals.getString(currIndex - 1)); } else { values[currIndex] = argsVals.getDouble(currIndex - 1); } numIndex /= 10; } } return getReturn(jsonStr, 200, currMethod.invoke(null, values)); } catch (Exception e) { //优先返回详细的错误信息 if (e.getCause() != null) { return getReturn(jsonStr, 500, "method execute error:" + e.getCause().getMessage()); } return getReturn(jsonStr, 500, "method execute error:" + e.getMessage()); } } else { return getReturn(jsonStr, 500, "call data empty"); } } private String getReturn(String reqJson, int stateCode, Object result) { String insertRes; if (result == null) { insertRes = "null"; } else if (result instanceof String) { result = ((String) result).replace("\"", "\\\""); insertRes = "\"" + result + "\""; } else if (!(result instanceof Integer) && !(result instanceof Long) && !(result instanceof Boolean) && !(result instanceof Float) && !(result instanceof Double) && !(result instanceof JSONObject)) { // 非数字或者非字符串的构造对象类型都要序列化后再拼接 if (mGson == null) { mGson = new Gson(); } insertRes = mGson.toJson(result); } else { //数字直接转化 insertRes = String.valueOf(result); } String resStr = String.format(RETURN_RESULT_FORMAT, stateCode, insertRes); ////////Log.d(TAG, mInjectedName + " call json: " + reqJson + " result:" + resStr); return resStr; }
}
我把你的代码改了一下,用起来会更加灵活:(你可以参考一下) new MyInjectedChromeClient(new JsCallJava.InjectObj("myjs.ui", MyJs.class), new JsCallJava.InjectObj("myjs.ui2", MyJs2.class,MyJs3.class,MyJs4.class));
package cn.pedant.SafeWebViewBridge;
import android.text.TextUtils; import android.webkit.WebView; import android.util.Log;
import com.google.gson.Gson;
import org.json.JSONArray; import org.json.JSONObject;
import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap;
public class JsCallJava { private final static String TAG = "JsCallJava"; private final static String RETURN_RESULT_FORMAT = "{\"code\": %d, \"result\": %s}"; private HashMap<String, Method> mMethodsMap; /////<private String mInjectedName;>///// private String mPreloadInterfaceJS; private Gson mGson;
}