最近一周都在搞这玩意了,写点文档给后人参考吧。
一、Gradle 对模块的描述
这里使用2个例子,只有一个模块,例如使用 Intellij 创建的新工程;只有两个模块(父子关系),例如使用 AndroidStudio 创建的默认 App。
1 2 3 4 5 6 7 8 9 10 11 12
| ➜ HelloGradle lsa total 40 drwxr-xr-x 12 leadroyal staff 384B 7 19 18:04 . drwxr-xr-x 7 leadroyal staff 224B 7 21 21:09 .. drwxr-xr-x 4 leadroyal staff 128B 7 12 14:13 .gradle drwxr-xr-x 7 leadroyal staff 224B 7 19 18:08 .idea -rw-r--r-- 1 leadroyal staff 492B 7 19 18:04 build.gradle drwxr-xr-x 3 leadroyal staff 96B 7 12 14:13 gradle -rwxr-xr-x 1 leadroyal staff 5.2K 7 12 14:13 gradlew -rw-r--r-- 1 leadroyal staff 2.2K 7 12 14:13 gradlew.bat -rw-r--r-- 1 leadroyal staff 34B 7 12 14:13 settings.gradle drwxr-xr-x 4 leadroyal staff 128B 7 18 15:55 src
|
- .gradle 存放一些临时的东西,要 gitignore 掉
- .idea intellij全家桶的临时文件,要 gitignore 掉
- build.gradle 必备,描述当前模块的主要信息,经常需要编辑(例如sourceSets、plugin、dependencies等)
- gradle 必备,存放描述当前 gradle 版本的文件和一个 wrapper
- gradlew、gradlew.bat 必备,是启动脚本
- settings.gradle 非必备,但经常有,描述模块的名称、目录
- src,非必须,只是一般这么命名了,用来存放代码
再看看build.gradle 的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| plugins { id 'java' }
group 'com.leadroyal' version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories { mavenCentral() }
jar { from { configurations.runtime.collect { zipTree(it) } } manifest { attributes 'Main-Class': "Hello" } } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile 'com.qcloud:cos\_api:5.4.4' compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5'
}
|
plugins是使用的插件,常见的有java、scala、shadow、springboot、maven,这种。
repositories是仓库,表示寻找依赖的地方,例如mavenCentrol、jCenter、mavenLocal这种。
jar 是指执行名为 "jar"的这个task 时需要做什么,这里写法不优雅,不要模仿,就是打包。
dependencies 是依赖,compile 是老一点的写法了,新写法是 implement,但还没有被废弃,compile 有两种格式。这个地方可能会 exclude 一些依赖中的依赖,或者 force 指定依赖版本。如果是依赖另一个本地 gradle 模块的话,使用compile project(":sub")这种格式。
再看看Android App的目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ➜ ctfposed lsa total 88 drwxr-xr-x 18 leadroyal staff 576B 6 7 14:12 . drwxr-xr-x 12 leadroyal staff 384B 6 1 16:00 .. drwxr-xr-x 4 leadroyal staff 128B 4 20 2017 .gradle drwxr-xr-x 12 leadroyal staff 384B 6 7 16:03 .idea drwxr-xr-x 12 leadroyal staff 384B 5 28 10:55 app -rw-r--r-- 1 leadroyal staff 498B 4 20 2017 build.gradle -rw-r--r-- 1 leadroyal staff 862B 2 25 2017 ctfposed.iml drwxr-xr-x 3 leadroyal staff 96B 2 25 2017 gradle -rw-r--r-- 1 leadroyal staff 932B 11 28 2017 gradle.properties -rwxr--r-- 1 leadroyal staff 4.9K 2 25 2017 gradlew -rw-r--r-- 1 leadroyal staff 2.3K 2 25 2017 gradlew.bat drwxr-xr-x 3 leadroyal staff 96B 2 3 17:35 lib -rw-r--r-- 1 leadroyal staff 523B 2 25 2017 local.properties -rw-r--r-- 1 leadroyal staff 15B 2 25 2017 settings.gradle
|
文件内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ➜ ctfposed cat build.gradle // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.0'
// NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } }
allprojects { repositories { jcenter() } }
task clean(type: Delete) { delete rootProject.buildDir }
|
这个说了等于没说,里面啥也没。
再看看 settings.gradle,原来引用了名叫":app"的子模块,所以要到"app"这个目录下去找。
1 2
| ➜ ctfposed cat settings.gradle include ':app'
|
看看子模块的目录,刚好和之前的一样,但是没有 settings.gradle。
1 2 3 4 5 6 7 8 9 10 11 12 13
| ➜ ctfposed lsa app total 72 drwxr-xr-x 12 leadroyal staff 384B 5 28 10:55 . drwxr-xr-x 18 leadroyal staff 576B 6 7 14:12 .. drwxr-xr-x 3 leadroyal staff 96B 4 20 2017 .externalNativeBuild -rw-r--r-- 1 leadroyal staff 7B 2 25 2017 .gitignore -rw-r--r-- 1 leadroyal staff 343B 5 30 2017 CMakeLists.txt -rw-r--r-- 1 leadroyal staff 11K 5 28 10:55 app.iml drwxr-xr-x 6 leadroyal staff 192B 2 3 17:38 build -rw-r--r-- 1 leadroyal staff 1.0K 4 14 23:06 build.gradle drwxr-xr-x 5 leadroyal staff 160B 4 14 23:06 libs -rw-r--r-- 1 leadroyal staff 667B 2 25 2017 proguard-rules.pro drwxr-xr-x 5 leadroyal staff 160B 2 25 2017 src
|
看看里面的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| ➜ ctfposed cat app/build.gradle apply plugin: 'com.android.application'
android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.leadroyal.ctfposed" minSdkVersion 16 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { // Specifies the ABI configurations of your native // libraries Gradle should build and package with your APK. abiFilters 'armeabi-v7a' }
} buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "CMakeLists.txt" } } }
dependencies { provided files('libs/XposedBridgeApi-54.jar') provided files('libs/hotposed.jar') compile 'com.android.support:appcompat-v7:25.1.0' compile files('libs/core-1.58.0.0.jar') }
|
嗯,使用了 com.android.application 插件,写了 android 这个东西,写了dependencies这个依赖。很清晰!
二、子模块使用独立的 build.gradle 的目录结构
最直观的就是 android 这个例子了,只有3个gradle文件。
1 2 3 4 5 6 7
| ➜ HelloWidget find . | grep \\w\\+\\.gradle ./app/build.gradle ./build.gradle ./settings.gradle
➜ HelloWidget cat ./settings.gradle include ':app'
|
父模块里,settings.gradle 里写了子模块,叫 :app ,没有特别说明路径的话,就在app这个路径下。
子模块没有settings.gradle,这个无所谓,可有可无,也只是写几个名字而已。这也是我们最常见的格式,一父一子,父模块里写一些通用的设置,大部分代码都在子模块里。
再看另一个例子,我们手动创建Intellij项目,再多创建几个子模块。它们之间暂时没有依赖关系,相互虽然可能在 intellij 里会有提示,其实是相互不可见的那种。
这个 demo,在intellij里面操作非常方便,先创建空的 gradle 项目,会帮我们生成build.gradle 和 setting.gradle。
之后在里面创建新的gradle模块,选择Java类型,帮助我们自动生成 java 模板的 build.gradle。依法炮制,多创建几个java类型的 module,它们并没有什么联系,是相互独立的子项目。
1 2 3 4 5 6
| ➜ simple-gradle find . | grep \\w\\+\\.gradle ./part3/build.gradle ./part2/build.gradle ./part1/build.gradle ./build.gradle ./settings.gradle
|
这时候可以发现settings.gradle已经悄悄将它们 include 进来了。
1 2 3 4 5
| ➜ cat settings.gradle rootProject.name = 'simple-gradle' include 'part1' include 'part2' include 'part3'
|
在 build.gradle 里仍然是最开始的设置,这是第一种结构,子模块拥有独立的 build.gradle 文件。
右侧截图如图
三、子模块使用父模块的 build.gradle 的目录结构
还是上面那个例子,我们改成只使用父模块的一个 build.gradle 文件的格式。
改之前:
1 2 3
| ➜ simple-gradle cat build.gradle group 'com.leadroyal' version '1.0-SNAPSHOT'
|
基本什么都没有。
改之后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| ➜ simple-gradle cat build.gradle allprojects { group 'com.leadroyal' version '1.0-SNAPSHOT' } subprojects { apply plugin: "java" sourceCompatibility = 1.8 repositories { mavenCentral() } } project(":part1") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":part2") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":part3") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":full") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } }
|
这里需要使用 project(":part1") 这种方式来引入子模块,这样就可以删掉原来在分散的 build.gradle 的各种配置。
同样,在右侧可以看到合理的结构。
这里还可以使用 allprojects 和 subprojects 来批量进行一些操作,非常舒服。区别在于,allprojects 包括自己,而subprojects 不包括自己。
四、子模块之间如何相互依赖
还是以这part1/2/3为例,假设1独立,3依赖2。再写个总的,同时依赖1/2/3。 平时我们依赖一般都是依赖 maven 库,这里依赖本地的 project 的话,要用
compile project(":project-name")
例如我们刚刚说的这个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| ➜ simple-gradlecat build.gradle allprojects { group 'com.leadroyal' version '1.0-SNAPSHOT' } subprojects { apply plugin: "java" sourceCompatibility = 1.8 repositories { mavenCentral() } } project(":part1") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":part2") { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":part3") { dependencies { compile project(":part2") testCompile group: 'junit', name: 'junit', version: '4.12' } } project(":full") { dependencies { compile project(":part1") compile project(":part2") compile project(":part3") testCompile group: 'junit', name: 'junit', version: '4.12' } }
|
写了4个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.example.pkg1;
public class Part1 { }
package com.example.pkg2;
public class Part2 { }
package com.example.pkg3;
import com.example.pkg2.Part2;
public class Part3 extends Part2 { }
package com.example.full;
import com.example.pkg1.Part1; import com.example.pkg2.Part2; import com.example.pkg3.Part3;
public class Main { public void func() { Part1 p1 = new Part1(); Part2 p2 = new Part2(); Part3 p3 = new Part3(); } }
|
这个配置是可以正常编译通过的。
五、命令行里的一些操作
./gradlew build
使用当前项目提供的 gradle 版本和配置。
gradle build
使用系统提供的 gradle 版本和配置。
gradle dependencies
打印所有编译选项的依赖。
gradle dependencies -q --configuration runtime
仅打印runtime执行时的依赖。
gradle part1:build
执行 part1这个 project 的 build 任务。