Android Gradle 3.0.0插件是一个大版本的升级,对多个module带来了显著的性能提升。但同时也改变了一些此插件的行为,DSL和APIS。
升级到Gradle3.0.0会带来以下的性能提升:
Android plugin 3.0.0 要求Gradle4.1或者更高的版本。
需要在gradle-wrapper.properties文件中配置下列的内容:
distributionUrl=\
https\://services.gradle.org/distributions/gradle-4.1-all.zip
如果使用Android Studio 3.0或者更新版本,会提示自动更新到最新版本的Android plugin。对于手动更新工程,在工程级下的 build.gradle
配置如下的内容。
buildscript {
repositories {
...
// You need to add the following repository to download the
// new plugin.
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
}
}
NOTICE:
对于多模块和复合构建,如果Android插件每次构建不止一次加载,则可能会出现构建错误,可以查看常见错误进行修复。
要理解旧的Gradle插件2.0构建系统的局限性,请考虑以下具有多层模块的项目:
看最底层的模块,基本上可以做出两种不同的改变:
Note: 在下面的图形中,重新编译的模块将会以红色高亮
由于模块的外部接口不变,Gradle将只重新编译该模块。所有的引用的模块都将保持不变。
在这种情况下没问题。
当外部模块的接口改变,那引用此模块的module也需要重新编译。
但是这些模块可能直接通过自己的接口暴露底层模块的一部分!所以为了完全安全,还需要重新编译。
因此,Gradle将有效地需要重新编译所有模块。
现在我们遇到了一个很大的问题:一个代码更改导致所有模块被重新编译。造成这种情况的根本原因是Gradle不知道是否通过另一个模块泄漏了此模块的接口。
最新的Android Gradle 3.0插件要求您明确定义是否泄漏模块的接口。基于此来判断是否重新编译。
因此 compile
相关的接口被弃用了,引入了如下的接口:
api
: 可以通过自己的接口泄漏了这个模块的接口,这意味着和旧版本的compile
完全一致。 implementation
: 模块的接口只能自己使用,不能泄露给更上层的module中。 从理论上讲,你可以简单地用api依赖替换所有的编译依赖,但是仍然会导致所有的module都被重新编译。
最好的方式是使用implementation
代替所有的compile
。
使用implementation
会减少module重新编译。
Notice: 当想要泄漏底层的module接口给更上层的接口使用
api
。
由于已经接口都已变化,团队也利用这个机会最终给予其他配置适当的名称:
provided
修改为compileOnly
。apk
修改为 runtimeOnly
。Error:All flavors must now belong to a named flavor dimension.
The flavor 'flavor_name' is not assigned to a flavor dimension.
现在插件要求flavors必须属于一个flavor dimension,即使是只有一个flover。
// Specifies two flavor dimensions.
flavorDimensions "tier"
productFlavors {
free {
dimension "tier"
}
paid {
dimension "tier"
}
}
Error:Unable to resolve dependency for ':app@debug/compileClasspath':
Could not resolve project :library.
Error:Unable to resolve dependency for ':app@release/compileClasspath':
Could not resolve project :library.
使用变体的依赖关系解决方案,您不再需要使用特定于变体的配置(例如freeDebugImplementation)来获取本地模块依赖关系 - 插件会自动提供配置。
应该使用下面的配置:
dependencies {
// This is the old method and no longer works for local
// library modules:
// debugImplementation project(path: ':library', configuration: 'debug')
// releaseImplementation project(path: ':library', configuration: 'release')
// Instead, simply use the following to take advantage of
// variant-aware dependency resolution. You can learn more about
// the 'implementation' configuration in the section about
// new dependency configurations.
implementation project(':library')
// You can, however, keep using variant-specific configurations when
// targeting external dependencies. The following line adds 'app-magic'
// as a dependency to only the "debug" version of your module.
debugImplementation 'com.example.android:app-magic:12.3'
}
Process finished with exit code 1
Class not found: "EvaChannelInfoPluginTest"Empty test suite.
是因为Android Studio没有把build/classes/groovy/test添加到 JUnitStarter的classpath中,具体问题以及临时解决方案看此链接 IDE didn’t add build/classes/groovy/test
to JUnitStarter classpath
Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
project :app
考虑一下应用程序配置了一个名为“staging”的build type,但是它的一个依赖库不存在此build type。 当编译应用程序的“staging”版本时,它将不知道要使用依赖库的哪个版本,并且会看到上述类似的错误。
Android Gradle Plugin包含DSL元素,可帮助控制Gradle解决应用程序和依赖项之间的变体匹配不可行的情况。 请参阅下表以确定应使用哪个DSL属性来解决与变体依赖关系匹配相关的某些构建错误。
错误原因:
app包含一个依赖库不包含的build type, 比如,app包含“staging”的build type,但依赖库包含“debug”和“release”的build Type。
Notice: 当依赖库包含app不包含的build type时,不存在问题。这是因为根本不需要依赖库构建 build Type。
解决方案:
使用matchingFallbacks为给定的build type指定替代匹配,如下:
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']
}
}
}
错误原因:
对于app及其依赖库中存在的特定flavor dimension,但app包含库不包含的flavor。
比如,app和依赖都包含一个 “tier” 的flavor dimension。然而app中”tier” 包含 “free”和”paid”,但依赖库仅仅包含”demo” and “paid”。
Notice: 对于存在于app及其依赖库的给定flavor dimension,当库包含app所不具备的flavor时,不存在任何问题。 那是因为android gradle plun根本就不会从依赖中请求app不包含的flavor。
解决方案:
使用matchingFallbacks为app的“free”的flavor指定替代匹配,如下所示:
// In the app's build.gradle file.
android {
defaultConfig{
// Do not configure matchingFallbacks in the defaultConfig block.
// Instead, you must specify fallbacks for a given product flavor in the
// productFlavors block, as shown below.
}
flavorDimensions 'tier'
productFlavors {
paid {
dimension 'tier'
// Because the dependency already includes a "paid" flavor in its
// "tier" dimension, you don't need to provide a list of fallbacks
// for the "paid" flavor.
}
free {
dimension 'tier'
// Specifies a sorted list of fallback flavors that the plugin
// should try to use when a dependency's matching dimension does
// not include a "free" flavor. You may specify as many
// fallbacks as you like, and the plugin selects the first flavor
// that's available in the dependency's "tier" dimension.
matchingFallbacks = ['demo', 'trial']
}
}
}
错误原因:
依赖库包含app不支持的flavor dimension。
比如,依赖库包含“minApi”的flavor dimension,但是app不包含,当构建“freeDebug”版本的时候,插件不知道是使用“minApi23Debug”还是“minApi18Debug”的版本的依赖库
Notice: 当app包含一个flavor dimension,但依赖库不存在这是没问题的。这是因为插件仅仅匹配存在于依赖库里的flavor dimension,比如依赖库不包含ABIs的dimension,app的”freeX86Debug” 仅仅配置依赖库的“freeDebug”版本。
解决方案:
在defaultConfig
的配置中使用missingDimensionStrategy
指定遗失的dimension。也可以在productFlavors
来复写默认配置。
/ In the app's build.gradle file.
android {
defaultConfig{
// Specifies a sorted list of flavors that the plugin should try to use from
// a given dimension. The following tells the plugin that, when encountering
// a dependency that includes a "minApi" dimension, it should select the
// "minApi18" flavor. You can include additional flavor names to provide a
// sorted list of fallbacks for the dimension.
missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
// You should specify a missingDimensionStrategy property for each
// dimension that exists in a local dependency but not in your app.
missingDimensionStrategy 'abi', 'x86', 'arm64'
}
flavorDimensions 'tier'
productFlavors {
free {
dimension 'tier'
// You can override the default selection at the product flavor
// level by configuring another missingDimensionStrategy property
// for the "minApi" dimension.
missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
}
paid {}
}
}