​​​​​​​Android H5通用容器架构设计详解

目录
  • 背景
  • 术语对齐
  • 探索
    • 如何优雅地提供接口调用?
    • 怎样封装多个不同类型的H5容器容器?
      • 整体架构
      • 通用容器
      • 框架容器
      • 基础组件
  • 这样的架构能带来什么样的好处?

背景

大家如果经历过Hybrid项目的开发,即项目中涉及到H5与Native之间的交互,那么很有可能会遇到各种各样的H5容器。为什么会有那么多各种各样的容器呢...这也是轮子多的通病了,轮子多到业务方不知道选哪个。当然,也有可能大家压根就不会使用到H5容器,直接用系统WebView就完事儿了,比如我的前东家就是这样做的。那这篇文章的主题就是与前者相关的:当项目中拥有很多个H5容器时,怎样封装才能让业务侧用得爽呢?

下面按惯例,抛出这篇文章要解决的三个问题:

  • 如何优雅地提供接口调用?
  • 怎样封装多个不同类型的H5容器?
  • 这样的架构能带来什么样的好处?

术语对齐

术语 描述
H5框架容器 特指目前项目中正在使用的二方/三方H5容器。
H5通用容器 特指将项目中所有的框架容器抽象到一个容器中,让业务侧不需要感知到具体的框架细节。
A页面 url query参数中带a=true的页面,项目中用A容器承载。
B页面 url query参数中带b=true的页面,项目中用B容器承载。

探索

如何优雅地提供接口调用?

业务侧调用的接口其实很有限,可以说90%的业务都只是打开一个网页而已。

我们根据业务需要新建一个接口类:

/**
 * WebPage服务接口类
 */
public interface IWebPageService {
    /**
     * 打开url
     * @param url
     */
    void openUrl(String url);

    /**
     * 创建Fragment内置到某页面中使用
     * @return
     */
    Fragment buildFragment(String url, Context context);

    /**
     * 获取当前Url
     * @return
     */
    String getCurrentUrl();

    /**
     * 给h5发通知
     * @param eventData
     * @param eventName
     */
    void postNotificationToJS(String eventName, String eventData);
}

以上列举了4个非常常见的接口。如果有需要,还可以扩展其它的,比如设置容器生命周期相关的监听、设置H5发通知来时的监听等等。拿openUrl的实现举例,实现类通过url中的参数判断需要打开A容器还是B容器

@Override
public void openUrl(String url) {
     // 若url中含有A参数,则用A容器打开
     // if (urlParamHasA) {
        // startAContainer();
     // } else {
        // 否则用B容器打开
        // startBContainer();
     //}
}

这就从接口层这一层面屏蔽了内部框架容器。其它接口也是类似,原则就是不让业务侧感知到具体的实现细节,而不是跳个页面还需要知道这个url是要用A容器打开还是B容器打开。在应用启动时,可以将实现类注入到公共依赖中去,也可以通过ARouter等框架实现依赖注入,方便业务侧的调用。

怎样封装多个不同类型的H5容器容器?

整体架构

先上一张图:

接口层上面已经讲过了,这里我们直接看容器层。

通用容器

第一层就是我们抽出来的通用容器,WebPageActivity与WebPageFragement。项目中,不管是哪个H5框架容器,势必都是用Activity或者Fragment来承载的,所以我们相应的也需要有这两者作为父类去进行封装。而通用容器中,最重要的职责就是去执行通用逻辑,即每个框架容器都需要执行的逻辑。

通用职责可以有以下几点:

  • 设置页面属性,包括window flag、activity的主题等。
  • 解析url,将url中的关键参数记录下来,从而决定以哪种策略渲染UI。比如可以通过disableNav参数决定是否显示导航栏,通过statusBarStyle参数决定状态栏的风格等。
  • 控制通用UI的渲染,包括何时改变TitleBar、何时加载/隐藏Loading,何时渲染异常态UI等。
  • 决定框架容器加载时的逻辑顺序,如setContentView()->loadUrl()。
  • 接收生命周期事件与系统回调事件,并且分发回调。生命周期就不用说了,系统回调这里特指onActivityResultonRequestPermissionResult这类事件,然后将结果分发给各listener。

WebPageActivity#onCreate举例:

@Override
protected void onCreate(Bundle savedInstanceState) {
    // setWindowFlags(); 设置window属性
    // setTheme(); 设置主题
    // setTransition(); 设置转场动画

    super.onCreate(savedInstanceState);

    // parseUrl(); 解析url
    // initCommonUI(); 渲染通用UI 比如TitleBar、底部导航栏等

    setContentView();
    loadUrl();
}

protected abstract void setContentView();

protected abstract void loadUrl();

我们可以将设置window属性、设置主题这些通用行为放在通用容器中执行,而setContentViewloadUrl交由框架容器去执行。setContentView是因为不同的容器,layout xml可能是不一样的。loadUrl是因为每个容器用WebView去加载url的方式也可能不同,无法统一。类似的行为,若执行时机可统一,则由通用容器统一执行时机,比如setContentViewloadUrl。若时机也没法确定,甚至逻辑只会存在于某个框架容器中,那么就要写到子类中去了。

框架容器

图中第二层的容器A、容器B、容器C指的就是框架容器。有了通用容器承载共同的逻辑后,框架容器需要做的事情就比较少了。只需要加载各自的布局,初始化WebView,然后将url加载到WebView中就可以了(除非有某个框架容器需要特殊适配,那就得写些额外的代码)。具体的实现需要根据项目中框架容器的使用方式来确定。

基础组件

第三层表示基础组件。这里只列一些常见的基础组件。

  • Components:各类UI组件,比如TitleBar与异常态控件。
  • JS Bridge:JS Bridge可以单独放到一个类中做收口,然后分发给各个listener。listenr通过接口层进行注入。
  • WebViewClient:WebViewClient在日常开发中算是维护的非常频繁的一个类,职责主要是在shouldOverrideUrlLoading重定向时对url进行拦截,以及根据相应的生命周期回调(onPageStarted、onPageFinished、onReceviedError等)进行loading或异常态UI的渲染时。若每个框架容器可以设置同一个WebViewClient,那就非常方便了,只要改一处地方,所有容器就都生效了。
  • Interceptors:即用于WebView重定向时的拦截器。像我的项目中会有很多拦截相关的逻辑,比如将A页面拦截跳转到原生页面,就需要在重定向时进行拦截。但逻辑堆叠太多会提高维护的成本,因此建议用责任链模式(没用过的同学可以百度一下,很简单滴~)去处理拦截的这块逻辑。
  • Managers、Listeners:容器中总是需要很多辅助类去来帮助我们去管理一些东西,比如WebView的管理,url的管理。这里就不延伸了,根据实际需要去加。Listener也一样,关于容器生命周期的Listener,与JS Bridge交互相关的Listener,都可以通过接口层去实现注入与销毁。

当然,除此之外,根据每个项目的完整度与负责度,还会衍生出很多基础组件。比如H5的监控体系,H5的预加载体系,以及WebView预创建相关的缓存体系等。他们作为框架容器共同的底座承担相应的职责。

这样的架构能带来什么样的好处?

  • 对业务侧而言,接口统一收口到IWebPageService中去,调用方式更加简单明了,不需要再关注容器的具体类型。
  • 对容器侧而言,代码逻辑性清晰的同时,有效降低了日后的维护成本与开发成本。Loading、异常态不需要再在各类容器中重复写N遍,各种url params都统一收口到通用容器中去,重定向拦截逻辑也不再需要重复写N遍...总而言之,通用逻辑统一给通用容器与基础组件去承担,框架容器的代码,都是各框架容器所“独有”的。

到此这篇关于Android H5通用容器架构设计详解的文章就介绍到这了,更多相关Android H5容器架构内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android Studio打包H5网址页面,封装成APK

    目录 一.下载 AndroidStudio 二.新建项目 三.配置项目 MainActivity WebViewClient AndroidManifest.xml 一.下载 AndroidStudio 自行下载安装,https://developer.android.google.cn/studio/#downloads 二.新建项目 三.配置项目 MainActivity package com.lmm.myapp; import android.support.v7.app.AppComp

  • Android网页H5 Input选择相机和系统相册

    需求: 网页h5的input选择相机和系统相册,并且返回压缩的图片到h5. 代码: 1.WebView代码 package com.zql.sdk; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os

  • android H5本地缓存加载优化的实战

    2020年最后一周,正准备摸摸鱼回家过年,须不知"惊天阴谋"已在领导层酝酿.竖日,组长带着诡异的微笑向我走来: 组长: "快过年了,你回家路途遥远,要不要请两天假?" 我: "组长,你真是我的知己,想我所想,思我所思,你这么一说我就不客气了,那我就请两天" 组长:"行,请假肯定没问题,我一向很照顾兄弟们!!"(那一刻,一股暖流心中而过,早已将这一年他对我的"压榨"抛之脑后) "不过我还有个事跟你说

  • ​​​​​​​Android H5通用容器架构设计详解

    目录 背景 术语对齐 探索 如何优雅地提供接口调用? 怎样封装多个不同类型的H5容器容器? 整体架构 通用容器 框架容器 基础组件 这样的架构能带来什么样的好处? 背景 大家如果经历过Hybrid项目的开发,即项目中涉及到H5与Native之间的交互,那么很有可能会遇到各种各样的H5容器.为什么会有那么多各种各样的容器呢...这也是轮子多的通病了,轮子多到业务方不知道选哪个.当然,也有可能大家压根就不会使用到H5容器,直接用系统WebView就完事儿了,比如我的前东家就是这样做的.那这篇文章的主

  • Android View的事件体系教程详解

    目录 一.什么是View?什么是ViewGroup? 二.View的位置 三.View的触摸事件 1.MotionEvent 2.TouchSlop 3.VelocityTracker 5.Scroller 四.View的滑动 1)使用Scroll 2)通过动画 3)使用延时策略 五.View的事件分发机制 六.View的滑动冲突问题 View的滑动冲突常见可以简单分为三种: 滑动冲突的处理规则 滑动冲突的解决方法 一.什么是View?什么是ViewGroup? View是Android中所有控

  • Android自定义view实现侧滑栏详解

    目录 前言 需求 效果图 编写代码 主要问题 前言 上一篇文章学了下自定义View的onDraw函数及自定义属性,做出来的滚动选择控件还算不错,就是逻辑复杂了一些.这篇文章打算利用自定义view的知识,直接手撕一个安卓侧滑栏,涉及到自定义LayoutParams.带padding和margin的measure和layout.利用requestLayout实现动画效果等,有一定难度,但能重新学到很多知识! 需求 这里类似旧版QQ(我特别喜欢之前的侧滑栏),有两层页面,滑动不是最左侧才触发的,而是从

  • Android Adapter里面嵌套ListView实例详解

    Android Adapter里面嵌套ListView实例详解 前言: 可嵌套~但是显示需要特殊处理下~以下是处理方法 前几天因为项目的需要,要在一个ListView中放入另一个ListView,也即在一个ListView的每个ListItem中放入另外一个ListView.但刚开始的时候,会发现放入的小ListView会显示不完全,它的高度始终有问题.上网查了下,发现别人也有遇到这样的问题,而大多数人都不推荐这样的设计,因为默认情况下Android是禁止在ScrollView中放入另外的Scr

  • Android 中FloatingActionButton(悬浮按钮)实例详解

    Android 中FloatingActionButton(悬浮按钮)实例详解 一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 二.使用准备, 在as 的 build.grade文件中写上 compile 'com.android.support:design:22.2.0' 三.使用说明 <android.support.design.widget.FloatingActionButton android:id="@+id/floa

  • Android中mvp模式使用实例详解

    MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller. 在MVC里,View是可以直接访问

  • Android 网络请求框架Volley实例详解

    Android 网络请求框架Volley实例详解 首先上效果图 Logcat日志信息on Reponse Volley特别适合数据量不大但是通信频繁的场景,像文件上传下载不适合! 首先第一步 用到的RequetQueue RequestQueue.Java RequestQueue请求队列首先得先说一下,ReuqestQueue是如何对请求进行管理的...RequestQueue是对所有的请求进行保存...然后通过自身的start()方法开启一个CacheDispatcher线程用于缓存调度,开

  • EventStore文件存储设计详解

    背景 ENode是一个CQRS+Event Sourcing架构的开发框架,Event Sourcing需要持久化事件,事件可以持久化在DB,但是DB由于面向的是CRUD场景,是针对数据会不断修改或删除的场景,所以内部实现会比较复杂,性能也相对比较低.而Event Store实际上对数据只有新增和查询的需求,所以我想为Event Sourcing的场景针对性的实现一个Event Store.看了一下业界的一些实现,感觉都没有达到我的期望,所以想自己动手实现一个.下面是我构思的一个Event St

  • Android开发环境搭建过程图文详解

    一.工具 IDE:Android Studio4.1+genymotion (Android studio 自带AVD着实有些不好用,这里选择使用genymotion模拟器) JDK:1.8 SDK:7.1 版本管理:Git 二.环境搭建 1.安装jdk 这里使用的是jdk1.8 ,安装并配置环境变量,通用步骤,不一 一介绍了 2.安装Android Studio 安装:android-studio-ide-201.6858069-windows.exe ,默认安装即可配置sdk (可以选择设置

  • Android mvvm之LiveData原理案例详解

    1. 生命周期感知 1.1 生命周期感知组件 我们知道,Controller(Activity or Fragment) 都是有生命周期的,但是传统的 Controller 实现方式只负责 Controller 本身的生命周期管理,而与业务层的数据之间并没有实现良好解耦的生命周期事件交换.所以业务层都需要自己主动去感知 Controller 生命周期的变化,并在 Controller 的生存期处理数据的保活,而在消亡时刻解除与 Controller 之间的关系,这种处理方式随着业务规模的扩大往往

随机推荐