Android WebChromeClient下实现javaScript和Android互调

作者:陆金龙    发表时间:2024-02-25 04:55   

关键词:  

==========================1.js实现==========================
var nativeUtils={};
 
nativeUtils.CallBackMethods = new Hashtable();
 
//js调用本地函数
nativeUtils.invoke = function () {
  var methodid = arguments[0] + (new Date()).getTime() + parseInt(Math.random() * 1000);
  var nativearg = "native:" + arguments[0] + "@" + methodid + "(";
  var arg = [];
  for (var i = 1; i < arguments.length; i++) {//从1开始,因为0是要调用的
   if (typeof (arguments[i]) == "function") {
       this.CallBackMethods.add(methodid, arguments[i]);//缓存回调函数(键值对)
       arg.push(methodid);//将回调函数替换成 与回调函数相关联的一个字符串值(缓存的键)
   }
   else {
       arg.push(arguments[i]);//存放其他参数(回调函数外的)
    }
  }
  nativearg += JSON.stringify(arg) + ")";//native:ScanCode@ScanCode147131232131207819("[\"扫一扫添加\",\"ScanCode147131232131207819\"]")
  console.debug(nativearg);
}
//由本地回调js函数
nativeUtils.CallFromNative= function (methodid, args) {
    var func = this.CallBackMethods.items(methodid);//存缓存取出函数
    if (typeof (func) == "function") {
        func.apply(func, args);
    }
    this.CallBackMethods.remove(methodid);//移除缓存
}
// 定义js函数来调用本地函数的
nativeUtils.ScanCode = function (title,callback) {
    this.invoke("ScanCode",title,callback);
}
 
=========================2.Android实现===========================
public class MyBrowserClient extends WebChromeClient {
    WebView webview;
    @Override
    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
        Pattern p = Pattern.compile("native:(.*?)@(.*?)\\((.*?)\\)");
        Matcher matcher = p.matcher(msg);
        if (matcher.matches())
        {
            String func = matcher.group(1);//本地方法名
            String methodid = matcher.group(2);//回调函数名
            String args = matcher.group(3);//调用本地方法的参数
            CallNativeMethod(func,methodid,args);   
         }
        return super.onConsoleMessage(consoleMessage);
    }
    //调用的实现
    public static void CallNativeMethod(String func, String methodid ,String args )
    {
         MyJsInterface jsobj = (MyJsInterface) webview.GetJsInterface();
         JSONArray array = new JSONArray();
         try {
            array = new JSONArray(args);//参数从json字符串还原
          } catch (Exception err) {
                err.printStackTrace();
         }
         Method[] methods = jsobj.getClass().getMethods();
         for (Method m : methods) {
             //检查是否有@JavascriptInterface标签
             boolean isannotationed = false;
             Annotation[] annotations = m.getDeclaredAnnotations();
             for (Annotation a : annotations) {
                 if (a instanceof JavascriptInterface) {
                        isannotationed = true;
                        break;
                 }
             }
                if (!isannotationed) {
                    continue;
            }
            //查找到对应的方法
            if (m.getName().equals(method)) {
                Class[] argtypes = m.getParameterTypes();
                if (array.length() == argtypes.length)  //函数的参数个数必须一致
                {
                    try {
                      List<Object> callargs = new ArrayList<Object>();
                      for (int i = 0; i < array.length(); i++) {//准备参数
                          if (array.get(i) == JSONObject.NULL) {
                             callargs.add(null);
                            } else {
                             callargs.add(array.get(i));
                           }
                      }
                      Object ret = m.invoke(jsobj, callargs.toArray());//调用本地方法     
        if (!m.getReturnType().equals(Void.TYPE)) {
                           RunPlatformCallBack(methodid, ret);//这里是有返回值立即回调,也可以后续需要时回调
                      }
                      } catch (Exception err) {
                           Log.e("CallNativeMethod", err.getMessage());
                      }
                     break;
                    }
                }
            }
    }
    //回调的实现
    public static void RunPlatformCallBack(String func, Object args) {
        String jsonStr = null;
        if (args instanceof JSONArray || args instanceof JSONObject) {
            jsonStr = args.toString();
        } else {
            JSONArray jsonobj = new JSONArray();
            jsonobj.put(args);
            jsonStr = jsonobj.toString();
        }
        String jsfunc = String.format("nativeUtils.CallFromNative('%s',%s)", func, jsonStr);
        webview.loadUrl(String.format("javascript:%s", jsfunc));
    }
 
=============================3.测试==============================
//测试调用
nativeUtils.ScanCode("扫一扫添加",function(scanedText){
    alert("扫描到的文本:"+scanedText);
});