gradle7 从上手到实践之核心API

1 获取 Project

命令行操作:

./gradlew projects

#输出
Root project 'HelloAndroid'
+--- Project ':app'
\--- Project ':TestLib'

Project 对象提供的方法:

//getAllprojects返回所有的project,包括当前project,返回类型:Set集合。
def getProjects() {
    println '-----------------'
    println 'Root Project'
    println '-----------------'

    this.getAllprojects().eachWithIndex { Project project, int index
        if(index == 0) {
            println "Root project : ${project.name}"
        } else {
            println "+--- project : ${project.name}"         
        }
        
    }
}

def getSubprojects() {
    println "-------------------------------------"
    println "Sub Project"
    println "-------------------------------------"

    // 获取所有子project
    this.getSubprojects().eachWithIndex { Project project, int index ->
        println "+---- Project: ${project.name}"
    }
}

/**
 * 获取父Project, 如果本身就是Root Project,返回null
 */
def getMyParentProject() {
    // The parent project, or null if this is the root project.
    if (this.getParent()) {
        println "the parent project name is : ${this.getParent().name}"
    } else {
        println "the parent project is null"
    }
}

/**
 * 获取Root Project,如果本身就是Root Project,返回自己,不会返回null
 */
def getMyRootProject() {
    // The root project. Never returns null.
    def name = this.getRootProject().name
    println "the root project name is: ${name}"
}

2 扩展属性

在 Gradle 对象中使用扩展属性

//settings.gradle 中添加
gradle.ext.testGradleExt=10
println gradle.testGradleExt

在 Project 对象中使用扩展属性

//在根 build.gradle 定义扩展属性

ext {
        compileSdkVersion = 25
        libAndroidDesign = 'com.android.support:design:25.0.0'
    }

//在子 build.gradle 中访问扩展属性
println rootProject.ext.compileSkdVersion
//进一步简化
println rootProject.compileSkdVersion
//扩展属性会被子Project继承,子Project可直接访问
println this.compileSdkVersion

利用扩展属性解决 gradle 脚本中的魔数问题:

//根目录下创建 commmon.gradle 文件:
//用来存放应用中的所有配置变量,统一管理,而不再是每个moudle里都自己写一份,修改起来更加的方便

ext {

  android = [compileSdkVersion   : 25,
             buildToolsVersion   : '25.0.0',
             applicationId       : 'com.youdu',
             minSdkVersion       : 16,
             targetSdkVersion    : 23,
             versionCode         : 1,
             versionName         : '1.0.0',
             multiDexEnabled     : true,
             manifestPlaceholders: [UMENG_CHANNEL_VALUE: 'imooc']]

  signConfigs = ['storeFile'    : 'youdo.jks',
                 'storePassword': 'rzq123456',
                 'keyAlias'     : 'qndroid',
                 'keyPassword'  : 'rzq123456']

  java = ['javaVersion': JavaVersion.VERSION_1_7]


  dependence = ['libSupportV7'           : 'com.android.support:appcompat-v7:25.0.0',
                'libSupportMultidex'     : 'com.android.support:multidex:1.0.1',
                'libCommonLibrary'       : ':vuandroidadsdk',
                'libPullAlive'           : ':lib_pullalive',
                'libCircleImageView'     : 'de.hdodenhof:circleimageview:2.1.0',
                'libSystembarTint'       : 'com.readystatesoftware.systembartint:systembartint:1.0.3',
                'libUmengAnalytics'      : 'com.umeng.analytics:analytics:latest.integration',
                'libUniversalImageLoader': 'com.nostra13.universalimageloader:universal-image-loader:1.9.5',
                'libOkhttp'              : 'com.squareup.okhttp3:okhttp:3.3.0',
                'libAutoScrollViewPager' : 'cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2',
                'libSlidableActivity'    : 'com.r0adkll:slidableactivity:2.0.5',
                'libAndfix'              : 'com.alipay.euler:andfix:0.5.0@aar',
                'libLogger'              : 'com.orhanobut:logger:+',
                'libTinker'              : "com.tencent.tinker:tinker-android-lib:1.7.7",
                'libTinkerAndroid'       : "com.tencent.tinker:tinker-android-anno:1.7.7"]
}
//在根 build.gradle 中
apply from: this.file('common.gradle')
//其他地方引用:
rootProject.ext.android.compileSdkVersion

3 properties

gradle.properties:
gradle.properties 中定义扩展属性,只能定义 Key-value 属性

isLoadTest=false
mCompileSdkVersion=25

gradle 脚本中使用:

if(hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
    include ':Test'
}

android {
    compileSdkVersion mCompileSdkVersion.toInteger()
}

其他 properties:

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
ext."signing.keyId" = properties.getProperty("signing.keyId")
ext."signing.password" = properties.getProperty("signing.password")
ext."signing.secretKeyRingFile" = properties.getProperty("signing.secretKeyRingFile")

4 文件相关 API

//获取路径
println getRoootDir().absolutePath
println getBuildDir().absolutePath
println getProjectDir().absolutePath

//获取文件内容
def getContent(String path) {
    try {
        def file = file(path)  //相对于当前路径查找
        return file.text
    } catch(GradleException e) {
        println 'file not found..'
    }
    return null
}

//文本拷贝
copy {
    from file('youdo.jks')
    into getRootProject().getBuildDir()
}

//拷贝 apk 文件夹
copy {
    from file('build/outputs/apk/')
    into getRootProject().getBuildDir().path + '/apk/' 
}

//对文件树进行遍历
fileTree('build/outputs/apk') {
    fileTree.visit { FileTreeElement element ->
        println 'the file name is:' + element.file.name
        copy {
            from element
            into getRootProject().getBuildDir().path + '/test/'
        }
    }
}

5 依赖相关 Api

settings.gradle 中

pluginManagement { PluginManagementSpec spec -> 
    //配置 gradle 插件的依赖仓库地址,即我们 apply 的 gradle 插件去哪里下载?
    spec.repositories { RepositoryHandler handler ->
        handler.gradlePluginPortal()
        handler.google()
        handler.mavenCentral()
        handler.maven {
            name 'personal'
            url 'http://localhost:8081:/nexus/repositories/'
            credentials {
                username = 'admin'
                password = 'admin123'
            }
        }
    }
}

//根 build.gradle
plugins {
    id 'com.android.application' version '7.1.2' apply false
    id 'com.android.library' version '7.1.2' apply false
}

//配置工程的依赖仓库地址
dependencyResolutionManagement { DependencyResolutionManagement management ->
    management.repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    management.repositories { RepositoryHandler handler ->
        handler.google()
        handler.mavenCentral()
    }
}

// app 下的 build.gradle
dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

依赖方法及其区别

  • implementation api:这种是我们最常用的方式,使用该方式依赖的库将会参与编译和打包。implementation 依赖方式所依赖的库不会传递。api 依赖方式会传递所依赖的库。
  • compileOnly:只在编译时有效,不会参与打包
  • runtimeOnly:只在生成apk的时候参与打包,编译时不会参与,很少用。
  • testImplementation:只在单元测试代码的编译以及最终打包测试apk时有效。
  • debugImplementation:debugCompile 只在debug模式的编译和最终的debug apk打包时有效
  • releaseImplementation:Release compile 仅仅针对Release 模式的编译和最终的Release apk打包

6 执行外部命令

task(name: 'apkcopy') {
    doLast {
        def sourcePath = this.buildDir.path + '/outputs/apk'
        def desationPath = '~/Downloads/'
        def command = "mv -f ${sourcePath} ${desationPath}"
        exec {
            try {
                executable 'bash'
                args '-c' command
                println 'the command is execute success.'
            } catch(GradleException e) {
                println 'the command is execute failed'
            }
        }
    }
}

7 Task

A Task represents a single atomic piece of work for a build, such as compiling classes or generating javadoc.

定义Task

task helloTask {
    println "i am helloTask" //配置阶段执行
}

//通过TaskContainer去创建Task
this.tasks.create(name:'helloTask2') {
    println 'i am helloTask2'
}

//对 Task 进行基本配置
task helloTask(group: 'imooc', description:'task study'){
    println 'i am helloTask  '
}

task helloTask {
    setGroup('imooc')
    setDescription('task study')
    println "i am helloTask" 
}

//doFirst doLast
task helloTask {
    println 'i am helloTask'  //配置阶段执行
    doFirst {
        println 'i am helloTask doFirst'   //执行阶段执行
    }
     doLast {
        println 'i am helloTask doLast'
    }
}

task.doFirst {
        println 'i am helloTask doFirst'
}

执行顺序与依赖

task taskX {
    doLast {
        println 'taskX'
    }
}

task taskY {
    doLast {
        println 'taskY'
    }
}

task taskZ(dependsOn:[taskX, taskY]) {
    dependOn this.tasks.findAll {
        task -> return task.name.startsWith('lib')
    }
    doLast {
        println 'taskZ'
    }
}

task lib1 << {println 'lib1'}
task lib2 << {println 'lib2'}
task nolib << {println 'nolib'}

8 Extension

8.1 什么是 extension

//先定义一个普通的java类,包含2个属性
class Foo {
    int age
    String username

    String toString() {
        return "name = ${username}, age = ${age}"
    }
}
//通过 Project 的 getExtensions 方法创建一个名为 foo 的Extension
Project.getExtensions().create("foo", Foo)

//脚本中配置Extension
foo {
    age = 30
    username = "hjy"
}

task testExt << {
    //能直接通过 project 获取到自定义的 Extension
    println project.foo
}

8.2嵌套的 Extension

class OuterExt {

    String outerName
    String msg
    InnerExt innerExt = new InnerExt()

    void outerName(String name) {
        outerName = name
    }

    void msg(String msg) {
        this.msg = msg
    }

    //创建内部Extension,名称为方法名 inner
    void inner(Action<InnerExt> action) {
        action.execute(innerExt)
    }


    String toString() {
        return "OuterExt[ name = ${outerName}, msg = ${msg}] " + innerExt
    }

}


class InnerExt {

    String innerName
    String msg

    void innerName(String name) {
        innerName = name
    }

    void msg(String msg) {
        this.msg = msg
    }

    String toString() {
        return "InnerExt[ name = ${innerName}, msg = ${msg}]"
    }

}

def outExt = getExtensions().create("outer", OuterExt)

outer {

    outerName "outer"
    msg "this is a outer message."

    inner {
        innerName "inner"
        msg "This is a inner message."
    }

}

task testExt  {
    doLast {
        println outExt
    }

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容