android构建系统_android构建和最终游戏之旅

android构建系统

长话短说 (Long story short)

Just like every other Android project, we start with a single :app module. At the time we didn’t have many features, the codebase was small and compact, everything was good. Time goes by, we have more features in the project, our leader realizes this will soon become a problem so he split the project into multiple modules. Parallel builds were great, we were very happy with the result. Time goes by again, business grows, more and more features have been added to the project at the point we have 60+ modules in the project. When making changes on a single module, although other modules didn’t have to recompile, Gradle still spends some time to check whether it needs to recompile that module. And it turns out, checking 60+ modules takes a huge amount of time, build time just gets longer and longer.

与其他Android项目一样,我们从一个:app模块开始。 当时我们没有很多功能,代码库又小又紧凑,一切都很好。 随着时间的流逝,我们在项目中拥有更多功能,我们的领导者意识到这将很快成为问题,因此他将项目分为多个模块。 并行构建很棒,我们对结果感到非常满意。 随着时间的流逝,业务增长,在项目中有60多个模块时,项目中已添加了越来越多的功能。 在单个模块上进行更改时,尽管不必重新编译其他模块,但Gradle仍然花费一些时间来检查是否需要重新编译该模块。 事实证明,检查60多个模块要花费大量时间,构建时间越来越长。

样例项目 (Sample Project)

We discover that in Gradle instead of include ':home' you can includeBuild './home' which basically lets you include a project inside a project. The idea is that instead of including a module (say :home module), we include a project (called sample project) which includes the :home module. In the sample project, we set up a small com.android.application module that acts as a shell to run the code inside :home module. As a result, we didn’t have to include 60+ modules just so that we can test the code inside :home module. The sample project is lightweight, build is fast, productivity is good.

我们发现,在Gradle中,您可以包含includeBuild './home' ,而不是include ':home' ,它基本上可以让您将项目包含在项目中。 这个想法是,我们包括一个包含:home模块的项目(称为示例项目),而不是包含一个模块(例如:home模块)。 在示例项目中,我们设置了一个小的com.android.application模块,该模块充当外壳程序来运行:home模块中的代码。 结果,我们不必仅包含60个以上的模块即可测试:home模块中的代码。 样本项目轻量级,构建速度快,生产率高。

Image for post

Unfortunately, with this approach, we have to maintain the sample project. Nobody likes extra maintenance, and even if we do, maintaining 60+ sample projects is not feasible. In the end, we only have a few sample projects for modules that we work most frequently.

不幸的是,使用这种方法,我们必须维护示例项目。 没有人喜欢额外的维护,即使我们这样做,维护60多个示例项目也不可行。 最后,对于我们最常使用的模块,我们只有几个示例项目。

排除构建 (Exclude Build)

As it turns out, you can have a blazing fast build if you don’t have to build in the first place.

事实证明,如果您不必首先构建,便可以快速构建。

The idea of exclude build is that you only include whatever you need in that build and exclude the rest. This can be done with some simple if else statements inside setting.gradle

排除构建的想法是,您仅包括该构建中需要的任何内容,而排除其余部分。 这可以通过在setting.gradle使用一些简单的if else语句来完成setting.gradle

// setting.gradleshouldInclude = { moduleName ->if (project.hasProperty('include')) {
def include = project.property('include')
def regex = Pattern.compile(include, Pattern.CASE_INSENSITIVE)
return regex.matcher(moduleName).find()
}
return true}if (shouldInclude('home')) {
include(":home")
}

Build command:

生成命令:

./gradlew :app:installDebug -Pinclude="home|search|data"

This approach gives us the flexibility to include only what we need for each build, and we can change the combination of modules between builds. Build time now depends on what you include in each build, at the end of the day, it doesn’t matter how many modules you have, build time remains constant.

这种方法使我们可以灵活地仅包含每个构建所需的内容,并且可以在构建之间更改模块的组合。 现在,构建时间取决于您在每个构建中包括的内容,最终,无论有多少模块,构建时间都保持不变。

动态排除构建 (Dynamic Exclude Build)

Exclude build is great, our productivity has never been better. Because the build is now so fast, we were able to experiment more stuff, build and test more frequently, things that previously we didn’t bother to do because we will have to wait 5 minutes just to see the result.

排除构建是伟大的,我们的生产力从未如此出色。 由于构建现在是如此之快,因此我们能够进行更多的实验,更加频繁地构建和测试,而以前我们不费吹灰之力,因为我们仅需等待5分钟即可看到结果。

But…exclude build still have one small problem

但是...排除构建仍然有一个小问题

Image for post

Say you make a change in the :home module, recompile :home module is obvious, but because the :app module depends on :home module, even though it doesn’t change anything it still has to recompile. Unfortunately our :app module is quite big, recompiling takes some time and we are on a journey to find another solution, again.

假设您在:home模块中进行了更改,显然可以重新编译:home模块,但是由于:app模块依赖于:home模块,即使它没有任何改变,它仍然必须重新编译。 不幸的是,我们的:app模块很大,重新编译需要一些时间,而且我们正再次寻找另一个解决方案。

In Google I/O 2018, Android App Bundle was introduced by Google. It comes with features called dynamic delivery which will allow us to download additional features at run time and on-demand. At first glance, it seems like we can’t utilize much out of this feature, but it turned out that you can have a dynamic feature module that preinstalls with the app.

在Google I / O 2018中,Google引入了Android App Bundle。 它带有称为动态交付的功能,使我们可以在运行时按需下载其他功能。 乍一看,我们似乎无法充分利用此功能,但事实证明您可以在应用程序中预装一个动态功能模块。

Image for post

Because a dynamic feature module is supposed to be downloaded and installed at runtime, :app module must not know anything about it. Instead of depending on :home module, now :home module depends on :app module, the dependency is reversed. This lifts off the previous restriction, now the app module doesn’t depend on :home module anymore, it doesn’t have to recompile on each build. This is the point when we reach 1 minute build time because now we only have to compile only 1 single module.

因为应该在运行时下载和安装动态功能模块,所以:app模块一定不知道任何有关它的信息。 现在, :home模块不再依赖于:home模块,而是依赖于:app模块,而是将依赖关系反转了。 这解除了先前的限制,现在app模块不再依赖于:home模块,也不必在每个版本上重新编译。 这是我们达到1分钟构建时间的关键,因为现在只需要编译1个单个模块。

按需动态排除构建 (On-demand Dynamic Exclude Build)

Dynamic Exclude Build still has a problem, according to google if you have too much dynamic feature module, install time will increase.

动态排除构建仍然存在问题, 根据Google的说法,如果您有太多的动态功能模块,则安装时间会增加。

Limit the number of modules you configure as removable for install-time delivery to 10 or less. Otherwise, the download and install time of your app might increase.

将为安装时交付而配置为可移动的模块的数量限制为10个或更少。 否则,您的应用程序的下载和安装时间可能会增加。

This is very bad for the business because it reduces the successful install/update conversion rate, something might happen during the install time that leads to a failed installation. So basically you want to install as quickly as possible, which requires a small app size and 0 dynamic feature module.

这对企业来说非常不利,因为它会降低成功的安装/更新转换率,在安装期间可能会发生某些事情,从而导致安装失败。 因此,基本上,您希望尽快安装,这需要较小的应用程序大小和0个动态功能模块。

By adding another if else statement into build.gradle the configuration of a module now goes through 2 parses. Include this module into the build or not? If yes then should we include as a dynamic feature module or as a normal feature module?

通过在build.gradle添加另一个if else语句,模块的配置现在经历了2个解析。 是否将此模块包含在构建中? 如果是,那么我们应该将其包括为动态功能模块还是普通功能模块?

// setting.gradle
if (shouldInclude('home')) {
include(":home")
}// app/build.gradle
def dynamic = project.hasProperty("dynamic")
if (dynamic) {
if (shouldInclude('home')) {
dynamicFeatures += ":home"
}
if (shouldInclude('search')) {
dynamicFeatures += ":search"
}
}// home/build.gradle
if (dynamic) {
apply plugin: "com.android.dynamic-feature"
} else {
apply plugin: "com.android.library"
}

Build commands:

生成命令:

// debug build with home as a dynamic feature module
./gradlew :app:installDebug -Pdynamic -Pinclude="home"// debug build with home as a feature module
./gradlew :app:installDebug -Pinclude="home"// release build
./gradlew :app:bundleRelease

We now have the best of both worlds, using dynamic feature modules in debug build to have faster build times and using feature modules in release build to have faster install times.

现在,我们两全其美,在调试版本中使用动态功能模块可以缩短构建时间,而在发布版本中使用功能模块可以缩短安装时间。

In addition to that, we also write some tests and have some extra steps in the CI to ensure everything is properly configured.

除此之外,我们还编写了一些测试,并在CI中包含一些额外的步骤,以确保正确配置了所有内容。

智能按需动态排除构建 (Smart On-demand Dynamic Exclude Build)

All of these optimizations and extra setup serve one purpose solely: making the developing experience better. The experience is good, but it is not good enough. During the development process, as I said earlier, most of the time we only work on a single module or a specific screen, but we also want to have every related screen so that we would be able to see the interaction between them. For example, you work on the home module and make some changes to the search bar, and you want to test when the user touches on the search bar, will it navigate to the search screen. If your build doesn’t include the search module, the app will crash when you touch on the search bar. Another example is when you accidentally touch an element on the screen that triggers the navigation, the app will also crash (if that module is not included)

所有这些优化和额外的设置仅用于一个目的:改善开发体验。 经验是好的,但还不够好。 正如我前面所说,在开发过程中,大多数时候我们只在单个模块或特定屏幕上工作,但我们也希望拥有每个相关屏幕,以便我们能够看到它们之间的交互。 例如,您在home模块上工作,并对搜索栏进行了一些更改,并且您想测试用户何时触摸搜索栏,它将导航到搜索屏幕。 如果您的版本不包含搜索模块,则当您触摸搜索栏时,应用程序将崩溃。 另一个示例是,当您不小心触摸了触发导航的屏幕上的某个元素时,该应用也会崩溃(如果未包含该模块)

To solve this problem, for each module we build a maven artifact and install it into our local development machine (~/.m2/repository). During the configuration process, if the module is not included and we happen to have a local artifact, we just include it anyway.

为了解决这个问题,对于每个模块,我们都构建一个Maven工件并将其安装到我们的本地开发机器( ~/.m2/repository )中。 在配置过程中,如果未包含该模块,而我们恰好有一个本地工件,则无论如何我们都将其包含在内。

// setting.gradle
if (shouldInclude('home')) {
include(':home')
}// app/build.gradle
def hasLocalArtifact = { name ->// ...}if (!shouldInclude('home') && hasLocalArtifact('home')) {
implementation 'vn.tiki.android:home:1.0.0'
}

结束游戏 (End game)

It was a long journey but we were very happy with the result

这是一段漫长的旅程,但我们对结果感到非常满意

  • Constant build time, which doesn’t depend on the number of modules in your project.

    持续的构建时间,这与项目中模块的数量无关。
  • Faster install time, at the end of the day we still only have a single APK* instead of split APKs for dynamic feature modules.

    安装时间更快,最终,我们仍然只有一个APK *,而不是动态功能模块的拆分APK。
  • Ability to have a full set of features in the debug app without sacrificing any additional build time.

    能够在调试应用程序中拥有全套功能,而无需牺牲任何额外的构建时间。

There are still some more improvements we can make which I will talk about in the next article. These are small and good-to-have improvements that improve your developing experience. For this article, I just want to focus on the idea of Exclude Build. I hope that you can take away something from this, make changes in your project, and save some time.

我们还有很多改进可以做,我将在下一篇文章中讨论。 这些小巧的改进可以改善您的开发经验。 对于本文,我只想关注Exclude Build的想法。 我希望您可以从中学到一些东西,在项目中进行更改,并节省一些时间。

You can read my previous article where I discuss some of the technical issues when we try to apply the idea of Exclude Build into our project and how we overcome the challenges within the process :

您可以阅读我的前一篇文章,其中当我们尝试将“ 排除构建”的概念应用到我们的项目中以及如何克服流程中的挑战时,我将讨论一些技术问题:

Sample project:

示例项目:

翻译自: https://proandroiddev.com/android-build-and-the-journey-to-the-end-game-55c9766325c5

android构建系统

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值