目录
1、项目中Hybrid整体结构
2、桥接层
3、基础通信层
4、打开离线插件的流程
5、离线插件数据预加载优化
1、我的项目中Hybrid层次结构
我的项目中的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、离线插件整体思路
离线插件整体思路.png
(1)、运营平台上传打包好的离线插件;
(2)、server端发下离线插件配置;
(3)、App端根据server下发配置下载和更新离线插件。
(2.1)、离线插件包括html、css、js、img和config.json文件。
config.json文件是插件配置文件,记录插件包含的页面及其页面路径,是一段json数据,例如:
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离线插件的正常更新
离线插件正常更新.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开启独立的插件下载任务,且不与正常的更新检测任务耦合。流程如下:
离线插件紧急更新
(1)插件启动失败,进入BridgeWebView页,显示loading;
(2)根据pluginId,查找内存中的PluginBean,若找到,则直接开始下载,若未找到,则重新拉取离线插件接口,获取PluginBean,
(3)为PluginBean配置PluginEmergencyTask,放到线程池中开启紧急下载任务,复用单个插件下载逻辑下载该插件。(不同的是此时不需要对该plugin新的md5值和本地md5只校验,因为如果是该插件正常情况下下载成功,但是被删除,校验md5值会直接返回,无法下载该插件);
(4)若下载成功则重新打开该拆件,否则,关闭页面,并提示失败。
4、打开离线插件的流程:
打开离线插件的流程
一个打开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离线插件页面预加载数据流程如下:
作者:小红军storm
链接:https://www.jianshu.com/p/cbec93b4d502
共同学习,写下你的评论
评论加载中...
作者其他优质文章