继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android中Hybrid实战

慕标5832272
关注TA
已关注
手记 1263
粉丝 233
获赞 1008

目录

1、项目中Hybrid整体结构
2、桥接层
3、基础通信层
4、打开离线插件的流程
5、离线插件数据预加载优化

1、我的项目中Hybrid层次结构

webp

我的项目中的Hybrid结构层次

(1)H5页面层。
(2)桥接层:BridgeJs是一个.js文件,是NA和H5通信的桥梁,WebView在加载url之前需要将BridgeJs前置注入。
(3)基础通信层:该层主要由BridgeWebView、BridgeManager、WebPlugin组成,BridgeWebView提供了基本的页面加载,并捕获BridgeJs发送过来的事件交给BridgeManager进行处理;BridgeManager具备BridgeWebView的控制能力,负责处理NA向H5以及H5向NA的消息处理;WebPlugin是离线化插件,为了加速H5页面的展示,可将某个业务的h5、css、js、图片等资源打包,并离线化至本地,在打开相应页面的时候只需获取其对应页面的数据,省去h5、css、js、图片等资源的下载时间。
(4)协议分发层:该层是一个总体的bdwm协议分发器,将收到的协议分发到各个协议实现层进行处理。
(5)协议实现层:该层针对bdwm协议不同的scheme,分别对应不同的实现。NativePageCall用于APP内各个页面的跳转;WebSDKCall是用于为H5提供各种NA能力,WebPluginCall用于打开本地离线化插件。
(6)Native层:该层为客户端App层,为上述几种协议提供能力调用和支持。

2、桥接层

2.1、BridgeJs是什么?

BridgeJs是一个.js文件,是NA和H5通信的桥梁,具体来说就是H5调用NA能力或者打开NA页面必须通过调用BridgeJs中的方法来通知NA,NA也必须调用BridgeJs中的方法来给H5页面发送消息。

2.2、BridgeJs的注入方式

WebView注入BridgeJs文件的方式为,先将该文件读入内存作为BridgeJs,Android4.4以前通过loadUrl("javascript:" + BridgeJs)进行注入,BridgeJS注入完毕后,在JS函数尾部通过onConsoleMessage向NA发起通知,标记注入完毕的事件;4.4后的版本,可使用evaluateJavascript (String script, ValueCallback<String> resultCallback)方法注入并实现回调,注入完成后可向对应H5页面种入NA基本信息,供H5使用并调用H5中Ready方法触发H5页面渲染。

3、 基础通信层

3.1、BridgeWebView

由WebView+TitleBar+ProgressBar构成,ProgressBar根据onProgressChanged(WebView view, int newProgress)显示当前页面加载进度,避免页面加载时无状态,TitleBar支持多种主题,为H5提供三种UI操作元素(返回按钮,标题,功能按钮);WebView是作为H5页面的容器,在加载页面的同时,也负责捕获页面消息和注入JS。

3.2、BridgeManager

通过重写shouldOverrideUrlLoading(WebView view, String url),将收到的重定向url交给BridgeManager去拦截,BridgeManager通过调用SchemeDispatcher. onDispatch(String url)的去处理消息;如果BridgeWebView主动向H5发送消息,则通过BridgeManager执行相应的javascript方法。

3.3、 WebPlugin

3.3.1、离线插件整体思路

webp

离线插件整体思路.png

(1)、运营平台上传打包好的离线插件;
(2)、server端发下离线插件配置;
(3)、App端根据server下发配置下载和更新离线插件。

(2.1)、离线插件包括html、css、js、img和config.json文件。
config.json文件是插件配置文件,记录插件包含的页面及其页面路径,是一段json数据,例如:

webp

config文件

(3.1)、server端下发离线插件配置包括一个allMd5值和一个plugin_list插件列表,外层的md5表示所有插件zip包共同计算的总md5值,用于和本地总md5对比,判断是否有插件要更新。plugin_list中每个插件包含plugin_id,url和md5,plugin_id唯一标识该插件,并作为data/data/package name/WMPlugins/目录下插件的路径名,url为插件下载地址,md5为插件zip包的md5值,用于判断当前插件是否需要更新及下载完成后校验该包的完整性。

离线插件分为正常更新和紧急更新:

3.3.2离线插件的正常更新

webp

离线插件正常更新.png

(1)首先检测当前是否有更新任务队列正在运行,如果有,则直接返回;
(2)检测接口返回的allMD5值与本地sharedPreferences记录的上次成功更新的总md5值是否相同,如果相同,则直接返回,否则继续;

(3)为每个plugin配置更新任务PluginUpdateTask,然后放到线程池中执行,且所有的Task及其状态被记录在一个HashMap<String, PluginUpdateState>中,用于判断是否所有的插件都更新完成并且成功;

(4)PluginUpdateTask实现单个插件的更新流程:先检查本地相同pluginId的md5是否与新的相同,若相同,则直接返回True,否则,依次执行插件下载、md5完整性校验、删除旧插件、解压,最后将该插件新的md5值记录到本地。(每个插件下载成功或者失败都将其状态记录到HashMap<String, PluginUpdateState>中);

(5)检测是否所有的插件更新完成并且成功,如果是,则将allMd5值记录到本地,否则等待下次更新或者紧急更新。

3.3.3、离线包紧急更新

Plugin紧急更新用于一些极端case,在某些场景下,用户点击进入离线插件,可能会遭遇打开失败(例如插件被清理,上一次更新异常等),这种情况下,需要根据插件的pluginId,为该plugin开启独立的插件下载任务,且不与正常的更新检测任务耦合。流程如下:

webp

离线插件紧急更新

(1)插件启动失败,进入BridgeWebView页,显示loading;

(2)根据pluginId,查找内存中的PluginBean,若找到,则直接开始下载,若未找到,则重新拉取离线插件接口,获取PluginBean,

(3)为PluginBean配置PluginEmergencyTask,放到线程池中开启紧急下载任务,复用单个插件下载逻辑下载该插件。(不同的是此时不需要对该plugin新的md5值和本地md5只校验,因为如果是该插件正常情况下下载成功,但是被删除,校验md5值会直接返回,无法下载该插件);

(4)若下载成功则重新打开该拆件,否则,关闭页面,并提示失败。

4、打开离线插件的流程:

webp

打开离线插件的流程

一个打开plugin的bdwm协议是这样的:
demo://plugin?pluginId=xxx&pageName=xxx

(1)根据pluginId,获取该插件的目录pluginDir,一般为/data/data/package name/pluginId
(2)进入插件目录,找到config.json文件,并将其读取为WebPluginConfigModel;
(3)根据的pageName,可以查找到对应页面的pagePath;
(4)通过BridgeWebView打开本地页面"file://" + pluginDir + pageFilePath + "?" + query。

5、离线插件数据预加载优化

为了进一步加快离线包的页面显示速度,提出了离线包预加载数据,webview打开一个url之前,发起一个本地网络请求去请求即将打开的h5页面的数据。

1、预加载H5页面的前提:

在离线包的config.json文件中为需要预加载的页面添加预加载数据PreloadRequest,主要包含预加载的url,请求方法,请求参数等。

2、H5离线插件页面预加载数据流程如下:

webp



作者:小红军storm
链接:https://www.jianshu.com/p/cbec93b4d502


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP