美文网首页还不错WebViewandroid技术专栏
最好用的跨平台Js bridge新秀-DSBridge 安卓篇

最好用的跨平台Js bridge新秀-DSBridge 安卓篇

作者: lazydu | 来源:发表于2017-01-03 18:51 被阅读3557次

    DSBridge是目前地球上最好的IOS/Android javascript bridge.

    DSBridge-IOS:https://github.com/wendux/DSBridge-IOS

    DSBridge-Android:https://github.com/wendux/DSBridge-Android

    与WebViewJavascriptBridge的对比请移步 DSBridge VS WebViewJavascriptBridge

    DSBridge名称的由来:DSBridge是DSpider项目使用的 javascript bridge, 分离自
    五分钟了解DSBridge

    Web端

    假设Native端实现了两个api: testSyn、testAsyn。参数以json传递, testSyn为同步api,执行结束后会直接返回结果,而testAsyn为一个异步api(可能会执行耗时操作),执行结束后,结果异步返回。下面我们看看web端如何调用。

    Javascript调用Native

    var bridge = getJsBridge();
    var str=bridge.call("testSyn", {msg: "testSyn"});
    bridge.call("testAsyn", {msg: "testAsyn"}, function (v) {
      alert(v);
    })
    

    简单到不用解释!太优雅了。如果你体会不来,你也许应该去看看当今(马上将会成为历史)人气最高的WebViewJavascriptBridge ,相信你看完之后会回来的。虽说简单,但为了让你了然于胸,还是给出官方解释:

    getJsBridge

    功能:获取javascript bridge对象。

    等等,貌似和我之前使用的其他库不一样,难道不需要像WebViewJavascriptBridge那样先声明一个setupWebViewJavascriptBridge的回调?你有这种疑问很正常,先给出答案:不需要,DSBridge不需要前端任何安装代码,随用随取。DSBridge的设计原则就是:让三端使用方式都是最简单的! DSBridge获取bridge时,不依赖任何回调,也无需等待页面加载结束。ps: 这在ios>=8,android>sdk19上测试都没问题, DSBridge也对ios7.0-8.0,android sdk16-19之间的版本做了兼容,但是考虑到测试覆盖面的问题,建议所有代码都在dom ready之后执行。

    bridge.call(method,[args,callback])

    功能:调用Native api

    method: api函数名

    args:参数,类型:json, 可选参数

    callback(String returnValue):仅调用异步api时需要.

    同步调用

    如果你是一名经验丰富的开发者,想必看到第二行时已然眼睛一亮,想想node最被诟病的是什么,目前跨平台的jsbridge中没有一个能支持同步,所有需要获取值的调用都必须传一个回调,如果调用逻辑比较复杂,必将会出现“callback hell”。然而,DSBridge彻底改变了这一点。支持同步是DSBridge的最大亮点之一

    异步调用

    对于一些比较耗时的api, DSBridge提供了异步支持,正如上例第三行代码所示,此时你需要传一个回调(如果没有参数,回调可作为第二个参数),当api完成时回调将会被调用,结果以字符串的形式传递。

    供Native调用Javascript api

    假设网页中要提供一个函数test供native调用,只要将函数声明为全局函数即可:

    function test(arg1,arg2){
      return arg1+arg2;
    }
    

    如果你的代码是在一个闭包中,将函数挂在window上即可:

    window.test=function(arg1,arg2){
        return arg1+arg2;
    }   
    

    这样一来端上即可调用。

    Android端

    实现Api

    API的实现非常简单,只需要将您要暴漏给js的api放在一个类中,然后统一注册即可。

    public class JsApi{
        @JavascriptInterface
        String testSyn(JSONObject jsonObject) throws JSONException {
            return jsonObject.getString("msg") + "[syn call]";
        }
        @JavascriptInterface
        void testAsyn(JSONObject jsonObject, CompletionHandler handler) throws JSONException {
            handler.complete(jsonObject.getString("msg")+" [asyn call]");
        }
    }
    

    testSyn为同步api, js在调用同步api时会等待native返回,返回后js继续往下执行。

    testAsyn为异步api, 异步操作时调用handler.complete通知js,此时js中设置的回调将会被调用。

    为了安全起见,所有可供js调用的api必须添加@JavascriptInterface标注

    注册Api

    DWebView webView= (DWebView) findViewById(R.id.webview);
    webView.setJavascriptInterface(new JsApi());
    webView.loadUrl("xx");
    

    请使用sdk中的DWebView,它在实现了js bridge的同时,还提供了一些其它的api.

    第二句即为注册代码。

    调用Javascript

    DWebView提供了三个api用于调用js

    void callHandler(String method, Object[] args) 
    void callHandler(String method, Object[] args, CompletionHandler handler)
    void evaluateJavascript(String script)
    

    前两个api中,method 为函数名,args为参数数组,可以接受String 、int 、long、float、double等。

    第一个api用于调用没有返回值的js函数,没有参数时传null即可。

    第二个api用于需要返回值的场景,需要传递一个CompletionHandler接口对象,在complete(String returnValue)方法中处理返回值即可。

    第三个api用于执行任意js代码,内部已做版本兼容处理。

    调用时机

    DWebview只有在javascript context初始化成功后才能正确执行js代码,而javascript context初始化完成的时机一般都比整个页面加载完毕要早,随然DSBridge能捕获到javascript context初始化完成的时机,但是一些js api可能声明在页面尾部,甚至单独的js文件中(请务必不要这么做),如果在javascript context刚初始化完成就调用js api, 此时js api 可能还没有加载,所以会失败,综上所述,如果是客户端主动调用 js应该在onPageFinished后调用。简单的示例如下:

    webView.setWebViewClient(new WebViewClient(){
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            //期望返回值
            webView.callHandler("test",new Object[]{1,"hello"},new CompletionHandler(){
                @Override
                public void complete(String retValue) {
                    Log.d("jsbridge","call succeed,return value is "+retValue);
                }
            });
            //不期望返回值
            webView.callHandler("test",null);
        }
    });
    

    DWebview更多

    DWebview中下列函数会在主线程中执行,您不必在手动切换线程

    void loadUrl( String url) 
    void loadUrl(final String url, Map<String, String> additionalHttpHeaders)
    void evaluateJavascript(String script) 
    

    DWebview已经实现 alert、prompt、comfirm对话框,您可以不做处理,也可以自定义。值得一提的是js 在调用alert函数正常情况下只要用户没有关闭alert对话框,js代码是会阻塞的,但是考虑到alert 对话框只有一个确定按钮,也就是说无论用户关闭还是确定都不会影响js代码流程,所以DWebview中在弹出alert对话框时会先给js返回,这样一来js就可以继续执行,而提示框等用户关闭时在关闭即可。如果你就是想要阻塞的alert,可以自定义。而DWebview的prompt、comfirm实现完全符合ecma标准,都是阻塞的。

    补充:拉票了,如果你喜欢,欢迎去github star一下,顶一下哦,多谢支持! https://github.com/wendux/DSBridge-Android

    相关文章

      网友评论

      • 程序猿tx:你好,请问 js 调用onclick 方法 怎把值 传给 java 端的,

        js端 调用方法 ,比如想把 "11111" 的值传到java端
        function callAsyn() {
        dsBridge.call("testAsyn","11111", function (v) {
        })
        }

        java端如下:

        JsApi jsApi = new JsApi();
        jsApi.testAsyn("", new CompletionHandler<String>() {
        @Override
        public void complete(String retValue) {
        Log.i("》》》》》》 "," retValue====== "+retValue);
        }

        @Override
        public void complete() {

        }

        @Override
        public void setProgressData(String value) {

        }
        });
        dwebView.addJavascriptObject(jsApi, null);

        不知道java 在哪里去接收数据的
      • 清风流苏:仔细分析了作者的源码,发现所谓的异步调用完全是个幌子。包括Java端和Js端都是没有异步调用的。全部都是同步调用,只不过返回值一个是直接返回,一个是通过一个回调返回。
        清风流苏:@lazydu 大家理解不一样,不过库提供了带回调的接口就为实现异步调用创造了条件
        lazydu:@清风流苏 库提供了回调就可以实现异步逻辑了,具体的异步逻辑应该由用户自己去实现(是否要开新线程),还有异步的概念和线程并不是强相关的,并不是异步就得单开线程,node中一个线程也是异步的一把好手。
        清风流苏:在Android 4.2之上,接口是通过JavascriptInterface调用的,会运行在Android的子线程,如果是Android4.2之下,通过拦截prompt实现,这个方法就是运行域主线程,并且源码中也没有另外开线程池来运行,所以。。。
      • 阳光下的狐狸:看介绍说:getJsBridge的功能是获取javascript bridge对象。网页那边getJsBridge()提示undefined getJsBridge()这个方法,那不是就获取不到javascript bridge对象么? 还是网页那边需要配置一些东西? 有点不理解
        lazydu:@阳光下的狐狸 getJsBridge在页面的onload事件之后调用
      • 强某某:在android5.0包括以下,报Could not find method android.webkit.WebChromeClient.onPermissionRequest, referenced from method wendu.dsbridge.DWebView$2.onPermissionRequest
        然后导致的结果就是,5.0包括以下的手机和模拟器无法找到js方法,当然这是我根据log推测的,求帮助呀
        阳光下的狐狸:h5那边如何写连接桥,就是getJsBridge(); 具体是什么? 没搞过H5 不懂啊。。
        强某某:@lazydu 谢谢啦
        lazydu:@强某某
        This callback only added in API level 21
      • 山顶洞洞人:JAVA循环把值返回给JS怎么弄?比如JS调用JAVA的一个下载方法,JAVA方法要不停的返回下载进度给JS。
        lazydu:@山顶洞洞人 js中定义一个方法来处理下载进度,然后通过webview callhanlder将下载进度作为参数多次调用这个js方法
      • 强某某:省了我很多事,写一个重度js和java交互的app,ios,android,js都是我写,所以,这样统一之后,js不需要写两套了。但是,自定义alert怎么操作呢,能不能麻烦下,说的详细点,谢谢啦
        强某某:@lazydu 请问,ios版本的支持swift吗
        lazydu:自定义alert的方法和原生的webview、wkwebview相同,ps:UIWebview本身不支持自定义alert.
      • 不爱编码的蝎子:这只是解决了通信,但是如何处理路由呢。
      • uncochen:不错,技术实现起来不难,关键是H5那边配不配合:sleepy:
        lazydu: @uncochen 可以通用 DSBridge同时支持Android/Ios
        uncochen:@杜文 但是与Ios 不能通用吧,我们现在用的url 重定向。不是大公司哦,不过沟通起来也还是会有一些问题
        lazydu: @uncochen DSBridge前端调用这么简单 根本没什么成本 大公司的吧😏
      • 13871066fc58:我一直没有用过连接桥 用的是addJavaScript做的h5交互. 也看过好多webbridge框架 但是要用这个连接桥好像h5那边需要按照连接桥的思路写代码? 我看不懂h5代码 但是看javascipt代码那边也是有关于桥的代码
        lazydu: @13871066fc58 就是给js提供了一个调用原生方法的js入口,DSBridge不像其它jsbridge那么麻烦,它只有一个call方法,非常简单的。
      • 845df15a4fe7:看起来很好用的样子,已经star+fork.研究一下。如果可以,能不能用于生产。
        lazydu: @包恒 欢迎研究,欢迎使用😄
      • 宗仁:我发现原生调用JavaScript的次数很少,大部分都是网页调用原生,这种情况可以通过打开链接的方式,不需要任何第三方库
        已经star,持续关注中
        lazydu:@宗仁 GB级太夸张了,可以给上10k的数据测测。需要返回值的情况还是很多的,当然视看具体业务而定。 还有,如果不是自定义scheme这种方式,我还真没见过,麻烦给一个网易云音乐的相关实现链接,我没有找到。
        宗仁:@杜文 其实我说的1.不是url scheme,类似网易云音乐这种方式应该能解决大部分需求,前提是从一开始就是这么设计的。2.这种肯定咩办法了,需要原生返回结果的(定位之类的)。3.浏览器url长度和原生url限制目测并没有关系,如果是webview的话,url应该是没有限制的吧,至少GB级别的。4.打开链接的方式如果是一开始定义好的,可以参考网易云音乐,我认为设计的非常不错。需要返回值的情况,就像我说的,算是比较少的,这种情况就得靠你说的这种bridge了
        总之我觉得你这种跨平台的想法非常不错 :+1:
        lazydu: @宗仁 首先多谢啦😄。关于你的问题,如果用自定义urlscheme的方式,考虑如下几个问题 1.有返回值的情况下native要如何返回值?2.如果调用的是耗时的原生api,如何异步返回结果? 3.如果js要给native传递大量数据呢?(浏览器url一般都有长度限制) 4.打开链接的方式是兼容吗? iOS和Android需不需要一个完善清晰的接口标准?如参数怎么传递,结果如何返回?同步怎么处理?异步怎么处理?。解析scheme的方式难道就真的简单吗?其实 DSBridge Android端本身代码很少,但却很好的解决了这些问题。
      • lazydu:大家喜欢的话,欢迎去github star一下,非常感谢😄

      本文标题:最好用的跨平台Js bridge新秀-DSBridge 安卓篇

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