android与js的交互

 

        最近比较忙,同时也一直都在做关于android与js分享的准备,今天这篇文章主要是为了记录这段时间,对android与js的交互做的研究。

       1:讲讲为什么要有js与android之间的交互

随着科技的快速发展,很多公司都会对移动产品进行快速的迭代开发,降低开发的成本,来适应市场的需求。

有人说js会替代android原生的应用,因为js的跨平台,前端只要通过开发h5页面就能很快的在移动手机中展示,达到需求的效果。 

的确,js开发确实能降低不少的劳动成本,同时不需要在发现bug的时候发版本,带来良好的bug修复效果。但是在某些方面,还是不及原生的效果好,

那么android原生和js通常使用的场景是什么呢?我认为在功能性比较强的地方或者流畅度要求比较高的地方,我们会建议用android原生开发,在更换频率比较高的地方,会采用js开发,这样不仅满足来我们经常更换的需求,同时对流畅度也能有一定的保障。

    2:android与js交互的方法

     webView.loadUrl ( "javascript:callJS()" );这是android很早以前就有的一种调用js的方法,调用简单,但是缺点就是没有返回值,所以在4.4版本以后,又有了一个新的方法

webView.evaluateJavascript ( "javascript:callJsByEvaluateJavascript()" , new ValueCallback < String > ( ) {
    @Override
    public void onReceiveValue ( String value ) {
        Toast.makeText ( getApplicationContext ( ) , value , Toast.LENGTH_LONG ).show ( );
    }
} );

这个方法最主要的作用就是能够同时获取js的返回值,

  3:js与android的交互

   js调用的方法其实有很多,在4.2版本之前,android值只要添加

webSettings.setJavaScriptEnabled ( true );
webView.addJavascriptInterface ( new AndroidJs ( ) , "test" );//AndroidtoJS类对象映射到js的test对象

默认情况下webview中js是不能调用android中的代码的,我们需要手动的设置javascritpenable=true,同时把android中的AndroidJs对象以test的名字映射到webview中,通过上面的2行代码,就能够在h5页面通过test名字调用AndroidJs中的方法,但是因为java中存在反射,我们可以获取android的对象反射出所有的方法,所以在老版本中会存在漏洞。

在android4.2版本以上,google修复这个bug,也就是js只能调用有注解@JavascriptInterface注解的方法,这样一来,即使java中有反射,都不能反射调用android中没有@JavascriptInterface的方法了,修复了老版本中的漏洞。

@JavascriptInterface注解的方法是google官方推荐的方法,但是为了兼容老版本,同时防止有漏洞的情况,很多人都想到了其他的js调用android的方法,比如shouldOverrideUrlLoading当设置了

WebViewClient的时候,点击了h5页面上的某个链接的时候,webview的shouldOverrideUrlLoading就会被调用,凭着这个思路,android又产生了一个新的js点用android的方法,只需要在js调用android的时候,约定url链接,比如bridge://fareware/driver,这样一来,android只要解析这个url,就能获取到js传给android的参数,执行相应的动作。

这其实也是一种js调用android的方法,那么在探索js调用android有没有更好的方法的时候,还有一种,那就是在js中调用alert,prompt,confirm的时候,webview的下面某个方法就会被调用

webView.setWebChromeClient ( new WebChromeClient ( ) {
    @Override
    public boolean onJsPrompt ( WebView view , String url , String message , String defaultValue , JsPromptResult result ) {
        System.out.print ( "Url--->" + url + ":message-->" + message );
        result.confirm ( "js调用了Android的方法成功啦" );
        return true;
    }

    @Override
    public boolean onJsAlert ( WebView view , String url , String message , JsResult result ) {
        return super.onJsAlert ( view , url , message , result );
    }

    @Override
    public boolean onJsConfirm ( WebView view , String url , String message , JsResult result ) {
        return super.onJsConfirm ( view , url , message , result );
    }
} );

这三个方法中其中一个方法就会被调用,那我们也可以通过拦截这三个方法来进行js与android的交互。

以上就是讲解了android与js的相互交互,那么在了解了它们的交互之后,我们来看看一般的第三方框架是怎么实现android与js之间的交互的呢?看一下jsbridge.js,

由于对js不是很熟,所以在把jsbridge引入到android中的时候,遇到了几个坑,比如说我其实并没有导入这个js,但却能够正常的执行,第一个想到的是在android代码初始化的时候回去自动下载?但是我并没有添加网络的权限,所以这个猜测不合理,那么会不会在android的jar中存在,我就去看了android studio中的jar,找到这个jar

android与js的交互

也并没有看到有js,所以当时就很奇怪,,然后就进到了.gradle目录里面查看,里面有个aar包,解压缩之后,发现里面有个js文件,突然发现原来aar文件在android studio中是显示不出来的。。。

接下来来分析下jsbridge是怎么实现android与js的交互的

首先看上图  android有上面几个类

BridgeHandler:java端注册是时候需要

BridgeWebView:调用js的地方,存放了注册的callback,分析解析的url

BridgeWebViewClient:拦截js的调用

CallBackFunction:用来生成message,回调js

Message:保存基本的信息的类

   js的话主要是一个

WebViewJavascriptBridge.js

主要包含这些方法

android与js的交互

下面我们以js调用android为例来说明

1:首先在webview初始化的时候,会通过loadUrl把WebViewJavascriptBridge挂载到webview中,所以能通过window.WebViewJavascriptBridge调用到里面的方法,比如callHandler。

2:android端通过registerHandler注册一个handler,比如说是registerHandler("takePhone",takePhoneHandler);

3:js点击按钮,调用callHandler,传入参数,比如callHandler("takePhone",jsData,jsCallBack);

4:生成一个callBackId,responseCallBacks[callBackId]=jsCallBack; 并把传入的参数保存在一个messageQueue中;

5:调用messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;

6:android通过shouldOverrideUrlLoading进行拦截,解析,知道js的messageQueue中有消息

7:生成一个callBackFunction,调用 loadUrl(javascript:WebViewJavascriptBridge._fetchQueue());并且保存callbackFunction

8:通过 bizMessagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);把参数回调给android

9:android解析后,获取callbackFunction进行回调,通过js传入的takePhone取出android中保存的takePhoneHandler进行执行,

执行完成后组装一个callback,传入callBackId和takePhoneHandler处理的结果,回到给js

这样整个过程就结束了

通过上面的分析,你觉得这个框架怎么样呢?

我对于这个jsbridge的看法, 首先优点是封装的比较方便, java端和js端的代码写起来都更加方便了.
可以改进的地方第一点就是java调用js可以分api版本使用loadUrl()或者evaluateJavascript()方法.

第二点是js调用java我更喜欢在onJsPrompt()中回调.

第三点就是来回的交互流程太多了, 感觉可以再简化一些, 比如可以在第一次就将js给java的数据传递过去的, 而现在第一次传递过去的只是个标记而已。

第四点是使用这个jsbridge必须要使用BridgeWebview, BridgeWebview是继承自系统的Webview的,但是有的时候我们用的是腾讯的x5webview.