Android JSBridge的原理与实现

在Android中,JSBridge已经不是什么新鲜的事物了,各家的实现方式也略有差异。大多数人都知道WebView存在一个漏洞,见WebView中接口隐患与手机挂马利用,虽然该漏洞已经在Android 4.2上修复了,即使用@JavascriptInterface代替addJavascriptInterface,但是由于兼容性和安全性问题,基本上我们不会再利用Android系统为我们提供的addJavascriptInterface方法或者@JavascriptInterface注解来实现,所以我们只能另辟蹊径,去寻找既安全,又能实现兼容Android各个版本的方案。

首先我们来了解一下为什么要使用JSBridge,在开发中,为了追求开发的效率以及移植的便利性,一些展示性强的页面我们会偏向于使用h5来完成,功能性强的页面我们会偏向于使用native来完成,而一旦使用了h5,为了在h5中尽可能的得到native的体验,我们native层需要暴露一些方法给js调用,比如,弹Toast提醒,弹Dialog,分享等等,有时候甚至把h5的网络请求放着native去完成,而JSBridge做得好的一个典型就是微信,微信给开发者提供了JSSDK,该SDK中暴露了很多微信native层的方法,比如支付,定位等。

那么,怎么去实现一个兼容Android各版本又具有一定安全性的JSBridge呢?我们知道,在WebView中,如果java要调用js的方法,是非常容易做到的,使用WebView.loadUrl(“javascript:function()”)即可,这样,就做到了JSBridge的native层调用h5层的单向通信,但是h5层如何调native层呢,我们需要寻找这么一个通道,仔细回忆一下,WebView有一个方法,叫
setWebChromeClient,可以设置WebChromeClient对象,而这个对象中有三个方法,分别是onJsAlert,onJsConfirm,onJsPrompt,当js调用window对象的对应的方法,即window.alert,window.confirm,window.prompt,WebChromeClient对象中的三个方法对应的就会被触发,我们是不是可以利用这个机制,自己做一些处理呢?答案是肯定的。

至于js这三个方法的区别,可以详见w3c JavaScript 消息框 。一般来说,我们是不会使用onJsAlert的,为什么呢?因为js中alert使用的频率还是非常高的,一旦我们占用了这个通道,alert的正常使用就会受到影响,而confirm和prompt的使用频率相对alert来说,则更低一点。那么到底是选择confirm还是prompt呢,其实confirm的使用频率也是不低的,比如你点一个链接下载一个文件,这时候如果需要弹出一个提示进行确认,点击确认就会下载,点取消便不会下载,类似这种场景还是很多的,因此不能占用confirm。而prompt则不一样,在Android中,几乎不会使用到这个方法,就是用,也会进行自定义,所以我们完全可以使用这个方法。该方法就是弹出一个输入框,然后让你输入,输入完成后返回输入框中的内容。因此,占用prompt是再完美不过了。

到这一步,我们已经找到了JSBridge双向通信的一个通道了,接下来就是如何实现的问题了。本文中实现的只是一个简单的demo,如果要在生产环境下使用,还需要自己做一层封装。

要进行正常的通信,通信协议的制定是必不可少的。我们回想一下熟悉的http请求url的组成部分。形如http://host:port/path?param=value,我们参考http,制定JSBridge的组成部分,我们的JSBridge需要传递给native什么信息,native层才能完成对应的功能,然后将结果返回呢?显而易见我们native层要完成某个功能就需要调用某个类的某个方法,我们需要将这个类名和方法名传递过去,此外,还需要方法调用所需的参数,为了通信方便,native方法所需的参数我们规定为json对象,我们在js中传递这个json对象过去,native层拿到这个对象再进行解析即可。为了区别于http协议,我们的jsbridge使用jsbridge协议,为了简单起见,问号后面不适用键值对,我们直接跟上我们的json字符串,于是就有了形如下面的这个uri

<code class="hljs cs has-numbering" style="display: block; 
    padding: 0px; 
    color: inherit; 
    box-sizing: border-box; 
    font-family: 'Source Code Pro', monospace;
    font-size:undefined; 
    white-space: pre; 
    border-radius: 0px; 
    word-wrap: normal; 
    background: transparent;">jsbridge:
        <span class="hljs-comment" 
        style="color: rgb(136, 0, 0); 
        box-sizing: border-box;">//className:port/methodName?jsonObj
        </span>
</code>
<ul class="pre-numbering" style="box-sizing: border-box; 
    position: absolute; 
    width: 50px; 
    top: 0px; 
    left: 0px; 
    margin: 0px; 
    padding: 6px 0px 40px; 
    border-right-width: 1px; 
    border-right-style: solid; 
    border-right-color: rgb(221, 221, 221); 
    list-style: none; 
    text-align: right; 
    background-color: rgb(238, 238, 238);">
        <li style="box-sizing: border-box; 
            padding: 0px 5px;">1
        </li>
</ul>

有人会问,这个port用来干嘛,其实js层调用native层方法后,native需要将执行结果返回给js层,不过你会觉得通过WebChromeClient对象的onJsPrompt方法将返回值返回给js不就好了吗,其实不然,如果这么做,那么这个过程就是同步的,如果native执行异步操作的话,返回值怎么返回呢?这时候port就发挥了它应有的作用,我们在js中调用native方法的时候,在js中注册一个callback,然后将该callback在指定的位置上缓存起来,然后native层执行完毕对应方法后通过WebView.loadUrl调用js中的方法,回调对应的callback。那么js怎么知道调用哪个callback呢?于是我们需要将callback的一个存储位置传递过去,那么就需要native层调用js中的方法的时候将存储位置回传给js,js再调用对应存储位置上的callback,进行回调。于是,完整的协议定义如下:

<code class="hljs cs has-numbering" style="display: block; 
    padding: 0px; 
    color: inherit; 
    box-sizing: border-box; 
    font-family: 'Source Code Pro', monospace;
    font-size:undefined; 
    white-space: pre; 
    border-radius: 0px; 
    word-wrap: normal; 
    background: transparent;">jsbridge:
        <span class="hljs-comment" 
            style="color: rgb(136, 0, 0); 
            box-sizing: border-box;">//className:callbackAddress/methodName?jsonObj
        </span>
</code>
<ul class="pre-numbering" style="box-sizing: 
    border-box; 
position: absolute; 
    width: 50px; 
    top: 0px; 
    left: 0px; 
    margin: 0px; 
    padding: 6px 0px 40px; 
    border-right-width: 1px; 
    border-right-style: solid; 
    border-right-color: rgb(221, 221, 221); 
    list-style: none; 
    text-align: right; 
    background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box; 
           padding: 0px 5px;">1
    </li>
</ul>

假设我们需要调用native层的Logger类的log方法,当然这个类以及方法肯定是遵循某种规范的,不是所有的java类都可以调用,不然就跟文章开头的WebView漏洞一样了,参数是msg,执行完成后js层要有一个回调,那么地址就如下

<code class="hljs ruby has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">
<span class="hljs-symbol" style="color: rgb(0, 102, 102)
     box-sizing: border-box;">jsbridge:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">/Logger:callbackAddress/log</span>?{<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"msg"</span>
<span class="hljs-symbol" style="color: rgb(0, 102, 102)
    box-sizing: border-box;">:<span class="hljs-string" style="box-sizing: border-box
">"native log"</span>
</span>}</code
ul class="pre-numbering" style="box-sizing: border-box;>
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
</ul>


至于这个callback对象的地址,可以存储到js中的window对象中去。至于怎么存储,后文会慢慢倒来。

上面是js向native的通信协议,那么另一方面,native向js的通信协议也需要制定,一个必不可少的元素就是返回值,这个返回值和js的参数做法一样,通过json对象进行传递,该json对象中有状态码code,提示信息msg,以及返回结果result,如果code为非0,则执行过程中发生了错误,错误信息在msg中,返回结果result为null,如果执行成功,返回的json对象在result中。下面是两个例子,一个成功调用,一个调用失败。

<code class="hljs json has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">{ "<span class="hljs-attribute" style="box-sizing: border-box
">code</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">500</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">msg</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"method is not exist"</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">result</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-literal" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">null</span> </span>}</code>
<ul class="pre-numbering" style="box-sizing: border-box
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">2</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">3</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">4</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">5</li>
</ul>



<code class="hljs json has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">{ "<span class="hljs-attribute" style="box-sizing: border-box
">code</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">0</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">msg</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"ok"</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">result</span>":<span class="hljs-value" style="box-sizing: border-box;">{ "<span class="hljs-attribute" style="box-sizing: border-box
">key1</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"returnValue1"</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">key2</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"returnValue2"</span>
</span>, "<span class="hljs-attribute" style="box-sizing: border-box
">key3</span>":<span class="hljs-value" style="box-sizing: border-box;">{ "<span class="hljs-attribute" style="box-sizing: border-box
">nestedKey</span>":<span class="hljs-value" style="box-sizing: border-box;">
<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"nestedValue"</span> <span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"nestedArray"</span>:[<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"value1"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"value2"</span>] </span>} </span>} </span>}</code>
<ul class="pre-numbering" style="box-sizing: border-box
 position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">2</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">3</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">4</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">5</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">6</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">7</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">8</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">9</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">10</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">11</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">12</li>
</ul>


那么这个结果如何返回呢,native调用js暴露的方法即可,然后将js层传给native层的port一并带上,进行调用即可,调用的方式就是通过WebView.loadUrl方式来完成,如下。


<code class="hljs avrasm has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">mWebView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
     box-sizing: border-box;">.loadUrl</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"javascript:JSBridge.onFinish(port,jsonObj)
"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span>
</code
ul class="pre-numbering" style="box-sizing: border-box;>
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
</ul>


关于JsBridge.onFinish方法的实现,后面再叙述。前面我们提到了native层的方法必须遵循某种规范,不然就非常不安全了。在native中,我们需要一个JSBridge统一管理这些暴露给js的类和方法,并且能实时添加,这时候就需要这么一个方法

<code class="hljs avrasm has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">JSBridge<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
     box-sizing: border-box;">.register</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"jsName"</span>,javaClass<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
     box-sizing: border-box;">.class</span>)</code>
<ul class="pre-numbering" style="box-sizing: border-box
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
</ul>

这个javaClass就是满足某种规范的类,该类中有满足规范的方法,我们规定这个类需要实现一个空接口,为什么呢?主要作用就混淆的时候不会发生错误,还有一个作用就是约束JSBridge.register方法第二个参数必须是该接口的实现类。那么我们定义这个接口


<code class="hljs cs has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">
    <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">interface</span> IBridge{ }</code>
<ul class="pre-numbering" style="box-sizing: border-box
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">2</li>
</ul>


类规定好了,类中的方法我们还需要规定,为了调用方便,我们规定类中的方法必须是static的,这样直接根据类而不必新建对象进行调用了(还要是public的),然后该方法不具有返回值,因为返回值我们在回调中返回,既然有回调,参数列表就肯定有一个callback,除了callback,当然还有前文提到的js传来的方法调用所需的参数,是一个json对象,在java层中我们定义成JSONObject对象;方法的执行结果需要通过callback传递回去,而java执行js方法需要一个WebView对象,于是,满足某种规范的方法原型就出来了。


<code class="hljs cs has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">
    <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
    ">methodName</span>(WebView web view,JSONObject jsonObj,Callback callback){ }</code>
<ul class="pre-numbering" style="box-sizing: border-box;
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">2</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">3</li>
</ul>


js层除了上文说到的JSBridge.onFinish(port,jsonObj);方法用于回调,应该还有一个方法提供调用native方法的功能,该函数的原型如下


<code class="hljs cs has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">JSBridge.call(className,methodName,<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">params</span>,callback)</code>
<ul class="pre-numbering" style="box-sizing: border-box
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
</ul>

在call方法中再将参数组合成形如下面这个格式的uri

<code class="hljs cs has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">jsbridge:<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">//className:callbackAddress/methodName?jsonObj</span>
</code
ul class="pre-numbering" style="box-sizing: border-box>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
</ul>


然后调用window.prompt方法将uri传递过去,这时候java层就会收到这个uri,再进一步解析即可。

万事具备了,只欠如何编码了,别急,下面我们一步一步的来实现,先完成js的两个方法。新建一个文件,命名为JSBridge.js


<code class="hljs clojure has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">function</span> <span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">win</span>)</span> <span class="hljs-collection" style="box-sizing: border-box
">{ var hasOwnProperty = Object.prototype.hasOwnProperty<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> var JSBridge = win.JSBridge || <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">win.JSBridge</span> = <span class="hljs-collection" style="box-sizing: border-box
">{}</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> var JSBRIDGE_PROTOCOL = 'JSBridge'<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> var Inner = <span class="hljs-collection" style="box-sizing: border-box;">{ callbacks: <span class="hljs-collection" style="box-sizing: border-box
">{}</span>, call: function <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">obj</span>, method, params, callback)</span> <span class="hljs-collection" style="box-sizing: border-box
">{ console.log<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">obj+</span>
<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">" "</span>+method+<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">" "</span>+params+<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">" "</span>+callback)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> var port = Util.getPort<span class="hljs-list" style="box-sizing: border-box;">()</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> console.log<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">port</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> this.callbacks<span class="hljs-collection" style="box-sizing: border-box;">[port]</span> = callback<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> var uri=Util.getUri<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">obj</span>,method,params,port)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> console.log<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">uri</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> window.prompt<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">uri</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">""</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> }</span>, onFinish: function <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">port</span>, jsonObj)</span>
<span class="hljs-collection" style="box-sizing: border-box
">{ var callback = this.callbacks<span class="hljs-collection" style="box-sizing: border-box;">[port]</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> callback && callback<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">jsonObj</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> delete this.callbacks<span class="hljs-collection" style="box-sizing: border-box;">[port]</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> }</span>, }</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> var Util = <span class="hljs-collection" style="box-sizing: border-box;">{ getPort: function <span class="hljs-list" style="box-sizing: border-box
">()</span> <span class="hljs-collection" style="box-sizing: border-box;">{ return Math.floor<span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">Math.random</span>
<span class="hljs-list" style="box-sizing: border-box
">()</span> *<span class="hljs-number" style="color: rgb(0, 102, 102);
 box-sizing: border-box;"> (1</span> <<<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;"> 30</span>)</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> }</span>, getUri<span class="hljs-attribute" style="box-sizing: border-box;
 color: rgb(0, 102, 102);">:function</span>
<span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">obj</span>, method, params, port)</span>
<span class="hljs-collection" style="box-sizing: border-box
">{ params = this.getParam<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">params</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> var uri = JSBRIDGE_PROTOCOL + '<span class="hljs-attribute" style="box-sizing: border-box;
 color: rgb(0, 102, 102);">://'</span> + obj + '<span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(0, 102, 102);">:'</span> + port + '/' + method + '?' + params<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> return uri<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> }</span>, getParam<span class="hljs-attribute" style="box-sizing: border-box;
 color: rgb(0, 102, 102);">:function</span>
<span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">obj</span>)</span>
<span class="hljs-collection" style="box-sizing: border-box
">{ if <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">obj</span> && typeof obj === 'object')</span> <span class="hljs-collection" style="box-sizing: border-box
">{ return JSON.stringify<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">obj</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> }</span> else <span class="hljs-collection" style="box-sizing: border-box;">{ return obj || ''<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> }</span> }</span> }</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> for <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">
<span class="hljs-built_in" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">var</span>
</span> key in Inner)</span> <span class="hljs-collection" style="box-sizing: border-box
">{ if <span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">!hasOwnProperty.call</span>
<span class="hljs-list" style="box-sizing: border-box
">(<span class="hljs-title" style="box-sizing: border-box;
 color: rgb(102, 0, 102);">JSBridge</span>, key)</span>)</span> <span class="hljs-collection" style="box-sizing: border-box
">{ JSBridge<span class="hljs-collection" style="box-sizing: border-box;">[key]</span> = Inner<span class="hljs-collection" style="box-sizing: border-box
">[key]</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">
</span> }</span> }</span> }</span>)</span>
<span class="hljs-list" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">window</span>)</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span>
</code
ul class="pre-numbering" style="box-sizing: border-box;>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;javascript:void(null)
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">28</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">29</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">30</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">31</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">32</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">33</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">34</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">35</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">36</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">37</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">38</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">39</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">40</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">41</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">42</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">43</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">44</li>
</ul>

可以看到,我们里面有一个Util类,里面有三个方法,getPort()用于随机生成port,getParam()用于生成json字符串,getUri()用于生成native需要的协议uri,里面主要做字符串拼接的工作,然后有一个Inner类,里面有我们的call和onFinish方法,在call方法中,我们调用Util.getPort()获得了port值,然后将callback对象存储在了callbacks中的port位置,接着调用Util.getUri()将参数传递过去,将返回结果赋值给uri,调用window.prompt(uri, “”)将uri传递到native层。而onFinish()方法接受native回传的port值和执行结果,根据port值从callbacks中得到原始的callback函数,执行callback函数,之后从callbacks中删除。最后将Inner类中的函数暴露给外部的JSBrige对象,通过一个for循环一一赋值即可。

当然这个实现是最最简单的实现了,实际情况要考虑的因素太多,由于本人不是很精通js,所以只能以java的思想去写js,没有考虑到的因素姑且忽略吧,比如内存的回收等等机制。

这样,js层的编码就完成了,接下来实现java层的编码。

上文说到java层有一个空接口来进行约束暴露给js的类和方法,同时也便于混淆

<code class="hljs cs has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">interface</span> IBridge { }</code>
<ul class="pre-numbering" style="box-sizing: border-box
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
</ul>


首先我们要将js传来的uri获取到,编写一个WebChromeClient子类。


<code class="hljs java has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box
">
<span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">JSBridgeWebChromeClient</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">WebChromeClient</span> {</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157)
 box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box
">onJsPrompt</span>(WebView view, String url, String message, String defaultValue, JsPromptResult result) { result.confirm(JSBridge.callJava(view, message));
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">true</span>
 } } </code>
<ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
</ul>


之后不要忘记了将该对象设置给WebView


<code class="hljs avrasm has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">WebView mWebView = (WebView) findViewById(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.id</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.webview</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> WebSettings settings = mWebView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68);
 box-sizing: border-box;">.getSettings</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> settings<span class="hljs-preprocessor" style="color: rgb(68, 68, 68);
 box-sizing: border-box;">.setJavaScriptEnabled</span>(true)<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> mWebView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68);
 box-sizing: border-box;">.setWebChromeClient</span>(new JSBridgeWebChromeClient())<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span> mWebView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68);
 box-sizing: border-box;">.loadUrl</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"file:///android_asset/index.html"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span>
</code
ul class="pre-numbering" style="box-sizing: border-box;>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
</ul>


核心的内容来了,就是JSBridgeWebChromeClient中调用的JSBridge类的实现。前文提到该类中有这么一个方法提供注册暴露给js的类和方法


<code class="hljs avrasm has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">JSBridge<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.register</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"jsName"</span>,javaClass<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.class</span>)</code>
<ul class="pre-numbering" style="box-sizing: border-box
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
</ul>


该方法的实现其实很简单,从一个Map中查找key是不是存在,不存在则反射拿到对应的Class中的所有方法,将方法是public static void 类型的,并且参数是三个参数,分别是Webview,JSONObject,Callback类型的,如果满足条件,则将所有满足条件的方法put进去,整个实现如下

<code class="hljs cs has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">class</span> JSBridge { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> Map<String, HashMap<String, Method>> exposedMethods = <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> HashMap<>()
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
">register</span>(String exposedName, Class<? extends IBridge> clazz) { <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (!exposedMethods.containsKey(exposedName)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">try</span> { exposedMethods.put(exposedName, getAllMethod(clazz))
 } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">catch</span> (Exception e) { e.printStackTrace()
 } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> HashMap<String, Method> <span class="hljs-title" style="box-sizing: border-box
">getAllMethod</span>(Class injectedCls) throws Exception { HashMap<String, Method> mMethodsMap = <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">new</span> HashMap<>()
 Method[] methods = injectedCls.getDeclaredMethods();
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">for</span> (Method method : methods) { String name
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (name = method.getName()) == <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">continue</span>
 } Class[] parameters = method.getParameterTypes();
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span> != parameters && parameters.length == <span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">3</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">if</span> (parameters[<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">0</span>] == WebView.class && parameters[<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">1</span>] == JSONObject.class && parameters[<span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">2</span>] == JSCallback.class) { mMethodsMap.put(name, method)
 } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">return</span> mMethodsMap
 } }</code>
<ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">28</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">29</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">30</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">31</li>
</ul>


而至于JSBridge类中的callJava方法,就是将js传来的uri进行解析,然后根据调用的类名别名从刚刚的map中查找是不是存在,存在的话拿到该类所有方法的methodMap,然后根据方法名从methodMap拿到方法,反射调用,并将参数传进去,参数就是前文说的满足条件的三个参数,即WebView,JSONObject,Callback。


<code class="hljs vbscript has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> static <span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">String</span> callJava(WebView webView, <span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">String</span> uriString) { <span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">String</span> methodName = <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">""</span>
 <span class="hljs-built_in" style="color: rgb(102, 0, 102);
 box-sizing: border-box;">String</span> className = <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">""</span>
 <span class="hljs-built_in" style="color: rgb(102, 0, 102);
 box-sizing: border-box;">String</span> param = <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"{}"</span>
 <span class="hljs-built_in" style="color: rgb(102, 0, 102);
 box-sizing: border-box;">String</span> port = <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">""</span>
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (!TextUtils.<span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">isEmpty</span>(uriString) && uriString.startsWith(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"JSBridge"</span>)) { Uri uri = Uri.parse(uriString)
 className = uri.getHost();
 param = uri.getQuery();
 port = uri.getPort() + <span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">""</span>
 <span class="hljs-built_in" style="color: rgb(102, 0, 102);
 box-sizing: border-box;">String</span> path = uri.getPath()
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (!TextUtils.<span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">isEmpty</span>(path)) { methodName = path.<span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">replace</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"/"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">""</span>)
 } } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (exposedMethods.containsKey(className)) { HashMap<<span class="hljs-built_in" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">String</span>, Method> methodHashMap = exposedMethods.<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">get</span>(className)
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (methodHashMap != <span class="hljs-literal" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">null</span> && methodHashMap.size() != <span class="hljs-number" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">0</span> && methodHashMap.containsKey(methodName)) { Method method = methodHashMap.<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">get</span>(methodName)
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (method != <span class="hljs-literal" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">null</span>) { try { method.invoke(<span class="hljs-literal" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">null</span>, webView, <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> JSONObject(param), <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> Callback(webView, port))
 } catch (Exception e) { e.printStackTrace();
 } } } } return <span class="hljs-literal" style="color: rgb(0, 102, 102);
 box-sizing: border-box;">null</span>
 }</code>
<ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">28</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">29</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">30</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">31</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">32</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">33</li>
</ul>


看到该方法中使用了 new Callback(webView, port)进行新建对象,该对象就是用来回调js中回调方法的java对应的类。这个类你需要将js传来的port传进来之外,还需要将WebView的引用传进来,因为要使用到WebView的loadUrl方法,为了防止内存泄露,这里使用弱引用。如果你需要回调js的callback,在对应的方法里调用一下callback.apply()方法将返回数据传入即可,


<code class="hljs cs has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">class</span> Callback { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> Handler mHandler = <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> Handler(Looper.getMainLooper())
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> final String CALLBACK_JS_FORMAT = <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"javascript:JSBridge.onFinish('%s', %s)
"</span>;
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">private</span> String mPort
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">private</span> WeakReference<WebView> mWebViewRef
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box
">Callback</span>(WebView view, String port) { mWebViewRef = <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">new</span> WeakReference<>(view)
 mPort = port;
 } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
">apply</span>(JSONObject jsonObject) { final String execJs = String.format(CALLBACK_JS_FORMAT, mPort, String.valueOf(jsonObject));
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (mWebViewRef != <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span> && mWebViewRef.<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">get</span>() != <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span>) { mHandler.post(<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> Runnable() { @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
">run</span>() { mWebViewRef.<span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">get</span>().loadUrl(execJs)
 } });
 } } } </code>
<ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
</ul>


唯一需要注意的是apply方法我把它扔在主线程执行了,为什么呢,因为暴露给js的方法可能会在子线程中调用这个callback,这样的话就会报错,所以我在方法内部将其切回主线程。

编码完成的差不多了,那么就剩实现IBridge即可了,我们来个简单的,就来显示Toast为例好了,显示完给js回调,虽然这个回调没有什么意义。

<code class="hljs java has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box
">
<span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">BridgeImpl</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box
 color: rgb(102, 0, 102);">IBridge</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
">showToast</span>(WebView webView, JSONObject param, <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">final</span> Callback callback) { String message = param.optString(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"msg"</span>)
 Toast.makeText(webView.getContext(), message, Toast.LENGTH_SHORT).show();
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span> != callback) { <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">try</span> { JSONObject object = <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> JSONObject()
 object.put(<span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">"key"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"value"</span>)
 object.put(<span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">"key1"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"value1"</span>)
 callback.apply(getJSONObject(<span class="hljs-number" style="color: rgb(0, 102, 102);
 box-sizing: border-box;">0</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"ok"</span>, object))
 } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">catch</span> (Exception e) { e.printStackTrace()
 } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">static</span> JSONObject <span class="hljs-title" style="box-sizing: border-box
">getJSONObject</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">int</span> code, String msg, JSONObject result) { JSONObject object = <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">new</span> JSONObject()
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">try</span> { object.put(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"code"</span>, code)
 object.put(<span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">"msg"</span>, msg)
 object.putOpt(<span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">"result"</span>, result)
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">return</span> object
 } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">catch</span> (JSONException e) { e.printStackTrace()
 } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
 box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
 box-sizing: border-box;">null</span>
 } } </code>
<ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">28</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">29</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">30</li>
</ul>


你可以往该类中扔你需要的方法,但是必须是public static void且参数列表满足条件,这样才能找到该方法。

不要忘记将该类注册进去


<code class="hljs avrasm has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">JSBridge<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.register</span>(<span class="hljs-string" style="color: rgb(0, 136, 0)
 box-sizing: border-box;">"bridge"</span>, BridgeImpl<span class="hljs-preprocessor" style="color: rgb(68, 68, 68)
 box-sizing: border-box;">.class</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">
</span>
</code
ul class="pre-numbering" style="box-sizing: border-box;>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
</ul>


进行一下简单的测试,将之前实现好的JSBridge.js文件扔到assets目录下,然后新建index.html,输入

<code class="hljs xml has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-doctype" style="color: rgb(102, 0, 102)
 box-sizing: border-box;">
<!DOCTYPE HTML
/span> <span class="hljs-tag" style="color: rgb(0, 102, 102)>
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">html</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">head</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">meta</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">charset</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"utf-8"</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">title</span>>
</span>JSBridge<span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">title</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">meta</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"viewport"</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">content</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1, user-scalable=no"</span>/>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">src</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"file:///android_asset/JSBridge.js"</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">type</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"text/javascript"</span>>
</span
span class="javascript" style="box-sizing: border-box>
">
</span
span class="hljs-tag" style="color: rgb(0, 102, 102);>
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">script</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">script</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">type</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"text/javascript"</span>>
</span
span class="javascript" style="box-sizing: border-box>
"> </span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">script</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">style</span>>
</span
span class="css" style="box-sizing: border-box>
"> </span>
<span class="hljs-tag" style="color: rgb(0, 102, 102);
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">style</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">head</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">body</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">h3</span>>
</span>JSBridge 测试<span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">h3</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">ul</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"list"</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">li</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">button</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">onclick</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"JSBridge.call('bridge','showToast',{'msg':'Hello JSBridge'},function(res){alert(JSON.stringify(res))})"</span>>
</span> 测试showToast <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">button</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">li</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">br</span>/>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">ul</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">body</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">html</span>>
</span> </code
ul class="pre-numbering" style="box-sizing: border-box>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">3</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">4</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">5</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">6</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">7</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">8</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">9</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">10</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">11</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">12</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">13</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">14</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">15</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">16</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">17</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">18</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">19</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">20</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">21</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">22</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">23</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">24</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">25</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">26</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">27</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">28</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">29</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">30</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">31</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">32</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">33</li>
</ul>


很简单,就是按钮点击时调用JSBridge.call()方法,回调函数是alert出返回的结果。

接着就是使用WebView将该index.html文件load进来测试了


<code class="hljs handlebars has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="xml" style="box-sizing: border-box
">
<span class="hljs-string" style="color: rgb(0, 136, 0);
 box-sizing: border-box;">mWebView.loadUrl("</span>file:<span class="hljs-comment" style="color: rgb(136, 0, 0)
 box-sizing: border-box;">///android_asset/index.html")
</span> </span>
</code
ul class="pre-numbering" style="box-sizing: border-box;>
 position: absolute;
 width: 50px;
 top: 0px;
 left: 0px;
 margin: 0px;
 padding: 6px 0px 40px;
 border-right-width: 1px;
 border-right-style: solid;
 border-right-color: rgb(221, 221, 221);
 list-style: none;
 text-align: right;
 background-color: rgb(238, 238, 238);">
<li style="box-sizing: border-box
 padding: 0px 5px;">1</li>
<li style="box-sizing: border-box
 padding: 0px 5px;">2</li>
</ul>


效果如下图所示


这里写图片描述

可以看到整个过程都走通了,然后我们测试下子线程回调,在BridgeImpl中加入测试方法

<code class="hljs cs has-numbering" style="display: block;
     padding: 0px;
     color: inherit;
     box-sizing: border-box;
     font-family: 'Source Code Pro', monospace;
    font-size:undefined;
     white-space: pre;
     border-radius: 0px;
     word-wrap: normal;
     background: transparent;">
    <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
    ">testThread</span>(WebView webView, JSONObject param, final Callback callback) { <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">new</span> Thread(<span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">new</span> Runnable() { @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box
    ">run</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">try</span> { Thread.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102)
     box-sizing: border-box;">3000</span>)
     JSONObject <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">object</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">new</span> JSONObject()
     <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">object</span>.put(<span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"key"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"value"</span>)
     callback.apply(getJSONObject(<span class="hljs-number" style="color: rgb(0, 102, 102);
     box-sizing: border-box;">0</span>, <span class="hljs-string" style="color: rgb(0, 136, 0)
     box-sizing: border-box;">"ok"</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136)
     box-sizing: border-box;">object</span>))
     } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">catch</span> (InterruptedException e) { e.printStackTrace()
     } <span class="hljs-keyword" style="color: rgb(0, 0, 136);
     box-sizing: border-box;">catch</span> (JSONException e) { e.printStackTrace()
     } } }).start();
     }</code>
<ul class="pre-numbering" style="box-sizing: border-box;
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
        <li style="box-sizing: border-box
         padding: 0px 5px;">1</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">2</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">3</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">4</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">5</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">6</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">7</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">8</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">9</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">10</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">11</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">12</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">13</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">14</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">15</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">16</li>
        <li style="box-sizing: border-box
         padding: 0px 5px;">17</li>
</ul>

在index.html中加入


<code class="hljs xml has-numbering" style="display: block;
 padding: 0px;
 color: inherit;
 box-sizing: border-box;
 font-family: 'Source Code Pro', monospace;
font-size:undefined;
 white-space: pre;
 border-radius: 0px;
 word-wrap: normal;
 background: transparent;">
<span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">ul</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"list"</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">li</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">button</span> <span class="hljs-attribute" style="box-sizing: border-box
 color: rgb(102, 0, 102);">onclick</span>=<span class="hljs-value" style="box-sizing: border-box
 color: rgb(0, 136, 0);">"JSBridge.call('bridge','testThread',{},function(res){alert(JSON.stringify(res))})"</span>>
</span> 测试子线程回调 <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">button</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">div</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">li</span>>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
<<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">br</span>/>
</span> <span class="hljs-tag" style="color: rgb(0, 102, 102)
 box-sizing: border-box;">
</<span class="hljs-title" style="box-sizing: border-box
 color: rgb(0, 0, 136);">ul</span>>
</span
/code>
<ul class="pre-numbering" style="box-sizing: border-box
     position: absolute;
     width: 50px;
     top: 0px;
     left: 0px;
     margin: 0px;
     padding: 6px 0px 40px;
     border-right-width: 1px;
     border-right-style: solid;
     border-right-color: rgb(221, 221, 221);
     list-style: none;
     text-align: right;
     background-color: rgb(238, 238, 238);">
    <li style="box-sizing: border-box
     padding: 0px 5px;">1</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">2</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">3</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">4</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">5</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">6</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">7</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">8</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">9</li>
    <li style="box-sizing: border-box
     padding: 0px 5px;">10</li>
</ul>


理想的效果应该是3秒钟之后回调弹出alert显示

这里写图片描述

很完美,代码也不多,就实现了功能。如果你需要使用到生成环境中去,上面的代码你一定要再自己封装一下,因为我只是简单的实现了功能,其他因素并没有考虑太多。

当然你也可以参考一个开源的实现
Safe Java-JS WebView Bridge

最后还是惯例,贴上代码

http://download.csdn.net/detail/sbsujjbcy/9446915

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容