Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

我把你的JsCallJava.java修改了一下,这样使用起来更加灵活:(你可以参考一下) #13

Open
CLovinr opened this issue Mar 5, 2016 · 1 comment

Comments

@CLovinr
Copy link

CLovinr commented Mar 5, 2016

我把你的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;
}

}

@2yunyun
Copy link

2yunyun commented Aug 3, 2016

🙄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants