Android App 架构与组件化

导言

Android 系统如今以走过 12个年头,从2.X正式进入“智能机”时代,到6.X-9.X的引领移动端新特性,与iOS相互争锋,再到如今的11.X的合规与权限逐渐日趋严格。Android App的发展路程也随系统的不断迭代,已经有很多技术壁垒及技术整合,合规。这些一步步的迭代与发展,让国内App已经融合了太多东西。一个App中包含文字聊天、直播、视频、语音、购物、支付、内容发布、内容分享、剪辑等等一系列的功能已经越发正常。并且这些已经属于单一App的基本功能,产品、研发又在这些功能上不断迭代生产出各种与众不同的玩法。这时候如果没有一个好的App架构与框架来支撑App的功能,各个业务线之间的依赖逻辑可能会显得无比复杂,并时不时地发生循环依赖而导致研发时间暴增。如何使App的架构更加完善就成了各个App最为棘手的问题。

Android App 架构与组件化

Android App的架构与组件化是密不可分的,架构的第一步就是将各个非业务的功能性SDK拆分为可复用的组件SDK。所以组件化SDK是App架构的基础,这两个需要一起确立。

组件化

对于组件化而言,需要对各个复用SDK确定的点有如下几点:

  1. 所依赖的SDK
  2. SDK核心功能
  3. SDK业务边界
  4. SDK开方的API

所依赖SDK

对于中间层的SDK,需要依赖一些基层的SDK才能实现,比如:下载SDK可能需要依赖OKHttp的SDK;解耦的时候,如果对外提供统一接口,需要依赖Router相关SDK,比如阿里巴巴开源的ARouter;缓存一些业务数据、文件的时候,需要适配Android11的文件存储SDK;重写ImageView来实现自定义加载网络图片时,需要依赖Glide或Picasso相关的接口的SDK。组件化一定要规范好各自SDK所需要依赖的SDK有哪些,一般情况没有新特性,这些依赖树是不需要改版的。

版本号

相对应的,也要确定SDK的版本号。有些公司会在gradle脚本中将版本号隐去,统一根据版本号下发组件的版本号,这种发放可以解决各个业务模块依赖的版本号不同的问题。但是这也带来依赖于某一基础版本号(比如App版本号)来下发对应的依赖版本号。这种依赖还会带来查询真正依赖的版本困难的问题,如果要依赖最终的版本号有很多种办法,比如在主工程模块中覆盖,在gradle文件中统一替换等。
使用一致的,规范的组件依赖版本号是组件化的关键步骤。

SDK核心功能

在抽离SDK的时候,需要确立SDK的核心功能是什么。比如作为内容lib承接的业务封装可以包含:特定业务封装的ImageView,为了调用便利二次封装的音视屏业务代码,为了App内部实现音视频的焦点切换逻辑等等;作为内容生产lib承接的业务封装可以包含:二次封装的剪裁SDK业务代码,独立的有请求权限的相册调用的业务代码,调用相机拍摄的封装逻辑层等一系列中间层业务逻辑。

SDK业务边界

因为抽离SDK的时候很容易发现某一段代码放在A 组件中可以,放在B 组件中也合理的状况。这种情况就需要确定各个业务层的SDK边界。因为Native端的业务几乎都需要一致性的统一,所以这时候可以和iOS一起确认业务逻辑抽离的位置避免以后二次迁移。确立SDK业务边界是一个很重要的事情,因为它会涵盖之后在研发过程中迭代代码仓库的数量,理论上一个业务线内的需求最多只需要修改3-4个SDK即可,如果业务线内的需求需要横跨整个App中各个业务线的仓库,这时候就需要反思拆分的边界是否过于模糊。因为组件化的拆分是为了将相同逻辑的代码内聚到一个SDK中提供给各个业务方使用,而不是频繁修改所有仓库的代码。

SDK开放的API

对于一个对外开放的SDK来说,需要思考给外部业务方暴露的API有哪些,业务扩展时需要如何在迭代中以最小的成本兼容以前的逻辑,是否每次迭代都需要新增接口等问题。相对应的,如果业务方的SDK刚刚创立还在抽离各个业务方中的代码时,需要每个业务方都替换成新的API并兼容之前的所有业务场景。如果仅仅兼容新增的场景而保留老的API或业务代码时,还不如不做。因为这种封装的SDK会使后人维护起来更痛苦,需要维护两套,甚至几套。

Android App 架构

已经有计划将App组件化,就需要对组件化的目标有一个清晰的认识,就是有整体Android App的架构意识。如下为Android App 架构图

Android App 架构主要分为五层,最顶层为App壳,下层为业务线的实现层,再下层为中台统一的API层,用于简单封装外部SDK或功能模块,接下来是内部封装的非框架类型的独立SDK,比如音视频SDK,基于OKHttp的网络SDK,APM SDK,本地日志上报SDK(如Logan),对于系统权限获取封装的SDK,风控封装的SDK等一系列独立可复用的SDK,最底层为第三方独立SDK,如微信SDK,支付宝SDK,ARouter SDK等。下面会由底层往上层逐一介绍各层级的SDK所需要提供的内容。

底层SDK

对于底层SDK,其实就是第三方SDK及系统的API SDK。这一层几乎没有办法改动,迁移成公司内部的包名以后其实会更加麻烦,因为会导致开源仓库新修改的特性及Bug无法及时的合并到内部仓库之中。不过如果第三方SDK相对较小,可以直接迁移到内部源码直接依赖的话,还是建议迁移聚合到自己内部的SDK中。所以这一层的主旨就是无法修改的第三方SDK。

独立封装SDK

独立封装的SDK指的就是公司内部独立自我封装的SDK,可能是基于其他第三方SDK,也可能是完全独立的SDK。比如音视频播放的SDK,可能就仅仅依赖于Android的SDK及相关的API;独立封装的Router组件等。类似这种组件可以在新开一个完全独立的App时直接集成到的App中稍作封装就可以使用。对于封装复杂的SDK可以仅仅暴露接口给上层,而实现直接由App依赖。达到完全解耦的目的。

统一中台封装SDK

对于一些外部的SDK可能需要一些不复杂的封装。一般来说可能只需要几行代码或者一个类的时候,开一个新的仓库维护会显得过于庞大,就好像发送心跳包的时候新开一个进程一般。所以一个单一的统一封装简单SDK的中台是有必要的。这一层的封装可以直接依赖封装。

业务层SDK

业务层的SDK其实主要分为两层,一层base层,一层业务实现层,base层一般以共同依赖的数据模型、对外暴露的接口为主,实现层为真正的页面、业务逻辑。其中base层可以直接由各个业务实现层依赖,但是base层之间不可互相依赖,业务实现层互相之间也不可以互相依赖,这样就可以达到循环依赖的避免。当然,也可以在gradle脚本中定义各个SDK的层级,如果依赖相同层级的SDK直接报错来达到循环依赖的避免。

App壳

App壳一般不做任何业务逻辑,只是指定App所依赖的组件SDK的版本号及一份根据BuildConfig生成的配置解析。在App指定的版本号可以覆盖其他SDK中的版本号。这部分比较重的是编译脚本而不是代码实现。理论上代码实现只需要一个类即可。

结语

对于整个Android App 有全盘的认知是一名高级开发需要掌握的基本技能。希望可以借助这篇文章一起探讨App 架构的演进。如果说这些都很熟知,但是没办法将整个App推进到架构完美的状态,其实需要反思两个层面:1. 业务重心在什么地方;2. 推进能力问题还是自己实力确实有所欠缺。

App架构其实是业内相当成熟的解决方案,并且有多种方案可供大家参考,希望每个App的迭代成本都可以有效降低。

你可能感兴趣的:(Android App 架构与组件化)