Gradle核心(二):Gradle Project詳解及實戰

博客主頁java

在講解Task以前,先了解Gradle核心之Project詳解及實戰android

Project相關的API

獲取Project

查看全部的Project,在Gradle中爲咱們提供了Task任務projects,執行下面命令後,會列出全部的Projectsegmentfault

> gradlew projects

// 執行上面命令後,列出全部的project,包括Root project
------------------------------------------------------------
Root project
------------------------------------------------------------

Root project 'walletApp'
\--- Project ':app

咱們能夠經過Project提供的API訪問全部的project。getAllprojects返回全部的project,包括當前project,返回類型:Set集合bash

def getMyAllProjects() {
    println "-------------------------------------"
    println "Root Project"
    println "-------------------------------------"

    // 獲取全部project,包括自己
    this.getAllprojects().eachWithIndex { Project project, int index ->

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

也提供了getSubprojects返回全部子project,返回類型:Set集合閉包

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

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

除了上面兩種方式,還提供了獲取 Parent projectRoot project ,對應的方法分別是getParent()getRootProject()。他們主要區別是,getParent()若是自己就是Root Project,則返回null;而getRootProject()若是自己就是Root Project,返回Root project,不會返回nullapp

/**
 * 獲取父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}"
}

統一配置Project

能夠在Root project中經過Project提供的project方法對單個project進行獨立配置,如應用插件、project分組、project版本、依賴等信息maven

project('app') { Project project ->
    project.apply plugin: 'com.android.application'
    project.group 'com.yqb.mm'
    project.version '1.0.0'

    project.dependencies {

    }
}

每一個Project都會有一個Build文件,能夠經過Project提供的subprojects 或者 allprojects 能夠對Child Project統一配置gradle

this.subprojects {
    println "The project name is ${project.name}"
}

// 輸出日誌信息
The project name is app
The project name is basiclib

屬性相關的API

Project默認提供下面幾種屬性,從下圖中能夠看出,爲何gradle中build文件名是build.gradle了。
ui

除了Project默認提供的,咱們也能夠經過ext關鍵字自定義屬性。下面是咱們自定義的應用包名、版本信息、依賴、簽名文件等相關信息。this

ext {
    applicationId = "com.kerwin.test"

    // android sdk version
    // 使用以下:
    // def versions = rootProject.ext.versions
    // compileSdkVersion versions.compileSdkVersion
    // buildToolsVersion versions.buildToolsVersion
    versions = [
            compileSdkVersion: 26,
            minSdkVersion    : 19,
            targetSdkVersion : 26,
            versionCode      : 182,
            versionName      : '1.8.2',
    ]

    // dependencies
    // 使用以下:
    // def dependencies = rootProject.ext.dependencies
    // compile dependencies.support.appcompat
    dependencies = [
            support     : [
                    appcompat : "com.android.support:appcompat-v7:26.1.0",
                    constraint: "com.android.support.constraint:constraint-layout:1.1.3",
                    design    : "com.android.support:design:26.1.0"
            ],
            gson        : "com.google.code.gson:gson:2.8.5"
    ]

    signingConfigs = [
            debug: [
                    storeFile    : '../keystore/mm_debug.keystore',
                    storePassword: 'pa123456',
                    keyAlias     : 'mm_key',
                    keyPassword  : 'pa123456',
            ]
    ]
}

除了上面方式自定義屬性外,還能夠在gradle.properties文件中定義,但只能是簡單的Key-Value形式.
gradle.properties文件中自定義以下屬性:

// gradle.properties
TINKER_ENABLE=true

例如能夠在settings.gradle文件中根據在gradle.properties文件中定義的屬性作一些操做

if (hasProperty('TINKER_ENABLE') ? Boolean.parseBoolean(TINKER_ENABLE) : false) {
    println "TINKER_ENABLE 打開了."
} else {
    println "TINKER_ENABLE 關閉了."
}

// 當TINKER_ENABLE=true,輸出日誌信息
TINKER_ENABLE 打開了.

文件相關API

路徑獲取相關API

在Project中提供了不少獲取文件路徑的方法,如:getProjectDir()getRootDir()getBuildDir()

// Root project的根目錄路徑
println "the root directory of this project, ${project.getRootDir().absolutePath}"
// 當前project的build文件路徑
println "the build directory of this project, ${project.getBuildDir().absolutePath}"
// 當前project的目錄路徑,若是當前project是Root project,等同於getRootDir()
println "The directory containing the project build file, ${project.getProjectDir().absolutePath}"

// 輸出的日誌信息
the root directory of this project, D:\work\yqb.com\newCode\merchantApp
the build directory of this project, D:\work\yqb.com\newCode\merchantApp\build
The directory containing the project build file, D:\work\yqb.com\newCode\merchantApp

文件操做相關API

文件的定位,根據文件路徑獲取文件內容
println getContent('settings.gradle')

def getContent(String path) {
    try {
        def file = file(path)
        return file.text
    } catch (Exception ex) {
        println "getContent has error: ${ex.getMessage()}"
        return ""
    }
}
文件拷貝

Project爲咱們提供了簡便的方法copy對文件進行拷貝。

def copyApk() {
    this.copy {
//        srcApkDir>>> D:\work\yqb.com\newCode\merchantApp\app\build\bakApk
//        destApkDir>>> D:\work\yqb.com\newCode\merchantApp\build\apk

        // from 用於指定拷貝的源文件或者文件夾
        from file("${buildDir}/bakApk/")
        
        // into 用於指定拷貝的目的地
        into file("${getRootProject().getBuildDir().path}/apk")
    }
}

除了使用frominto 指定源路徑和目的地以外,還能夠配置拷貝後使用rename文件從新命名、exclude移除不需拷貝的文件等。

def copyApk() {
    this.copy {
//        srcApkDir>>> D:\work\yqb.com\newCode\merchantApp\app\build\bakApk
//        destApkDir>>> D:\work\yqb.com\newCode\merchantApp\build\apk
        // 指定拷貝的源文件或者文件夾
        from file("${buildDir}/bakApk/")

        // 指定拷貝的目的地
        into file("${getRootProject().getBuildDir().path}/apk")

        // 移除不須要拷貝的文件, 例如:不拷貝以txt結尾的文件
        //exclude "**/*.txt"

        // 也可使用閉包,移除不須要拷貝的文件
        exclude { details ->
            println "exclude>>> file: ${details.file}"
            return details.file.name.endsWith('.txt')
        }

        // 從新命名拷貝的文件名
        rename { String fileName ->
            println "rename>> fileName: ${fileName}"
            fileName.replace("app-arm-debug.apk", "test.apk")
        }
    }
}
文件樹遍歷

Project提供的fileTree方法,能夠將指定文件目錄下全部的文件封裝成文件樹對象操做

fileTree("build/outputs/apk") { ConfigurableFileTree fileTree ->
    fileTree.visit { FileVisitDetails details ->
        println "The file name is ${details.file}"

        copy {
            from details.file
            into "${getRootProject().getBuildDir().path}/apk"

            exclude { file ->
                return file.file.isDirectory()
            }
        }
    }
}

依賴相關API

Project提供了依賴相關的API,如 buildscript

buildscript {
    repositories {
        maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath 'com.alibaba:arouter-register:1.0.2'
      
        classpath("com.tencent.tinker:tinker-patch-gradle-plugin:${TINKER_VERSION}") {
            changing = TINKER_VERSION?.endsWith("-SNAPSHOT")
            exclude group: 'com.android.tools.build', module: 'gradle'
        }
    }
}

執行外部命令API

可使用Project提供的javaexec 或者 exec 執行一個外部命令。使用外部命令實現一個copy功能

tasks.create(name: 'copyAPK') {
    doLast {
        def srcFilePath = this.buildDir.path + "/outputs/apk"
        def destFilePath = this.buildDir.path + "/outputs/backup"
        def command = "mv -f ${srcFilePath} ${destFilePath}"

        exec { ExecSpec execSpec ->
            try {
                executable 'bash'
                args '-c', command
            } catch (Exception ex) {
                println "copyAPK>>> error: ${ex}"
            }
        }
    }
}

若是個人文章對您有幫助,不妨點個贊鼓勵一下(^_^)

相關文章
相關標籤/搜索