Android中Hybrid实战

作者: 小红军storm | 来源:发表于2018-11-18 16:34 被阅读0次

    目录

    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离线插件页面预加载数据流程如下:

    H5离线插件数据预加载

    打开预加载h5页面的url一般是
    demo://plugin?pluginId=xxx&pageName=xxx&requestPreload=true

    (1)首先根据pluginId从对应插件的config配置文件中读取相应页面的预加载数据PreloadRequest。

    (2)根据预加载数据PreloadRequest中的url,请求方法,请求参数等利用本地okhttp框架构建一个网络请求,去获取数据。

    (3)当数据获取成功,如果jsbridge注入完成,则调用其回调方法PreloadFinish,将获取到的数据传递给h5页面;如果jsbridge未注入完成,则将获取的数据缓存到内存,待jsbridge注入完成,在其注入完成的回调中,调用h5页面的回调方法PreloadFinish将数据传递给h5页面。h5页面收到数据后,并可根据数据去填充页面。

    注:我们用一个boolean的变量标记jsbridge是否注入完成,jsbridge注入完成,会有一个回调,我们可以在回调中将这个变量置位true,标记注入完成。

    相关文章

      网友评论

        本文标题:Android中Hybrid实战

        本文链接:https://www.haomeiwen.com/subject/mkydfqtx.html