如何简单快速搭建 Android 大仓

简介: 书接上文,上回提到 B 站Android团队为了解决组件化后协作上的问题,已经采用了大仓(monorepo)的方案来组织代码。

书接上文,上回提到 B 站Android团队为了解决组件化后协作上的问题,已经采用了大仓(monorepo)的方案来组织代码。

国内实践大仓的团队少之又少,更别提 Android 的大仓了,几乎没有来自其它团队的可借鉴经验。在这条路上,我们可以算作先行者。本文粗陋,文中所列思路不可能适用所有团队,仅给同样想实践Android 大仓的人些许启发。

一个标准的 Gradle 项目

首先回顾一下 Android 项目的组织方式。自从13年开始官方逐渐迁移到 Android Studio 做为 IDE 后,Android 项目的开发和编译就绑在 Gradle 上了。

一个标准的 Gradle 项目结构如下所示:

MyApp/
├── build.gradle 
├── settings.gradle 
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar  
│       └── gradle-wrapper.properties  
├── gradlew  
├── gradle.properties 
└── app
     ├── build.gradle
     └── src
          └── main
              ├── java
              ├── res
              └── AndroidManifest.xml

通常,会有多个Gradle Module存在:

MyApp/
├── build.gradle 
├── settings.gradle 
├── app
│     ├── build.gradle
│     └── src
├── lib1
│     ├── build.gradle
│     └── src
└── lib2
      ├── build.gradle
      └── src

其中 settings.gradle 会注册所有的 Module

include ':app', ':lib1', ':lib2'

多仓库

随业务的扩张,Module 数量会越来越多。遵循多数人实践过的组件化的思路,按业务分仓库存放便理所当然:

android group/
  ├── MyApp/ 
  │     ├── build.gradle
  │     └── settings.gradle
  ├── app1/
  │     ├── build.gradle
  │     └── settings.gradle
  ├── app2/
  │     ├── build.gradle
  │     └── settings.gradle
  └── libs/
        ├── build.gradle
        └── settings.gradle

每个仓库都是一个标准 Gradle 项目,通过 publishing 插件将module 都上传 aar(或者jar)到 maven私服(如nexus)上,再在 MyApp/build.gradle 中以 maven 组件的形式依赖它们,最终打包成apk:

repositories {
    maven {
        name = "myRepo"
        url = "http://myrepo.example.com/android"
    }
}
dependencies {
    implementation 'com.example.android:app-a:1.0.0'
    implementation 'com.example.android:app-b:1.0.0'
    implementation 'com.example.android:lib-a:1.1.0'
}

[图片上传失败...(image-7a44b2-1546505515555)]

此时的代码组织方式便是上文中所述的多仓库形态(可能许多团队正处于当前阶段)。

多仓到大仓

那么,如何既能快速搭建出适用于 Android 的大仓,又能不影响当前的团队协作流程,还要尽量避免迁移带来的开发效率降低?

经过一段时间的深入研究 Gradle API,终于找到一个简单快速的可行方案——composite builds

上面说过,其实每个仓库都是按业务分离的标准的 Gradle 项目,那么就可以通过Gradle 官方提供的一个直接引入其它项目的API——includeBuild——快速将所有仓库组织起来。

在 MyApp/settings.gradle 中直接引入其它 Gradle 项目:

includeBuild '../app1'
includeBuild '../app2'
includeBuild '../libs'

另外比较令人惊喜的是,如Gradle 官方所说,includeBuild会自动替换依赖com.example.android:app-a为有对应声明的module,如 project(:app1:app-a)。这样仍然可以用原有的依赖写法,什么都不用改,基本没有迁移工作量。

具体示例可以见官方示例项目:https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/compositeBuilds/hierarchical-multirepo

而且,使用 includeBuild 能保留当前的开发流程不变,每个模块仍发布到 maven 上,不破坏既有协作流程。各个业务的开发,通过Android Studio 打开自己项目的目录即可,可以说几乎没有开发效率的影响。

解决了各个项目合并问题,另外一个就是要保证大仓的可维护性。

上文讲过,依然沿用之前分层的方式,按约定的文件夹组织:

<root dir>
    ├── build.gradle
    ├── settings.gradle 
    ├── app/
    │    ├── app-a
    │    │    ├── src 
    │    │    └── build.gradle
    │    ├── app-b
    │    │    ├── src
    │    │    └── build.gradle   
    │    ├── build.gradle
    │    └── settings.gradle
    │
    ├── common/
    │    ├── common-a
    │    │    ├── src
    │    │    └── build.gradle
    │    ├── build.gradle
    │    └── settings.gradle
    │
    ├── framework/
    │    ├── lib-a
    │    │    ├── src
    │    │    └── build.gradle
    │    ├── build.gradle
    │    └── settings.gradle
    │
    └── MyApp
         ├── src
         └── build.gradle

各个业务方的代码只需要按层级对号入座即可。

对号入座的方式有很多种,最简单的便是直接拷贝项目到对应目录,而如果要保留原仓库的提交记录,则可以使用 git filter-branch 和 git update-index 等命令(略过不表╮( ̄▽ ̄)╭)。

收敛合并权限

人总是会犯错的,为了不让近百名开发成员在一个仓库里打架,我们需要在 gitlab 权限分配的基础上,通过API实现自动化的方式来合并代码。

每个文件夹(或者模块)可以添加一个配置文件,如OWNERS,业务团队自己分配 owner和reviewer。

<root dir>
    ├── app
    │    ├── OWNERS
    │    └── app-a
    │          └── OWNERS
    ├── common
    │    ├── OWNERS
    │    └── common-a
    │          └── OWNERS
    ├── framework
    │    ├── OWNERS
    │    └── lib-a
    │          └── OWNERS
    └── MyApp
         └── OWNERS

通过gitlab webhook及note api来实现一个自动化工具:

当开发人员提交一个新的 Merge Reqeust 时,工具找到有变更文件夹的对应 owner 及 reviewer,提醒他来review 和操作合并;当他在MR中提交merge指令时,由自动化工具执行合并操作。

综述

  1. 通过 Gradle 的includeBuild将所有分开的仓库合并到一起,并按一定的目录层级组织各个子项目。
  2. 通过 gitlab 的 api 实现一个自动化工具来合并代码。

通过上述两个步骤,便打造了一个大仓雏形。然而这只是大仓的第一步,未来还有很多工作呢…

关于大仓,本文只简单描述了一下方案大致思路,行文粗糙,希望对想实践大仓的你有所帮助,如有疑问欢迎评论留言。

欢迎加入Android进阶交流群;701740775。进群可免费领取一份最新技术大纲和Android进阶资料。请备注csdn

相关文章
|
弹性计算 Java API
产品百科 | 如何快速搭建短视频 App ( Android 版)
通过阅读本文,您可以快速了解趣视频 Demo 基本信息和搭建方法。
产品百科 | 如何快速搭建短视频 App ( Android 版)
|
XML API Android开发
Android 垃圾分类APP(一)申请API、搭建项目、访问接口获取数据
Android 垃圾分类APP(一)申请API、搭建项目、访问接口获取数据
487 0
Android 垃圾分类APP(一)申请API、搭建项目、访问接口获取数据
|
XML 缓存 JSON
Android OkHttp+Retrofit+RxJava搭建网络访问框架(含源码)
Android OkHttp+Retrofit+RxJava搭建网络访问框架(含源码)
776 0
Android OkHttp+Retrofit+RxJava搭建网络访问框架(含源码)
|
XML API Android开发
Android 天气APP(四)搭建MVP框架与使用
Android 天气APP(四)搭建MVP框架与使用
281 0
Android 天气APP(四)搭建MVP框架与使用
|
Java 程序员 Maven
Android的Nexus搭建Maven私有仓库
Android的Nexus搭建Maven私有仓库
437 0
Android的Nexus搭建Maven私有仓库
|
ARouter 开发工具 Android开发
Android 手把手带你搭建一个组件化项目架构(下)
本文介绍了组件化、组件分层、解决了组件的独立调试、集成调试、页面跳转、组件通信等。 其实会了这些后你基本可以搭建自己的组件化项目了。其实最大的问题还是分组分层、组件划分。这个就需要根据你的实际情况来设置。
562 0
Android 手把手带你搭建一个组件化项目架构(下)
|
开发工具 Android开发
Android 手把手带你搭建一个组件化项目架构(上)
目录 一、组件化 1.1 为什么使用组件化 1.2 模块化与组件化 1.2.1 模块 1.2.2 组件 1.3 组件化的优势 1.4 组件化需要解决的问题 二、组件分层 2.1 基础组件 2.2 common组件(lib_common) 2.3 功能组件 2.4 业务组件 2.5 主工程(app) 2.6 完成后项目 三、组件单独调试 3.1 创建组件(收藏) 3.2 动态配置组件的工程类型 3.2.1 build.gradle(module) 3.2.2 设置gradle.properties 3.2.3 动态配制插件(build.gradle)
865 0
Android 手把手带你搭建一个组件化项目架构(上)
|
设计模式 编解码 数据可视化
Android修行手册-UI组件快速搭建App界面
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!
264 0
|
传感器 数据采集 编解码
【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )(二)
【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )(二)
490 0
【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )(二)
|
Android开发
android 底部标签栏CommonTabLayout搭建项目底部菜单(带消息提醒)
android 底部标签栏CommonTabLayout搭建项目底部菜单(带消息提醒)
android 底部标签栏CommonTabLayout搭建项目底部菜单(带消息提醒)