转载请注明出处:
Gradle升级4.1(插件3.0.0)变化了哪些东西,需要做哪些改变。
地址:http://www.jianshu.com/p/8c732dc47edd
目录
前言
gradle升级4.1(插件3.0.0,as 3.0.0)改了不少的东西,尤其是依赖的变化。所以我们还是需要了解一下(升级到3.0以后,编译速度快了不少),对以后添加依赖库/改动build.gradle都是有帮助的。上个测试编译时间对比图:
提前准备
升级到gradle插件(gradle-tools)3.0.0:
- 需要gradle版本升级到4.1以上。
- android studio版本升级到3.0.0以上。
- 升级Android SDK Build Tools 版本26.0.0以上
依赖使用api和implementation,废弃compile
区别示意图
提示一下:gradle tools升级到3.0.0以上,compile关键字 已经明确写明废弃了(api关键字的作用等同于之前的compile),但是google官方文档上说“还会保留一段时间,直到下个比较大的gradle tools版本发布”。所以现在仍然使用compile,不会报错。
gradle插件升级到3.0.0以上最大的区别是依赖方式的改变:
implementation的“访问隔离”只作用在编译期
implementation的“访问隔离”只作用在编译期。什么意思呢?如果lib C 依赖了lib A 2.0版本,lib B implementation依赖了lib A 1.0版本:
- 那么编译期,libC 可访问2.0版本的libA ,libB可访问1.0版本的libA。但最终打到apk中的是2.0版本(通过依赖树可看到)。
- 在运行期,lib B 和lib C都可访问lib A的2.0版本(因为apk的所有dex都会放到classLoader的dexPathList中)。
使用implementation有什么好处
- 如果项目中有很多级联的工程依赖,比如上图中lib A B C的依赖是工程依赖。如果使用的依赖方式是compile/api,那么当lib A接口修改后重新编译时,会重新编译libA B C(即使lib C中并没有用到修改的libA的接口)。如果使用implementation依赖,因为“编译期隔离”的原因,不相关的lib就不会进行重新编译。
- 如果项目中都是aar依赖,编译减少时长这个优点就没有了(因为aar已经是编译好的字节码了)。那么还有什么用呢?还是以上图为例。之前我们都是compile依赖,如果lib A已经依赖了lib B,那么在libC的build.gradle中就不用写lib A的依赖了。但这样会有问题:
* 我从lib C的build.gradle的依赖列表中不能完整的知道libC都需要依赖哪些lib。
* 假设这么一种情况,我知道项目中的依赖的libA的最高版本是2.0,那么app运行时就是使用的这个2.0版本的libA。这时候我需要打一个libC的aar。lib C如果通过compile传递依赖了libA,因此从lib C的build.gradle中不知道lib C 编译时依赖的是哪个版本的lib A。如果libC 打aar(编译)时,依赖的仍然libA 1.0,可能这个aar就有问题了。
所以使用implementation是一种比较规范的依赖做法。虽然可能需要多写一写依赖,但是项目的可读性是有很大好处的(虽然多写一些依赖,apk打包运行时仍然是采用最高版本的lib,所以对运行不影响)。
依赖的变种感知(variant-aware dependency)
什么意思呢?一个项目中需要构建的是某个变种(buildType+flavors 如SpeedDebug),那么当构建依赖的lib时,会自动寻找对应的变种(SpeedDebug)进行构建。所以这就有个问题,有可能你依赖的lib里面并没有对应的变种,怎么办吧?新版本的gradle中提供了一些api来解决这种事情,比如:
android {
buildTypes {
debug {}
release {}
staging {
// Specifies a sorted list of fallback build types that the
// plugin should try to use when a dependency does not include a
// "staging" build type. You may specify as many fallbacks as you
// like, and the plugin selects the first build type that's
// available in the dependency.
matchingFallbacks = ['debug', 'qa', 'release']
}
}
}
具体可以看官方指南。不过因为我们的依赖一般都是aar依赖,并且lib中也一般不会写一些特别的buildType或flavor,所以这个对我们没啥影响。
这里需要注意一个规范:
对于渠道类型(flavor),必须添加 flavor dimension,就算你所有的渠道只有一种维度。(好在亮总已经添加过了,所以没我什么事了~~),使用方式就是在productFlavors块前面添加flavorDimensions:
// Specifies two flavor dimensions.
flavorDimensions "tier", "minApi"
productFlavors {
free {
// Assigns this product flavor to the "tier" flavor dimension. Specifying
// this property is optional if you are using only one dimension.
dimension "tier"
...
}
paid {
dimension "tier"
...
}
minApi23 {
dimension "minApi"
...
}
minApi18 {
dimension "minApi"
...
}
}
因为build时有了变种感知功能,所以我们在工程依赖的时候就不需要写类似(写了会报错):
debugImplementation project(path: ':library', configuration: 'debug')
这种的依赖方式的了。当我们build一个debug变种时,对于工程依赖直接写如下所示就可以了:
implementation project(':library')
对于aar依赖,我们仍然可以使用指定变种类型的依赖,如:
debugImplementation 'com.example.android:app-magic:12.3'
围绕变种感知功能,还牵扯一些其他的一些改变,需要的可以看用户指南
一些坑
-
找不到apkVariantData:
Could not get unknown property 'apkVariantData' for object of type com.android.build.gradle.internal.api.ApplicationVariantImpl.
什么原因呢?gradle插件3.0.0版本 升级了gradle的api,导致有些api不能用。恰好AndResGuard 1.2.3版本插件用到了这个过期的api。所以升级没办法了。那AndResGuard有没有新的版本呢?
抱歉,暂时还没有。所以先注释掉。到时候再改吧~
-
需要显示声明annotation Processor库
Error:Execution failed for task ':aimovie:javaPreCompileDebug'.Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.- roboblender-3.0.1.jar (org.roboguice:roboblender:3.0.1)Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
什么原因导致的这个错误呢?在gradle插件3.0.0之前的版本中,如果你写了compile a ,那么不但会把lib a 放到compile classpath 路径下,还会自动放到processor classpath路径下。这会导致processor classpath路径下有大量不必要的依赖,这会更加编译时间。所以从gradle插件3.0.0以后,如果一个库是annotation processors库(如果库中还有META-INF/services/javax.annotation.processing.Processor,那么就认为这是一个annotation processors库),那么需要自己手动使用annotationProcessor关键字添加:
dependencies {
...
annotationProcessor 'com.google.dagger:dagger-compiler:<version-number>'
}
并且,如果发现annotation processors库也存在于compile classpath路径下,那么就会报错。所以这么说的话,我们就不能使用compile/api/implementation来依赖一个annotation processors库了,只能使用annotationProcessor关键字来依赖annotation processors库。但如果annotation processors库也需要放到compile classpath 路径下,怎么办呢?那么需要使用compile/api/implementation再声明依赖一次。注意新版本中,compile/api/implementation这些关键字只会把这个库放到compile classpath路径下,不再放到processor classpath路径下。所以,如果一个annotation processors库要放到processor classpath和compile classpath两个路径下,那么需要用两个关键字声明两次。那么前面说了,如果发现annotation processors库在processor classpath路径会报错,所以需要在android defaultConfig块中进行声明不进行错误检查。
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath false
}
}
}
}
当然,如果不想那么麻烦,直接使用如下配置也可以,但是这样的配置在之后的gradle插件版本中并不支持,所以不推荐。
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath true
}
}
}
}