50

招才猫直聘安卓DU动态框架实现

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI1NDc5MzIxMw%3D%3D&%3Bmid=2247488449&%3Bidx=1&%3Bsn=f27b914a1546aa7d83875541371a62e4
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

导语

市场环境瞬息变换,产品需要根据市场进行快速调整。如何在保证优秀的用户体验,常规发版节奏不变的情况下,可针对部分重要产品功能完成热部署,成为当下我们要解决的技术问题。市场上的解决方案多种多样,如插件化、RN、WEEX等。前几期文章介绍过iOS的轻量级动态部署开发框架,现将Android端的动态部署开发框架-DU也一并发出来,一起探讨学习。下面将向大家详细介绍此框架。

DU的框架产生

什么是DU?DU,全称为DynamicUpdate。顾名思义,就是动态更新框架。DU的诞生,是为了解决Android平台的动态部署能力,因此我们可以通过DU解决产品同学想快速验证的部分重要需求,同时用户体验接近Native。

要实现快速迭代,就要避开APP发版环节,采用动态部署的方式,将功能动态下发到用户手机内。市场上解决此类问题的方案也多种多样,常见方案大致存在以下几种:

A、Web / Hybird 方案;

B、JS + Native 方案;

C、Android插件化方案。

三种方案各有优缺点,具体优缺点对比以及技术选型不是本文重点,这里不再展开讨论,感兴趣的同学可自行查阅相关文章。我们选取的是第二种方案:JS+Native解决方案。

JS+Native动态部署方案,其原理是:通过JS与native交互协议,用JS代码操作原生系统的UI组件,代替DOM元素来渲染。由于最终渲染是由Native完成,所以即实现了跨平台动态更新的特性,也保证了流畅的用户体验。市面上较流行的解决方案有:

React Native:是由Facebook开源的跨平台移动应用开发框架。支持用开源的JavaScript库React.js来开发iOS和Android原生App。其主张“Learn once, write everywhere”。

WEEX:WEEX是一款基于通用跨平台的 Web 开发语言和开发经验,来构建 Android、iOS 和 Web 应用的开发框架。目前 前端框架Vue 和 Rax被广泛应用于 Weex 页面开发。其宣称“Write Once, Run Everywhere”。

DU也是基于JS+Native原理。它更加轻量,是面向Android研发人员设计的一款动态开发框架。它的设计思路遵循招才猫动态部署框架整体的思路,使Android/iOS  Native开发的小伙伴上手机开发成本低,甚至可忽略。下图是用DU框架开发的页面,大家可以看出,与我们Android开发规范相似度非常高。

UjArQfr.png!web

看了demo代码,相信大家对DU的开发有了个初步的认识。下面我将向大家详细介绍DU开发框架原理与实现。

DU框架原理

上一章已提到,DU的技术方案为JS+Native。具体方案如下图:

byQv6nB.png!web

协议通信层:DU框架,选取了Google的JavaScript引擎V8,实现JavaScript和Android的相互调用。在JS端以及Native分别对协议进行了封装与解析。DU所有的数据交互,都是以此为基础来扩展的。
JS端SDK:DU围绕协议层,封装了对上层业务支持的各个功能模块,并提供DynamicUpdateAPI,供JS业务层调用。如页面组件、类转换器、资源管理、配置管理、扩展模块、崩溃收集等,这些模块的封装,会通过协议层传输到Native端,具体的实现,都由Native端完成。
Native端:则是对JS端定义的模块具体实现。如网络扩展模块,会接受JS端传递的网络协议数据,然后调用Native网络框架(如OKHttp)去执行真正的网络请求,并将结果通过协议层,会传JS端。
JS业务层:业务逻辑具体实现层,通过调用JS端提供的DynamicUpdateAPI,完成需求功能的开发工作。
DU框架完整的运转流程如下图:

aAbiIbn.png!web

DU渲染原理

上文提到过,DU是一款面向Android开发人员的动态开发框架,主要体现在页面创建、生命周期管理以及组件间通讯等封装,都与Android Native开发规范高度保持一致。除了JS语言与Java语言在编写方式上稍有差别外,Android同学在使用DU过程中,会有一种熟悉感扑面而来。下面向大家介绍DU页面渲染以及生命周期管理的原理。

1、渲染原理

rMRvMnz.png!web

DU的布局文件、文案定义、颜色、尺寸定义,都与Android完全一致,都是用xml定义,就连文件命名也延续了Android的命名;

DU的图片,放到了固定的图片文件夹中,在布局文件中使用的时候,只要定义$drawable/xxx即可加载对应的图片文件;

DU框架里面封装了加载DU页面的DUActivity以及DUFragment。在启动DU页面时,将布局文件与页面进行关联。在Activity/Fragment创建的时候,会自动创建资源解析器与构建器。

资源解析器会将布局文件以及布局中用到的颜色、尺寸、图片等信息,进行解析转换,并交给Views生成器,生成一个个带有完整描述的组件,这些组件会形成ViewsTree。

转换器将生成的ViewsTree交给构建器。构建模块会根据各个控件的描述,创建对应的组件,并添加到DecorView上,并为有交互的控件添加事件监听。

至此,DU完成了页面的渲染。

2、生命周期 DU将Android的生命周期,映射到了JS页面的生命周期,使JS可以在生命周期内,处理自己的业务逻辑。具体方式如下图:

BrmYRvR.png!web

DU同样支持带有启动模式的Activity。由于Android的Activity需要在AndroidManifest.xml注册,DU采用了占坑的方式,提前在AndroidManifest.xml注册了带有启动模式的Activity。

3、UI扩展 DU已经对构建页面的基本组件做了封装。如常用的Layout、Button、ListView、CheckBox等。但是业务错综复杂,交互设计千变万化。显然一个框架是不能覆盖全部页面元素的。这里DU提供了UI扩展功能,只要按照DU的扩展规范,即可轻松创建属于你的UI界面。具体方法如下:

yQjIjaJ.png!web

JSUIComponents,是对应控件的调用封装。如封装JSButton对应的各种方法调用。

UIComponents组件,就是现有APP自己创建的控件,也可以是系统封装的控件,如Button。

Proxy,是控件代理层。代理层有两个作用:

A、封装属性代理。通过代理里面封装的Property,为不同控件设置不同的属性,并且Property是可以继承的,相应的也就是控件的属性可以继承。如DUViewGroupProxy.Property 继承自DUViewProxy.Property,所以DUViewGroup不但拥有了自己的属性,同时也拥有了DUView的属性。这样可以避免重复定义控件属性,增加属性复用性。

B、将调用与实现隔离。如Button控件,在招才猫端对应的就是招才猫封装的ZCMButton,但是对应其他APP,就会是xxxButton。有了代理层, 在集成DU框架时,可以实现控件的快速切换,而不是再封装一套。

view_config配置文件,此文件主要作用是将View与Viewproxy做映射关系。

layout.xml,为布局文件。

以上为Native端的实现。

SDK里面已经封装了交互协议以及View生成器。在SDK初始化的时候,已经根据view_config.xml的配置信息,将View与ViewProxy做了一一对应。在渲染页面时,view生成器会根据layout创建相应控件,并通过ViewProxy,调用view的setxxx方法,为view属性赋值。

DU模块扩展

使用DU框架进行混合开发,不可避免的要使用一些Native已经封装好功能,比如分享、网络请求、支付等等。为解决此类使用场景,DU提供了扩展功能。具体原理如图:

bU3uQrZ.png!web

与UI扩展类似:

jSExtendsible封装了扩展模块的方法调用;

NativeExtengdsible,是具体扩展功能的实际执行方;

extendsible_config.xml将jSExtendsible与NativeExtengdsible做了映射关系;

SDK内部,通过ModuleManager,将jSExtendsible调用协议解析、并交给NativeExtengdsible执行,最后将执行结果返回。

DU类转换器

JS是弱类型语言,在DU的协议传输中,DU框架将所有数据转为字符串传输。而Android端的具体执行,其实都是根据协议,通过反射调用相应功能模块来完成的。Java是强类型语言,这就需要将协议中方法调用的参数做强类型转换。

例如:JS端调用textView.setHeight(12)设置高度,协议传输过程中,12是字符串,调用的是Android端TextView的setHeight(int pixels) 方法。这时需要将字符串”12“转换为int类型。类转换器处理的就是类似场景。

目前DU已经封装了30几种类转换器,基本可以覆盖常规开发需要。接入方也可以根据实际情况,扩展自己的类转换器。具体原理以及实现过程和UI扩展、模块扩展一致,如下图。这里不再赘述。

imAZ3aU.png!web

DU踩的坑

以上, DU动态框架核心技术点已给大家分享完毕。当然,我们在开发过程中,遇到了各种各样的问题,在这里和大家做个分享,采坑经验最宝贵:

1、JS引擎的选择

在DU行程框架诞生之前,招才猫使用了以WebView为引擎,作为协议中转核心,通过JS,创建Native页面并执行相关逻辑,实现了发布页面的动态化。

在后续优化中,在发布页面基础上,提取了通用协议,并做了更加丰富的封装,产出了第一版DU,同样,第一版DU框架的核心引擎也是WebView。WebView在这里的作用仅仅是执行JS,并负责与Native通讯。可以想见,WebView页面绘制等功能并没有使用,但是我们仍会进行初始化,造成了资源浪费。经过对比与调研,我们最终引入了V8,作为DU框架的JS解析执行以及通讯引擎,减少了DU在运行时的资源消耗。

2、复杂动画的处理

在需求开发中,必然会用到各种动画效果,DU框架已支持常用的动效实现,如Animation、Transition等,DU已做了封装,可以直接使用。但在我们使用过程中发现,简单动效还好,DU完全能够胜任。一旦在DU中实现比较复杂的动效时,页面就会出现卡顿现象。经过试验与分析,我们发现在动效执行过程中,JS与Native会进行频繁交互,在协议传输、解析过程中,由于数据传输过于频繁,造成通讯模块处理延迟,导致页面卡顿。

在解决动画问题上,我们针对动效交互的协议做了大量优化,但收益不佳。在后续优化中,我们放弃了在动效交互协议上做文章,而是考虑其他解决方案。得益于我们UI扩展能力,在开发实践中,我们将复杂动效封装成UI组件,将动效完全交由Native实现,JS端仅仅作为调用方。这样,就不存在动效执行中,协议交互频繁的问题了。此方案的坏处就是如果动效组件在之前版本中没有实现过,还是需要跟随版本上线。不过在实践中,需要特别复杂动效的情况,少之又少。DU完全能够胜任目前的需求。

结语

除以上框架核心技术内容,DU框架还有其他优秀的技术实现,如高效的DUListView、框架安全、崩溃采集等,限于篇幅原因,我们不在此一一赘述,欢迎大家线下相互交流、学习。

参考文献

1、https://reactnative.cn/
2、https://weex.apache.org/zh/guide/introduction.html
3、https://nodejs.org/en/
4、https://github.com/eclipsesource/J2V8
5、https://developer.android.com/docs

作者简介

黄金鑫,HRG技术部资深开发工程师,目前主要负责招才猫直聘安卓端相关业务开发与维护工作,对移动Android端相关技术,尤其是动态框架开发方面有一定研究。

阅读推荐


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK