safe-java-js-webview-bridge
safe-java-js-webview-bridge copied to clipboard
我把你的JsCallJava.java修改了一下,这样使用起来更加灵活:(你可以参考一下)
我把你的JsCallJava.java修改了一下,这样使用起来更加灵活:(你可以参考一下)
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;
}
}
🙄