原创

Android项目管理搭档之Gradle全方位解读

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://gaolei.blog.csdn.net/article/details/80032335

转载请标明地址:https://blog.csdn.net/gaolei1201/article/details/80032335

Gradle简介

1、Gradle 设计的方式使得它可以很容易地扩展构建和插入到现有的构建过程中,Google 推广 Gradle 和 Android Studio 时,目标是让代码复用、构建 variant、配置和定制构建过程变得更加简单。

2、Gradle 面向Java应用为主。当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。

3、AS 3 的开发者,那么 AS 中的默认仓库为 mavenCenter 、JCenter 和 google。Gradle内建支持jcenter()仓库,项目库打包成aar文件类似jar,只是多了res,lib文件的包,上传到jcenter后,可以很方面的在本地调用库文件

Gradle用途之Android

1、大家有没想过Android Studio是如何把我们编写的代码怎么编译打包成APK的?其实就是用Gradle利用sdk>build-toolsGradle自动化编译打包的。我们可以为Gradle指定构建规则,然后它就会根据我们的“命令”自动为我们构建app。Android Studio中默认就使用Gradle来完成应用的构建。有些同学可能会有疑问:”我用AS不记得给Gradle指定过什么构建规则呀,最后不还是能搞出来个apk。“ 实际上,app的构建过程是大同小异的,有一些过程是”通用“的,也就是每个app的构建都要经历一些公共步骤。因此,在我们在创建工程时,Android Studio自动帮我们生成了一些通用构建规则,很多时候我们甚至完全不用修改这些规则就能完成我们app的构建。

2、有些时候,我们会有一些个性化的构建需求,比如我们引入了第三方库,或者我们想要在通用构建过程中做一些其他的事情,这时我们就要自己在系统默认构建规则上做一些修改。这时候我们就要自己向Gradle”下命令“了,这时候我们就需要用Gradle能听懂的话了,也就是Groovy。Groovy是一种基于JVM的动态语言

android编译打包的过程

Gradle文件和执行阶段

1、当使用studio创建一个新项目时,会默认生成三个gradle文件。其中的两个文件--setting.gradle和build.gradle文件位于项目的根目录,另外一个build.gradle文件则在android app模块内。其执行顺序是setting.gradle->根目录build.gradle- >项目中build.gradle

2、一个gradle的构建通常有如下三个阶段a. 初始化-项目实例会在该阶段被创建。

如果一个项目有多个模块,并且每一个模块都有其对应得build.gradle文件,那么就会创建多个项目实例;

b. 配置-在该阶段,构建脚本会被执行,并为每个项目实例创建和配置任务;

c. 执行-在该阶段,gradle将决定哪个任务会被执行,哪些任务会被执行取决于开始该次构建的参数配置和该gradle文件的当前目

录;

Gradle的两个重要概念

1、Task

在Gradle中,每一个待构建的工程是一个Project,构建一个Project需要执行一系列Task,比如编译、打包这些构建过程的子过程都对应着一个Task。具体来说,一个apk文件的构建包含以下Task:Java源码编译、资源文件编译、Lint检查、打包以生成最终的apk文件等等。

2、 Plugin

插件的核心工作有两个:一是定义Task;二是执行Task。也就是说,我们想让Gradle能正常工作,完成整个构建流程中的一系列Task的执行,必须导入合适的插件,这些插件中定义了构建Project中的一系列Task,并且负责执行相应的Task。

Gradle 之Task

1、常用命令,是plugin: 'com.android.application'包含的gradle clean,清除编译时生成的临时文件。
gradle assemble,功能同build,但没有Lint和UnitTest。gradle assembleDebug,只编译打包Debug版本。

gradle assembleRelease,只编译打包Release版本。

我们可以看一下assembleDebug的依赖关系:https://blog.csdn.net/codetend/article/details/51909267?utm_source=itdadao&utm_medium=referral

2、 Gradle 自定义Task ,class MyTask extends DefaultTask {}
task hello3 (type: MyTask){

doLast{
println "action2+++++"

}}

 

获取每个Task执行时间

class TaskTimeMonitor implements TaskExecutionListener, BuildListener {

    private Clock clock
    private times = []

    @Override
    void beforeExecute(Task task) {
        clock = new org.gradle.util.Clock()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = clock.timeInMs
        times.add([ms, task.path])
        task.project.logger.warn "${task.path} spend ${ms}ms"
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task spend time:"
        for (time in times) {
            if (time[0] >= 50) {
                printf "%7sms  %s\n", time
            }
        }
    }

    @Override
    void buildStarted(Gradle gradle) {}

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}


• gradle.addListener new TaskTimeMonitor() 通过这个监听器我们可

以获取编译过程中执行了哪些Task及每个Task执行的时间 

我们可以通过执行 gradlew assembleDebug  来看效果

根据gradle的回调Task自动化执行

1、//当任务图创建的时候这个回调会自动执行,你知道这个逻辑会在任何任务之前执行,所以你可以自定义做一些操作

gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
//    使用Groovy语法调用getAllTasks方法获取所有的task,然后做相应的操作
    taskGraph.allTasks.findAll { it.name ==~ /lint.*/ }*.enabled = false
//    taskGraph中没有release的task,做相应的操作
    if (taskGraph.hasTask(release)) {        version = '1.0'
    } else {version = '1.0-SNAPSHOT'
    }
    tasks.updateAAR.execute()
    println "updateAAR.execute()--------------------------"
}
也可以自定义TaskExecutionGraphListener  ,可参考:http://wiki.jikexueyuan.com/project/gradleIn-action/build-lifetime.html
2、每个模块,配置的时候并不会执行task,
 配置完了以后,有一个重要的回调project.afterEvaluate,它表示所有的模块都已经配置完了,可以准备执行task了; 
project.afterEvaluate {
    println "app evaluate start"
    println "app evaluate end"
}

  •  

Gradle 之Plugin

1、Android Gradle Plugin其实包含多个Gradle Plugin,不过通常开发过程中,我们只会用到其中的两个——com.android.application、com.android.library,对应于Android工程的Application与Library模块;当然,除了这两个插件,AGP还包含:com.android.test、com.android.atom、com.android.instantapp等插件。这些类似于域名的东西被称为Gradle Plugin Id,用于唯一标示一个插件。上面提到的插件及其扩展,在源码中都有与之对应的类来实现,比如:com.android.application插件对应于类AppPlugin.java与AppExtension.java;com.android.library插件对应于类LibraryPlugin.java与LibraryExtension.java。其实你完全可以把Gradle插件理解为类似ButterKnife一样的一个第三方库(工具),其不同版本所具有的功能是不同的

2、apply plugin: 'com.android.application'

• 这句话的意思就是应用“com.android.application“这个插件来构建app模块,app模块就是Gradle中的一个Project。也就是说,这个插件负责定义并执行Java源码编译、资源文件编译、打包等一系列Task。实际上"com.android.application"整个插件中定义了如下4个顶级任务:

• assemble:构建项目的输出(apk)
• check:进行校验工作
• build:执行assemble任务与check任务• clean:清除项目的输出

• 当我们执行一个任务时,会自动执行它所依赖的任务。比如,执行assemble任务会执行assembleDebug任务和assembleRelease任务,这是因为一个Android项目至少要有debug和release这两个版本的输出。

android{}配置块

• aaptOptions { }

• adbOptions { }

• buildTypes { }

配置aapt选项配置adb选项

配置build类型

• compileOptions { } 配置编译选项

• dataBinding { } 配置数据绑定选项

• defaultConfig { } 默认的配置,如果有定义的话,所有的product

flavors会继承这些配置

• dexOptions { } 配置dex 选项

• externalNativeBuild { } 配置外部本地生成选项(例如:ndk开发时使用)

• jacoco { } 配置jacoco选项

Gradle之添加依赖

  • compile 'com.android.support:support-v4:23.3.0'

  • compile(name: 'aar_file_name', ext: 'aar')

  • compile project(':xxxsdk')

  • compile files('libs/fastjson-1.1.53.android.jar')

  • provided files('libs/glide-3.7.0.jar')

  • compile('org.eclipse.paho:org.eclipse.paho.android.service:1.0.2'){

  • Compile

  • compile是对所有的build type以及favlors都会参与编译

    并且打包到最终的apk文件中。

  • Provided

  • Provided是对所有的build type以及favlors只在编译时使用,类似eclipse中的external-libs,只参与编译,不打包到最终apk。

  • APK

exclude(group: 'com.google.android', module: 'support-v4') •

只会打包到apk文件中,而不参与编译,所以不能再代码中直接调用jar中的类或方法,否则在编译时会报错

}

  • Test compile

  • Test compile 仅仅是针对单元测试代码的编译编译以及

    最终打包测试apk时有效,而对正常的debug或者release apk包不起作用。

  • Debug compile

  • Debug compile 仅仅针对debug模式的编译和最终的

    debug apk打包。

  • Release compile

  • Release compile 仅仅针对Release 模式的编译和最终的

Gradle多渠道打包 ,并且自定义不同渠道包

1、 productFlavors {xiaomi {

applicationId "com.example.xiaomi"minSdkVersion 14
signingConfig signingConfigs.configtargetSdkVersion 26

versionCode 3versionName '3.0.0'dimension "one"

manifestPlaceholders = [app_name: "App1", icon:"@mipmap/icon_app1", welcome_bg:

"@mipmap/bg_app1", tint_color:

进一步自定义不同的打包

上面讲了通过manifestPlaceholders 可以结合AndroidManifest.xml中的<meta-data>可以动态设定不同App名称,应用图标,背景图片,状态栏颜色等。那么有没有别的方式呢,不仅可以自定义图标,文字还可以自定义layout呢?答案是可以的

src文件夹内默认是main,里面包含java文件、res资源等。我们可以自定义src的内容,对应 productFlavors

自定义APK名称,多渠道打包android.applicationVariants.all { variant ->

variant.outputs.all { output ->variant.productFlavors.each { flavor ->

def separator = "_"

def buildType = variant.variantData.variantConfiguration.buildType.name

def versionName = variant.versionName

def versionCode = variant.versionCode

def date = new Date()

def formattedDate = date.format('yyyyMMdd')

def apkName =flavor.name + separator +buildType + separator + "v" + versionName + separator + versionCode+".apk"

if (buildType == "release") {

apkName = flavor.name + separator +buildType + separator + "v" + versionName + separator + versionCode +separator + formattedDate + ".apk"

}

output.outputFileName = apkName}

}

加快编译速度,配置gradle

1、/.gradle/gradle.properties中添加如下配置(没有该文件则新建一

个):
org.gradle.daemon=true //独立进程,停止后台进程命令:gradle --

stop
org.gradle.parallel=true //并行构建,需要将项目拆分成多个子项

目,通过aar引用才能起效

2、打开settings->Build,Execution,Deployment->Build Tools->Gradle,

选中Offlie Work //设置离线编译,更新依赖包时要取消它

3、多个module编译时会增加时间,每个module中都有一个build.gradle,编译的时候,每个module的build.gradle中的task都需要执行,所以编译时间会很长。

Task之复制文件

1、上个幻灯片讲的可以把所有module的aar拷贝到文件夹libs中,

//打包命名
def eachModuleAAR(){
    def libPath= getRootProject().projectDir.getAbsolutePath()+"/libs/";
    for (Project project : getRootProject().getAllprojects()) {
        println  "eachModuleAAR-------------"+project.name.toString()
        def projectModuleAARPath=project.buildDir.absolutePath+"/outputs/aar/";
        def dir = new File(projectModuleAARPath)
        if (!dir.exists()) continue
        dir.eachFile { File file ->
            copy{
                from file.absolutePath
                into libPath
            }
            println  project.name + ' Update SUCCESS!'
        }
    }
}


2、Eclipse把class打jar包容易,那么AndroidStudio如何打jar包呢?
需要打jar包的module的gradle写入如下task,然后执行命令 gradlew makeJar你就可以在此module的libs文件夹下看到
task makeJar(type: Copy) {
    from('build/intermediates/bundles/release/classes.jar')
    into('/libs/')
    rename('classes.jar', 'httputils.jar')
}

Gradle模块化

• 咱们编程时提倡模块化,因为遵循功能单一原则,够低耦合高聚合原则。把功能封装起来如果多个地方调用的话会很方便。同样道理,我们也可以将gradle模块化,不同功能单独建立一个gradle文件,他们之间又是可以相互依赖

• 通过apply from: 'config.gradle'。就可以和其它gradle建立联系

 

编写自己的library和plugin,可参考

• Android 快速发布开源项目到jcenter:https://blog.csdn.net/lmj623565791/article/details/51148825

• Gradle之使用Android Studio 编写Gradle插件并上传Library到JCenter:https://blog.csdn.net/lisdye2/article/details/52292896

 

有关gradle的开源框架,大家可以研究下,加深理解

大家可以研究下面gradle的开源框架,来看在实际应用

1、腾讯开源的AndResGuard:
AndResGuard是一个帮助你缩小APK大小的工具,他的原理类似AndroidProguard,但是只针对资源。他会将原本冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。
通过修改resources.arsc文件,从而可以混淆安卓的资源文件路径,达到减少apk包的体积的目的。在原生的buildApk步骤之后,使用产生的apk作为输入文件,对其进行混淆压缩,产出一个新的apk。
2、腾讯开源的多渠道快速打包技术VasDolly:http://mp.weixin.qq.com/s/709mXKfEzSuLrd0WCqrmbg

 

 

Thank you!希望今天分享的知识对你们有帮助

 

文章中的有关代码可以下载,地址:https://github.com/gaoleiandroid1201/androidgradle

 

 

文章最后发布于: 2018-04-24 20:49:28
展开阅读全文
0 个人打赏
私信求帮助

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览