gradle 大纲

322 阅读3分钟

一.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插件
    1. 配置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

六.gradle构建优化