至今为止做过的项目里,H5和android的通信都是一个个方法写好,用注解标识,然后互相调用,而且还都写在同一个地方,甚至有些没把WebView放到另一个进程中去,而且方法多了,显得特别臃肿和混乱。之前写过一个可跨进程的WebView框架,经过学习之后做出了改进。虽然还有很多可优化的点,这就算先记录下来吧
Github传送门
框架结构图
各个类之间的关系就是这样,调用流程也差不多就是这样
使用方法
创建一个Commond指令
一个指令为一个方法,又或者你可以创建一个通用指令,再或者你可以进行封装都可以。
这里通过打开一个Activity的简单指令来介绍
- 首先,一个指令必须继承Command并实现两个方法,
CommandName
和执行方法
(指令名称要和H5端保持一致的) - 其次使用
AutoService
注解去标志他属于 Command.class,方便后续查找(AutoService可通过自定义注解替代) - 参数callback属于AIDL文件,如果有数据回调可以使用,没有可以不用管
执行一个指令
指令在android端创建,接着等着H5端来调用我们的方法
- 如下,H5端想调用上面创建的指令,只需要在方法中,传入指令名称'openActivity'和message参数,android端就可以在本地指令集中找到对应指令,并根据message执行相应操作
这样看起来是不是清爽很多?只有一个个指令,可以写到同一个文件中,也可以分开一个个写,甚至可以单独创建一个module去专门存放指令,我是感觉比一个方法一个@JavascriptInterface注解清爽了不少
Web调用Main的分析
首先原理是使用了AIDL,但是这里就不对AIDL进行阐述了。网上已经有很多优秀的文章了。 不过为了方便理解,就先这样简单的认为吧
- AIDL 就是中间人,接口
- Stub 实现方,实现AIDL中的方法
- Proxy 就是遥控器,拿到该对象就能调用AIDL里定义的方法了
AIDL就好比一个菜单,里面有定义好的菜名。 Proxy遥控器就可以根据AIDL菜单去点菜。 Stub 就像一个厨师,你点的菜,最终AIDL会告诉Stub,让他去做具体实现
还是先来看看两个AIDL文件吧
两个AIDL文件
- IWebviewProcessToMainProcessInterface
(简称IWebToM)
这个AIDL简单,里面只有一个方法,并且接受三个参数
分别是 指令名称,携带的参数,和另一个AIDL对像
- ICallbackFromMainprocessToWebViewProcessInterface
(简称CallbackMToWeb)
这个也很简单,就是一个回调函数的名称,和一个回调的数据
入口takeNativeAction
这是H5调用android方法的入口,可以看到将传递过来的数据转换成JsParam.class后,就直接交给WebCommandDispatcher处理了
WebCommandDispatcher 遥控器
可以看到 WebCommandDispatcher 中存放了一个IWebToM对象,并且启动了Service
接着通过 IWebToM.Stub.asInterface(service) 方法就能得到 AIDL的Proxy对象,拿到遥控器
也就是说 WebCommandDispatcher 就可以执行IWebToM定义的方法了
也就是调用Proxy对象中的 handleWebCommand 方法
MainCommandsManager Stub实现类
可以看到,是直接继承IWebToM.Stub的,并且之前使用的 AutoService 注解在这里也会用到,
她会帮我们收集通过 AutoService 打上了 Command
标志的类,然后保存起来
然后遥控器调用方法时,就会调用到我们复写的方法,然后在收集到的Command指令集中查找,找到对应指令执行方法
Main回调Web的分析
我们知道回调是通过CallbackMToWeb这个AIDL对象来完成的,那么谁是遥控器,谁是实现类呢?
CallbackMToWeb的实现类
回到WebCommandDispatcher中的方法,可以看到,在调用IWebToM的方法时,就已经传入了一个CallbackMToWeb实现类
按照上面的流程,这个Stub实现类,就会一直传递给某个具体指令,然后调用就会回到onResult方法,而方法中直接将回调的数据交给了 webView 处理, 这样就完成了Main到Web的回调了
CallbackMToWeb的遥控器在哪里
是不是全程没看到通过 Stub.asInterface 方法拿到遥控器,既然他能调用起来,就说明内部帮我们做了转换呗。
那我们就进入到AIDL中,系统帮我们生成CallbackMToWeb文件,直接点击就能找到他的调用处
是在系统帮我们生成的IWebToM文件中,handleWebCommand调用时,会帮我们生成一个Proxy对象,然后再传递出去,所以说但我们传递到某个具体指令时,就已经是Proxy对象了,这样整个流程才能走得通
结尾
这个框架只是简单框架,因为总是忘记思路,所以做一下记录。还有很多地方是可以优化的,欢迎在评论区指出交流~