一.gradle 学习大纲
agp 源码查看方式
在app/build.gradle中添加项目使用的android gradle plugin的版本的依赖,可以从project structure - project - android gradle plugin version 查看
compileOnly "com.android.tools.build:gradle:4.1.2"
gradle dsl 地址
developer.android.com/reference/t…
二.gradle构建流程大纲
gradle脚本执行流程大纲
初始化阶段
执行setting.gradle并且构建project对象,setting对象 识别并且处理module对象
细节1 可以通过配置:dir来配置依赖的模块的目录
这个阶段有两个钩子函数
gradle.projectsLoaded {
}
gradle.settingsEvaluated {
}
配置阶段
配置任务依赖关系,构建有向无环图 在这个阶段,我们设定好各个任务的依赖关系,和一些初始化的变量,这个阶段我们已经有了Project对象
//所有的module都生效
gradle.beforeProject {
}
//所有的module都生效
gradle.afterProject {
}
//仅仅当前的project生效
beforeEvaluate {
}
//仅仅当前的project生效
afterEvaluate {
}
执行阶段
根据任务依赖关系,执行任务列表
三.自定义gradle task
class RenameTask extends DefaultTask{
RenameTask(){
group "重命名任务"
description "输出重命名"
}
@Input
@Option
String inputFile
@OutputFile
@Option
String outputFile
@TaskAction
def rename(){
println "rename actioned"
}
}
//tasks.create("rename" , RenameTask)
task rename(type:RenameTask){
}
方式二
task test doLast{
println "do Last"
}
project 对象
- 每个build.gradle在配置阶段中会产生一个project对象
- allProjects{} 可以对所有的模块配置生效
- subProjects 对子模块生效
ext
- ext 是一个方法
- 所有的对象都可以使用ext扩展属性
- gradle.properties配置的属性对所有的project都可见
四.自定义gradle 插件
- 脚本插件(xxx.gradle)
apply from : "zip.gradle"
- 二进制插件
class MyPlugin implements Plugin<Project>{
@Override
void apply(Project target) {
println "MyPlugin project is ${target}"
}
}
apply plugin: MyPlugin
buildSrc
公共的构建脚本,会被自动添加到脚本的classPath中,因此在任何的module中都可以直接引用
apply plugin :ZipPlugin
public class ZipPlugin implements Plugin<Project> {
@Override
public void apply(Project target) {
target.afterEvaluate(project -> {
Task task = project.getTasks().getByName("packageDebug");
System.out.println("task is " + task);
if (task != null){
task.doLast(task1 -> {
Map<String , Class<?>> map = new HashMap<>();
map.put("type" , Zip.class);
Zip zipTask = (Zip)project.task(map , "zipTask");
zipTask.getArchiveFileName().set("outputs.zip");
zipTask.getDestinationDirectory().set(new File(project.getBuildDir().getAbsolutePath() +"/custom"));
FileCollection files = task.getOutputs().getFiles();
System.out.println("zip to path ==>" + zipTask.getDestinationDirectory().get().getAsFile().getAbsolutePath());
for (File file :
files) {
System.out.println("output file name ===>" + file.getName());
}
zipTask.from(files);
});
}
});
}
}
gradle 依赖管理-依赖冲突解决
打印依赖树
./gradlew :app:dependencies --configuration releaseRuntimeClasspath
依赖冲突解决的三种方式
- 1.单个依赖添加exclude排除依赖
implementation "com.duowan.ark:base:${ark_version}", {
exclude group:"com.duowan.ark", module: "eventbus"
exclude group:"com.duowan.ark"
}
- 2.公共配置通过resolutionStratege指定特定版本
configurations.all {
resolutionStrategy {
force "com.huya.mtp:furion:${furion_version}"
force "com.huya.mtp:mtpencrypt-adr:1.1.100"
force "com.huya.mtp:udb-wrapper-api:1.3.450"
force "com.huya.mobile.security:hydeviceid:1.6.18"
force "com.huya.mtp:didbase:2.5.202"
force "com.huya.mtp:didsdk:2.5.202"
}
}
- 3.在configurations中添加configuration排除依赖
configurations{
configuration{
all*.exclude module:"eventbus"
}
}
- 4.在某个依赖下申明强制使用 表示强制使用某个版本
implementation 'com.github.chrisbanes:PhotoView:2.3.0'{
force true
}
五.gradle 常用方法分析
productFlavor , flavorDimensions,buildTypes
defaultConfig {
applicationId "com.hch.ioc"
minSdkVersion 22
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
debug {
storeFile file("../debug.keystore")
storePassword "123456"
keyAlias "debug"
keyPassword "123456"
v2SigningEnabled false
}
config {
v2SigningEnabled false
}
release {
v2SigningEnabled false
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug{
minifyEnabled false
signingConfig signingConfigs.debug
}
}
flavorDimensions "version","api"
productFlavors{
huawei{
dimension "version"
}
qihoo{
dimension "version"
}
api21{
dimension "api"
}
api23{
dimension "api"
}
}
组合输出的build类型为,一共6种
[huawei , qihoo][api21 , api23][debug,release]
一些tips说明
-
1.所有的build类型默认配置继承自defaultConfig
-
2.resValue
可以向app的res/values中动态加入一些配置信息,会自动在res下生成一个gradleResValue.xml文件
defaultConfig {
...
resValue "string" , "defaultName" , "Lucy"
}
flavorDimensions "version","api"
productFlavors{
huawei{
resValue "string" , "testAddName" , "Jack"
}
api21{
dimension "api"
buildConfigField "Boolean", "isRelease", "false"
}
}
生成的文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Automatically generated file. DO NOT MODIFY -->
<!-- Value from product flavor: huawei -->
<string name="testAddName" translatable="false">Jack</string>
<!-- Value from default config. -->
<string name="defaultName" translatable="false">Lucy</string>
</resources>
- 3.buildConfigField
向动态生产的BuildConfig.java中插入一些变量,可以加在defaultConfig中,或者加在productFlavor中
defaultConfig {
...
buildConfigField "int", "defaultValue", "1"
resValue "string" , "defaultName" , "Lucy"
}
flavorDimensions "version","api"
productFlavors{
huawei{
dimension "version"
buildConfigField "Boolean", "isRelease", "false"
}
api21{
dimension "api"
buildConfigField "Boolean", "isRelease", "false"
}
}
- 3.sourceSets
用于指定编译期间各个目录的路径 sourceSets主要用在组件化处理中,需要对于组件的不同的模式如组件模式或模块模式 分别加载不同的manifest文件以及对应的src文件
sourceSets {
sourceSets.each{its->
println "source set --> ${its}"
}
main{
java {
srcDirs "src/main/java"
srcDirs "src/baidu/java"
exclude "com/bd/hch/TestInBaiduExclude.java"
}
// manifest.srcFile = ['src/main/AndroidManifest.xml']
manifest {srcFile}
// res.srcDirs = ["src/main/res"]
res{srcDirs "src/main/res"}
// jniLibs.srcDirs = ['libs']
jniLibs{
srcDirs "libs"
}
}
huawei{
java{
}
}
}
- 4.adbOptions 比较常见的-d 和 -g
// -r: replace existing application
// -t: allow test packages
// -d: allow version code downgrade (debuggable packages only)
// -p: partial application install (install-multiple only)
// -g: grant all runtime permissions
adbOptions{
installOptions "-d"
installOptions "-g"
}
- 4.分包
将app继承自MultiDexApplication, 或者在onAttachBase中执行MultiDex.install(this)
multiDexEnabled true
aar的依赖与构建
aar的构建与打包
- 1.新建android module,命名为testAAR
- 2.并添加测试代码,
- 3.执行打包构建命令
./gradlew :testAAR:assembleRelease
- 4.会生成build/outputs/testAAR-release.aar
aar的依赖
- 方式一
implementation fileTree(dir: 'libs', include: ['*.jar' , "*.aar"])
- 方式二
此处的repositories 要放在android{}中
repositories {
flatDir {
dirs "libs"
}
}
implementation name:"testAAR-release" , ext:"aar"
aar的发布 maven
- 1.使用maven-publish 插件 和 signing插件
-
- 配置publications 发布的aar相关的信息
- 3.配置repositories 发布的url相关的信息
在gradle.prperties中配置
version=1.1.0
GROUP=com.hch.testAAR
一个典型的发布mave仓库的模板
apply plugin: 'com.android.library'
//所有工程都要用的公共配置,由各个子模块直接apply from
apply plugin: 'maven-publish'
apply plugin: 'signing'
def getReleaseRepositoryUrl() {
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
: "https://oss.sonatype.org/content/repositories/releases/"
}
def getSnapshotRepositoryUrl() {
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
: "https://oss.sonatype.org/content/repositories/snapshots/"
}
def getRepositoryUsername() {
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "admin"
}
def getRepositoryPassword() {
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "admin123"
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles
}
//android.libraryVariants
project.afterEvaluate {
publishing {
publications {
maven(MavenPublication) {
groupId project.group
artifactId project.name
version version
artifact androidSourcesJar
artifact bundleReleaseAar
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
def configurationNames = ["releaseCompile", 'compile', 'api', "implementation"]
//Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each
configurationNames.each { configurationName ->
if (!configurations.names.contains(configurationName)) {
return
}
configurations[configurationName].allDependencies.each {
if(it.group != null && it.name != null)
{
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
if (it.artifacts.size() > 0)
{
it.artifacts.each { rule ->
if (rule.classifier != null)
{
println "rule.classifier = " + rule.classifier
dependencyNode.appendNode('classifier', rule.classifier)
}
if (rule.type != null)
{
println "rule.type = " + rule.type
dependencyNode.appendNode('type', rule.type)
}
}
}
}
}
}
}
}
}
}
}
def getRepositoryUrl() {
if (version != null && version.toLowerCase().endsWith("snapshot")) {
return getSnapshotRepositoryUrl()
} else {
return getReleaseRepositoryUrl()
}
}
publishing {
repositories {
maven {
url getRepositoryUrl()
credentials {
username = getRepositoryUsername()
password = getRepositoryPassword()
}
}
}
}
执行aar任务publish ,publish是mave自带的任务,它依赖于assembleRelease
./gradlew publish