Gradle 使用技巧 [Chinese ver]

Gradle Skill

[TOC]

BuildConfig字段

BuildConfig 字段有默认生成的和自定义的字段,他们在编译后会自动生成到 app/build/source/BuildConfig/Build Varients/package name/BuildConfig 文件。内容如下:

1
2
3
4
5
6
7
8
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.example";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0.0";
}

这是一般工程里都会有的字段.

这里要介绍的是自定义的字段,我们通过自定义的字段可以配置不同 buildTypes 和不同版本的字段。可以用它来便捷的控制许多功能,比如 Log 打印等等。

自定义字段

我们可以通过在不同的 buildTypes 中添加以下类型的代码实现自定义字段

1
buildConfigField "boolean", "LOG_PRINT", "false"

这个命令代表我们在该 buildTypes 下创建了一个类型为 boolean ,名为 LOG_PRINT ,值是 false 的参数。

编译后 BuildConfig 文件变为如下

1
2
3
4
5
6
7
8
9
10
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.darenscm.www.scmprofabric";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0.0";
// Fields from build type: debug
public static final boolean LOG_PRINT = true;
}

可以看到多了这一个参数

1
public static final boolean LOG_PRINT = true;

然后我们在程序中使用 BuildConfig.LOG_PRINT 就可以调用这个参数了。

减小 apk 的大小

为屏幕密度构建多个 apk

通过排除其他不需要的屏幕密度文件来减小 apk 大小.将他们都上传到 Google Play 中,用户将会下载到和他们屏幕密度匹配的 apk

1
2
3
4
5
6
7
8
9
10
11
android {
splits {
density {
enable true
// Specify a list of screen densities which Gradle won't create multiple APKs for
exclude 'ldpi', 'mdpi'
// Specify a list of compatible screen size for the manifest
compatibleScreens 'small', 'normal', 'large', 'xlarge'
}
}
}

为 ABI 构建多个 apk

这个技巧是针对 Application Binary Interfaces(ABIs) 的,目前的 Android 市场中有多个 CPU 框架,我们可以指定想要支持的 ABI 生成多个 apk.

1
2
3
4
5
6
7
8
9
10
11
12
android {
splits {
abi {
enable true
reset()
// Specify a list of ABIs that Gradle should create APKs for
include 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a'
// If you don’t want to generate a universal APK that includes all ABIs.
universalApk false
}
}
}

使用指定 ABI 构建 apk

这个技巧不同于多个 APK。你能指定你想要支持的 CPU 框架,Android Studio 将只生成一个 APK。

1
2
3
4
5
6
7
8
9
android {
defaultConfig {
...
ndk {
abiFilters 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a'
// armeabi, mips and mips64 has removed since NDK r17
}
}
}

这个方式可能会比上一个生成多个 apk 的方式要好,因为之前有过使用多个 apk 方式的情况下出现崩溃.

删除未使用替代资源

同理,语言包也是可选的.

1
2
3
4
5
6
android {
defaultConfig {
resConfigs 'en', 'th'
...
}
}

压缩无用代码和资源

  • 启用 minifyEnabled 会缩小和混淆代码,减小 apk 的大小
  • 同时还可以启用 shrinkResources 在压缩后删除无用的资源.这是由于压缩删除无用代码但是关联的资源并没有一起删除.
  • proguard-android 之后添加 -optimize 它会为 app 做更多的优化,使得大小更小.但是这个过程将会花很多时间,应该只在发布版本中使用 -optimize
1
2
3
4
5
6
7
8
9
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

模块化Gradle

当项目的数量变多的时候如果我们还是采用了旧的方式一个模块配一个的话,会导致后期维护成本增高,变动难以同步.

这个时候我们可以使用 apply from: 来提供模块化 gradle 的支持.

字符串等的统一也可以使用 ext 中用变量声明统一.

优化编译速度

注意AS配置:

​ 如及时更新Gradle和Gradle plugin 以及 JDK版本、扩大AS内存等(修改-Xms256m)、取消AS的自更新设置,去除不经常使用的插件等。

慎重sub-module:

​ 减少sub-module或者将sub-module导成aar,并上传到私有的maven仓库就更加方便啦,每增加一个sub-module的构建的时间会增加很多。从根上解决这个问题,我们应该增加sub-module时要慎重,同时要考虑他的独立性,与主module要完全解耦。这样我们不会再开发的时候产品要换个ui图也跑到sub-module里边修改。当我们修改了sub-module的时候,编译器会检测到修改重新编译,然后copy到主工程的buid/intermediates/exploded-aar目录下。

守护进程daemon:

​ 当我们在gradle.properties中配置org.gradle.daemon=true的时候,相当于开了个进程,这样我们构建项目的许多工作比如加载虚拟机之类的就在该进程中完成。

并行编译parallel:

​ 这个适用于有多个依赖sub-module的情况下,如果单单只有一个module实测会耗时更多。看看官方的说法:When configured, Gradle will run in incubating parallel mode.This option should only be used with decoupled projects. org.gradle.parallel=true。这里通过增大gradle运行的java虚拟机大小,达到多个module并行构建的目的。

依赖库使用固定版本:

​ 我们配置依赖的时候 如依赖V4包,com.android.support:support-v4:23.0.0+,再后边有个+后表示依赖最新的,这样可以保证依赖的库有更新时能够得到更新。但是,小编并不建议这么做。因为每次构建都需要访问网络去判断是否有最新版本,这样也是需要耗时的。我们可能需要频繁的构建调试,但是我们一般很少更新库。当然,这些可以配置在你的release分支上,总之,调试的请配置固定版本吧。

去除无用的构建任务task:

​ Gradle每次构建都执行了默认的许多task,其中部分task是我们不需要执行的,至少在调试的时候不需要,我们可以把这些屏蔽掉,方法如下:

1
2
3
4
5
tasks.whenTaskAdded { task ->
if (task.name.contains('AndroidTest') || task.name.contains('Test')) {
task.enabled = false
}
}

巧用include:

​ 对于我们没有依赖的module,我们可以在settings.gradle里边去掉改module的include,建议写成一行只include一个module,如下:

1
2
include:'lib1'
//include:'lib2'

​ 这样我们实际就只include了lib1,当我们sync或者build\clean的时候就没有lib2的事啦,这样解决时间。

减少构建过程中的I/O操作:I/O操作,如copy文件,访问git等,Debug版本配置的minSdkVersion 21+(builder faster)

Instant Run:

​ 注入依赖技术,不需要安装就可以达到更新apk的目的。 详细参考Instant Run: How Does it Work?!

避免 Legacy Multidex

如果你的 app 超过64k方法限制,你需要使用 Multidex。如果你的的minSdkVersion是21或更低,你也是用 Multidex,那么你将使用 Legacy Multidex,这会使你在构建时变慢。

要避免 Legacy Multidex,你可以定义新的flavor,并在app/build.gradle中指定minSdkVersion21或更高。

1
2
3
4
5
6
productFlavors {
development {
minSdkVersion 21
...
}
}

禁用Multi APK

可以在开发构建环境禁用多个 APK 生成,因为打包和创建这些 APK 需要时间。可以在app/build.gradle的 debug 代码块中添加以下两行代码禁用它。

1
2
3
4
5
6
7
buildTypes {
...
debug {
splits.abi.enable = false
splits.density.enable = false
}
}

包含最少的资源

在平常的开发构建的情况下,我们可以通过减少语言和屏幕密度等内容来提高速度.

1
2
3
4
5
6
productFlavors {
dev {
resConfigs('en', 'xhdpi')
...
}
}

禁用 PNG 缩进

默认情况 AAPT 会缩进 PNG 来减小他们的大小,但是在平时的开发构建中无关紧要.我们可以通过下面的属性将其设置为 false .

1
2
3
4
5
6
7
buildTypes {
...
debug {
aaptOptions.cruncherEnabled = false
...
}
}

禁用更新构建 ID (Firebase Crashlytyics)

如果有使用 Firebase Crashlytyics 的情况下可以通过以下方式禁用它

1
2
3
4
5
6
buildTypes {
debug {
ext.alwaysUpdateBuildId = false
...
}
}

配置 gradle.properties

1
2
3
4
5
6
7
8
9
10
11
12
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.daemon=true
org.gradle.parallel=true
# 只编译需要的项目,在org.gradle.parallel=true情况下,起很大作用
org.gradle.configureondemand=true
org.gradle.caching=true
android.enableBuildScriptClasspathCheck=false

使用 R8 shrinker

可以在 gradle.properties 文件中通过如下的配置启用它:

1
android.enableR8=true

R8 还提供了更高级的选项,full mode 会带来更多的优化,代价是对 proguard 的兼容性变差

1
android.enableR8.fullMode=true

Android manifest 中占位符

它允许我们动态替换我们在AndroidManifest文件里定义的占位符

1
<meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/>
1
2
3
4
5
android {
defaultConfig {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: 'dev']
}
}

About Me

我的博客 leonchen1024.com

我的 GitHub https://github.com/LeonChen1024

微信公众号

wechat

You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×