《在飞Android Gradle实战》之核心模块Project2

hi各位小伙伴,前面《在飞Android Gradle实战》之生命周期1我们已经介绍了Gradle的生命周期。

      只有了解了gradle的生命周期才能写出正确的脚本代码。初始化阶段gradle会完成所有工程的初始化,决定我们的项目有多少个子项目 这个阶段重点就是解析setting.gradle文件,初始化阶段完毕就是配置阶段,build.gradle中的代码大部分都是执行在配置阶段的,配置阶段执行完之后就是运行阶段,在 运行阶段段真正执行task中的逻辑,只有知道这三个阶段的作用,才能写出正确的脚本代码,否则代码很容易执行再错误的生命周期。

前言:

  了解完生命周期之后,还需要了解一个核心内容就是Project,Project是脚本的入口,只有了解了它才能开始真正的脚本开发。

  还是一样的风格,只讲实战中经常用到的内容,让你快速入门和使用,加上我自己的分析让你更加清楚的了解这些内容。至于基础知识请自己学习~。

本章难度:简单  普通 困难    

本章重要程度:普通 重要 核心

 

一:什么是Project

     在Android Studio的Terminal中调用./gradlew projects就可以看到你项目中有哪些project了。

《在飞Android Gradle实战》之核心模块Project2_第1张图片

上图中显示,我们的项目有3个project。

project有个特征,就是每个里面都有一个build.gradle文件。所以可以通过它来判断是否是project。

《在飞Android Gradle实战》之核心模块Project2_第2张图片

如上图,由三个project组成:Root poject:'dap-audience-network'  2个子project:'buildSrc'、'ToolboxSample'

二:Project API

1.getAllProjects() 获取所有project,包括自己。getSubproject()获取子project,不包括自己

//====获取所有project 类似./gradlew projects====
def getProjects() {
    println '-----'
    //eachWithIndex是遍历
    this.getAllprojects().eachWithIndex { Project project, int index ->
        println "project:${project.name}"//输出project的Name
    }
    println '-------'
    //获取子project
    this.getSubprojects().eachWithIndex { Project subProject, int index ->
        println "project_subject:${subProject.name}"//输出subproject的Name
    }
    println '-------'
    def rootName = this.getRootProject().name
    println "root_project:${rootName}"//输出根project的名字
}

this.getProjects()

《在飞Android Gradle实战》之核心模块Project2_第3张图片

2.使用Project API管理project

//针对project'ToolboxSample'这个project操作配置些内容
project('ToolboxSample'){
    apply plugin 'com.android.application'  //输出格式是application
    group 'com.inmoc'    //指定分组
    version '1.0.1'      //指定版本
    dependencies{      //配置依赖模块

    }
    android{} //配置android模块
    
}

=====
//针对自己及子project配置
allprojects{}
//只包括子工程,不包含自己
subprojects{Project project ->
    //如果是库工程,让他支持Maven功能
    if (project.plugins.hasPlugin('com.android.library')) {
        apply from: '../publishToMaven.gradle'
    }
}

不通点:上面这个例子中的不通点就是作用范围不同allprojects{}>subprojects{}>project{}

经验:

    通过allprojects{},subprojects{},project{}可以在多submodule的开发环境中很好使用,可以批处理部分功能,不需要多个build.gradle中都写一遍。

3.Project属性api

//Project默认属性
public interface Project extends Comparable, ExtensionAware, PluginAware {
    /**
     * The default project build file name.(看到这个属性API我们就知道了为什么我们project中会有一个build.gradle而不是其他名字的原因)
     */
    String DEFAULT_BUILD_FILE = "build.gradle";

    /**
     * The hierarchy separator for project and task path names.(project使用的路径分隔符)
     */
    String PATH_SEPARATOR = ":";

    /**
     * The default build directory name.(每个project的输出文件夹,所以我们每个project中都有一个build文件夹就是这么来的)
     */
    String DEFAULT_BUILD_DIR_NAME = "build";

    String GRADLE_PROPERTIES = "gradle.properties";

    String SYSTEM_PROP_PREFIX = "systemProp";

    String DEFAULT_VERSION = "unspecified";

    String DEFAULT_STATUS = "release";

通过上面我们看到Project的默认属性是很少的,所以Google开发者给我们提供了扩展属性来使用,满足我们的需求。

 

图1:当前是在RootProject中定义的Project的两个扩展属性

//图1
//1.通过def定义变量
def mCompileSdkVersionABC =25
//2.通过ext加闭包来定义扩展属性
ext{
    vvv='com.facebook.stetho:stetho:1.5.0'
}

《在飞Android Gradle实战》之核心模块Project2_第4张图片

图2:使用图一种RootProject中定义的vvv扩展属性

《在飞Android Gradle实战》之核心模块Project2_第5张图片

经验:

    如果是多个project相互交互,使用ext{}闭包形式可以两个gradle脚本交互,但是def定义变量的形式只能当前project使用,所以建议使用ext{}闭包形式。

4.Project文件属性API

 4.1获取位置相关api

//文件相关api
println "rootDir:" + getRootDir().absolutePath //获取root dir
println "buildDir:" + getBuildDir().absolutePath  //获取build dir
println "projectDir:" + getProjectDir().absolutePath //获取当前Project dir

 4.2:file操作api


println "file内容{:${getContent('settings.gradle')}}" //输出settings.gralde中的内容
def getContent(String filePath){
    try {
        def file=file(filePath)//file api参数是file的路径
        return file.text //获取file中的内容
    } catch (GradleException e) {
        println 'file not found..'
    }
    return null
}

《在飞Android Gradle实战》之核心模块Project2_第6张图片

输出结果《在飞Android Gradle实战》之核心模块Project2_第7张图片

经验:

     file()中的参数无需传绝对路径,而是相对于当前project的相对路径

     file.text返回的结果就是文件的中内容,无需像java那样来解析文件中的内容,groovy中api帮我们做了处理。

4.3:文件拷贝Api 

//file copy
copy{
    from 'settings.gradle'   //from文件来源
    into 'settings2.gradle'  //into文件目的地
//    into getRootProject().getBuildDir().path+'/setting2.gradle'   //也可以路径
    exclude{} //排除
    rename{}  //重命名
}

4.4:文件树遍历Api

//file文件树遍历,遍历build/outputs文件夹下面内容,将里面的file拷贝到test目录中
fileTree('build/outputs/'){FileTree fileTree ->  //参数fileTree
    fileTree.visit{FileTreeElement element ->//visit遍历文件数,element是每个文件
        copy{
            from element.file
            into getRootProject().path+'/test/'
        }
    }
}

5:依赖相关API

  5.1buildScript   转载请注明出处:

buildscript { ScriptHandler scriptHandler ->
    //配置工程的仓库地址
    scriptHandler.repositories { RepositoryHandler repositories ->
        repositories.jcenter()
        repositories.mavenCentral()
        repositories.maven {
            name 'inmoc'  //一般公司名字
            url 'http://'
            credentials {// 设置用户名密码
                username = ''
                password = ''
            }
        }
    }
    //配置工程的"插件"依赖地址,gradle使用的插件,外面的dependencies{compile}这些是针对应用程序的插件配置
    scriptHandler.dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'
    }
}
//去掉参数后
buildscript {
    //配置工程的仓库地址
    repositories {
        rjcenter()
        mavenCentral()
        maven {
            name 'inmoc'  //一般公司名字
            url 'http://'
            credentials {// 设置用户名密码
                username = ''
                password = ''
            }
        }
    }
    //配置工程的"插件"依赖地址,gradle使用的插件,外面的dependencies{compile}这些是针对应用程序的插件配置
   dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'
    }
}

经验:

     看上面内容是不是很眼熟。之前你是否也纳闷为什么我们的项目中会有两个地方都配置了dependencies呢?那是因为gradle构建的不同需求。这两个dependencies是对两部分的依赖,一个是gradle本身需要的对第三方库的依赖,另一个是应用程序(app)中真正对第三方库的依赖。上面看到的就是针对gradle的配置依赖,android的是在app下的build.gradle中的dependencies{}闭包中,请自行查看自己的项目内容。

5.2外部命令执行

//用外部命令copy
task('apkcopy') {//task内容下章介绍
    doLast { //doLast{}中的内容都是在gradle的执行阶段去执行。将outputs文件夹下的内容copy到test2中
        def sourcePath = this.buildDir.path + '/outputs/'
        def destaPath = this.buildDir.path + '/test2/'
        def command = "mv -f ${sourcePath} ${destaPath}"
        exec {//exec执行外部命令
            try {
                executable 'bash'  //固定写法
                args '-c', command 
                println 'command is success..'
            } catch (GradleException e) {
                println 'command is exception ...'
            }
        }
    }
}

Terminal执行 ./gradlew apkcopy

《在飞Android Gradle实战》之核心模块Project2_第8张图片

 

经验:

    这章主要说了什么是project,所有project的组织结构是一个树的形式来组织的,所以就可以用subproject在父节点中找到子节点,当然也可以找到root节点,所以构建project就是跟我们每个程序员交互的核心。project的初始化是通过我们的build.gradle,所以我们编写的脚本核心就在build.gradle中。

 

Ps:我是在飞~~,只有空闲时间更新博客,所以本系列偏快速入门和个人经验分享。主要讲实战中经常用到和我认为重要的内容。所以文章尽量简短,敬请谅解,希望我的博客对你有帮助!本系列暂定阅读者已经有groovy基本知识,如果需要我来说下groovy内容也可以评论中提出,后续单开一章带领大家简单入门下Groovy。

祝各位工作顺利!
有问题可联系q:1660380990邮箱[email protected]

你可能感兴趣的:(android,Gradle)