美文网首页还不错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