Gradle 3.0.0 插件可以为大型多模块项目带来显著的性能提升,因此,插件的行为,DSL 和 API 都有一些比较大的变化,所以它对于 Android 是一项重大的升级
升级 Gradle 版本
Android 插件 3.0.0 要求 Gradle 4.1+,如果你使用 Android Studio 3.0(以下简称 AS )或者更高版本打开已有项目,请按相关提示,将现有项目更新为兼容版本的 Gradle
如果想手动修改 Gradle 版本,修改 gradle-wrapper.properties 内的 URL 地址如下
distributionUrl=\
https\://services.gradle.org/distributions/gradle-4.1-all.zip
使用插件
如果你使用 AS 3.0 或者更高版本打开已有项目,请按相关提示,将现有项目更新为最新版本的 Android 插件,如果要手动升级插件,像下面给出的例子来修改项目根目录下的 build.gradle 文件
buildscript {
repositories {
...
// 你需要增加下面的仓库来下载新的插件
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
}
}
使用新的依赖配置
Gradle 3.4 引入了新的依赖库配置,你可以控制这个依赖项具体行为,Android 插件使用了这些新的配置,这可以有效的减少项目的构建时间,下表列出了不同配置的含义以及行为
你的项目有如下依赖关系
App –> moduleA –> moduleB
新的配置项 | 过时的配置项 | 行为 |
---|---|---|
implementation | compile | 如果你的模块 moduleA 配置了 implementation 的依赖 moduleB,当 moduleB 发生变化时,仅会重新编译 B 和 A 而不编译 App,也就是说,implementation 的依赖库发生了变化,Gradle 只会重新编译依赖库和对依赖库有直接依赖关系的 module ,并且 App 内是调用不到 moduleB 的 api 大多数的 app 应该用这个配置项类配置依赖库 |
api | compile | 基本等同于 compile ,在 moduleB 发生变化时,会重新编译整个依赖树,所以编译时间相对 implementation 来说更长 |
compileOnly | provided | 等同于 provided ,只是在参与编译,不会打包到 apk 中(参与编译的意思是:写代码的时候可以直接用,编译出的 apk 并不包含这个类,像 android.jar 里的类 TextView 等) |
runtimeOnly | apk | 可以理解为与 compileOnly 相反,不参与编译,但是会输出到 apk 中,在运行时使用 |
其他类似的有 debugCompile 替换为 debugImplementation 等不再赘述,详见 Gradle 文档
在 Google IO 的相关话题中提到了一个建议,就是依赖首先应该设置为 implementation ,如果没有错,那就用 implementation ,如果有错,那么使用 api ,这样会使编译速度有所增快
注: compile, provided, 和 apk 现在依然可以使用。但是它们将会在下一个重要更新中移除
使用 annotation processor 依赖指令
在旧版本的插件中,你可以通过 compile 添加一个注解处理器,并且它会正常工作,但是这会向处理器添加大量不必要的依赖关系而对性能产生重大影响
在使用 3.0.0 插件时,你必须使用 annotationProcessor 指令来添加注解处理器在 dependencies 中,像下面给出的一样
dependencies {
...
annotationProcessor 'com.google.dagger:dagger-compiler:<version-number>'
}
3.0.0 中如果不使用 annotationProcessor 指令添加注解处理器,那么在编译时将会报错,如果依赖项包含一些组件需要参与编译,则使用 compile 再次依赖此依赖项
使用 AAPT2 的行为变化
为了改善增量资源处理,3.0.0 插件默认启用了 AAPT2 ,尽管 AAPT2 应该能够立即处理旧的项目,但本节仍将介绍一些您应该注意的行为变更
Android 清单文件的元素层次结构
在旧版本 AAPT,清单文件的元素节点嵌套不正确会被忽略或者打印一个警告
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myname.myapplication">
<application
...
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 错误的位置 -->
<action android:name="android.intent.action.CUSTOM" />
</activity>
</application>
</manifest>
旧版本 AAPT 会忽略错误的 <action> 标签,但是在 AAPT2 你将会看到下面的错误
AndroidManifest.xml:15: error: unknown element <action> found.
要解决这个问题,请确保你的清单文件的元素嵌套是正确的,可以参考清单文件结构
资源声明
你将不能再在 name 属性中指定资源类型,像下面这样
<style name="foo" parent="bar">
<item name="attr/my_attr">@color/pink</item>
</style>
上面的代码将会编译出错
Error: style attribute 'attr/attr/my_attr (aka my.package:attr/attr/my_attr)' not found.
解决办法:显式地指定 type=”attr”
<style name="foo" parent="bar">
<item type="attr" name="my_attr">@color/pink</item>
</style>
另外,如果使用 <style> 元素,那么他的 parent 必须也是 style 的资源类型,否则就会报下面的错误
Error: (...) invalid resource type 'attr' for parent of style
错误的使用 @ 资源引用符号
当你忽略或错误地放置资源引用符号 @ 时,AAPT2 现在会触发构建错误,例如
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<!-- 引用资源时缺失 @ 符号 -->
<item name="colorPrimary">color/colorPrimary</item>
</style>
在编译时,AAPT2 将会报下面的错误
ERROR: expected color but got (raw string) color/colorPrimary
此外,请考虑从 android 命名空间访问资源时是否错误地包含该符号,如下所示
<!-- 当从 “android” 命名空间内引用资源时,应省略 @ 符号 -->
<item name="@android:windowEnterAnimation"/>
在编译时,AAPT2 将会报错
Error: style attribute '@android:attr/windowEnterAnimation' not found
声明:本文节选翻译自Migrate to Android Plugin for Gradle 3.0.0,有部分内容是根据自己的理解来写的,如有偏差,欢迎指正