美文网首页
mui框架下的js和安卓原生交互的实现方式

mui框架下的js和安卓原生交互的实现方式

作者: 怀念小兔 | 来源:发表于2018-12-05 17:16 被阅读619次

    因为工作需要,研究了一下这方面的内容,官方文档写的很笼统,我觉得我有必要记录一下这个过程。

    背景

    为什么需要跟原生交互?其实mui是有在线打包的,在hbuilder里选择在线打包就可以生成apk,但是有些时候有特殊需求,比如我们需要调用一些只有java sdk的第三方服务,那就需要采用离线打包的方式,用java语言去调用第三方java sdk,再通过js调用java代码。

    实现方式

    其实这里有两种解决方案,一种是通过native.js来一个个加载原生类,再按java的写法调用,但是这样效率很低,加载每个原生类都会带来不小的性能开销,本文介绍的也不是这个。另一种方式就是通过5+runtime的js bridge调用自定义的java插件,我们来细说这种方式。

    首先,本盗图狗盗官网一张图吧:


    技术架构

    依赖关系是从上向下,所以我们先从底层讲起。

    Native部分

    1.编写插件类

    首先,我们在安卓离线打包工程里新建一个类继承io.dcloud.common.DHInterface.StandardFeature,这个类来自lib.5plus.base-release.aar,也就是5+runtime,然后在这个类中写实例方法,方法名可以随便取,只要js调用时跟这个一致就可以,但是参数是固定的,第一个参数是IWebView类型,代表调用这个原生方法的js所在的webview,第二个参数是JSONArray类型,它是js调用时传入的参数列表。

        /**
         * 同步调用原生的方法
         * @param webview 调用这个原生方法的js所在的webview
         * @param json js调用时传入的参数列表
         * @return 返回给js的值
         * */
        public String testFunctionSync(IWebview webview, JSONArray json){
            Log.e(TAG, String.format("webview = %s, jsonArray = %s", webview, json));
            Log.e(TAG, String.format("thread name = %s, id = %s", Thread.currentThread().getName(), Thread.currentThread().getId()));
            webview.evalJS("(function(){alert('webview.evalJS')})();");
            return JSUtil.wrapJsVar("reply from custom plugin");
        }
        /**
         * 异步调用原生的方法
         * @param webview 调用这个原生方法的js所在的webview
         * @param json js调用时传入的参数列表
         * */
        public void testFunctionAsync(IWebview webview, JSONArray json){
            try {
                Log.e(TAG, String.format("webview = %s, jsonArray = %s", webview, json));
                Log.e(TAG, String.format("thread name = %s, id = %s", Thread.currentThread().getName(), Thread.currentThread().getId()));
                Thread.sleep(3000);
                String callbackId = json.getString(0);
                String resultMsg = "after 3 seconds,the function return";
                JSUtil.execCallback(webview, callbackId, resultMsg, JSUtil.OK, false);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    

    作为一个原生程序员,提到同步异步,我首先就会想它在安卓里是哪个线程,所以加上了线程信息的Log,经运行得知,同步调用的方法在安卓中是在名为JavaBridge的线程中运行,而异步调用的方法则是在主线程里运行的。所以,同步调用的方法可以直接执行耗时操作,异步执行的方法里要执行耗时操作必须另起线程,否则在操作执行完之前,页面都是卡住的状态,搞不好就ANR了。
    这里顺便提一下,既然原生方法能拿到webview对象,那就可以不按套路出牌做很多事了,呵呵。如果两边不是一个公司开发的话,还真存在安全问题。这个不多考虑了

    2.注册插件

    在assets/data/dcloud_properties.xml中的features节点下新建以下节点

    <feature name="customPlugin" value="com.gopha.qxtandroidwrapper.CustomPlugin"/>
    

    这里的name是插件名,value是对应类的全名(带包名)。注册完之后,native部分就搞定了。

    bridge部分

    bridge中的东西是5+runtime提供的,我们只要会用就行了,主要就是这么三个方法:

        /**
         * 同步调用原生方法
         * @param service 插件名
         * @param action 方法名
         * @param args 传递参数列表
         * @return 原生方法的返回值
         * */
         String plus.bridge.execSync( String service, String action, Array<String> args );
        /**
         * 异步调用原生方法
         * @param service 插件名
         * @param action 方法名
         * @param args 传递参数列表
         * */
         void plus.bridge.exec( String service, String action, Array<String> args );
         /**
         * 获得回调id
         * @param onSuccess 成功时的回调函数
         * @param onFailed 失败时的回调函数
         * */
         String plus.bridge.callbackId(Function onSuccess, Function onFailed)
    

    同步方法是有返回值的,而异步方法的返回值则是通过回调函数传递,所以其中第三个方法只有在异步调用的时候才会需要。

    js部分

    js部分没什么多说的,直接上代码:

        //同步调用原生方法                  
        nativeSync:function(){
            //调用customPlugin插件的testFunctionSync方法,传递了两个参数,分别是James和Tracy
            //用result变量接收返回值
            var result = plus.bridge.execSync("customPlugin", "testFunctionSync", ["James", "Tracy"]);
            alert(result);
            console.log(result);
            alert(JSON.stringify(plus.bridge));
        },
        //异步调用原生方法
        nativeAsync: function(){
            var bridge = plus.bridge;
            var success = function(msg){
                alert("onSuccess,msg = " + msg);
            };
            var failed = function(msg){
                alert("onFailed,msg = " + msg);
            }
            //获取回调的id
            var callbackId = bridge.callbackId(success, failed);
            //注意,这里要跟原生开发的人定好回调id在参数列表中的索引位置
            plus.bridge.exec("customPlugin", "testFunctionAsync", [callbackId, "secondParam"]);
        }
    

    相关文章

      网友评论

          本文标题:mui框架下的js和安卓原生交互的实现方式

          本文链接:https://www.haomeiwen.com/subject/iidwcqtx.html