美文网首页
Gradle必备知识点

Gradle必备知识点

作者: DustMoon | 来源:发表于2018-12-20 15:55 被阅读0次

    之前对于Gradle的理解就是内嵌在AS里帮项目编译编译,打打包,仅次而已。。。不得其精髓,就无法享受Gradle带给开发的快感。

    什么是Gradle?
    是一款很优秀的构建工具。
    gradle官方文档
    gradle中文文档

    配置Gradle环境
    不要以为它只是AS的附属品,只要配置了Gradle的环境,哪里又可以用,当然也包括服务端,干的事就很多了。

    首先需要Java环境,JDK1.6以上,略。。。java -version
    下载Gradle 官网下载https://gradle.org/,直接下载地址

    distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip
    
    

    这里其实我拷贝的Gradle wrapper下gradle-wrapper.properties中的(等会会细说),下载all的是因为包含源代码,文档,实例等。
    配置环境变量vim ~/.bash_profile 配置完成source ~/.bash_profile

    GRADLE_HOME=/**/**/gradle
    PATH=${PATH}:${GRADLE_HOME}/bin
    export GRADLE_HOME PATH
    gradle -v
    //显示版本号即为成功
    

    当然,可以try了
    直接新建一个build.gradle文件,写入

    task helloWorld<<{
      println "hello wa wa !"
    }
    

    cd到同级目录下

    //hw是驼峰简写,  q  是日志级别quit ,println是quit级别
    gradle -q hw/helloWorld
    

    此处,应该可以简单想到AS gradle的工作原理了,实际里面是好多Gradle的任务。

    其实我们在AS送使用的是Gradle Wrapper,wrapper 顾名思义就是在gradle上包括了一层,便于团队开发,比如我用的mac,你用的windows 他用的linux,wrapper可以帮我处理这些,我们可以使用相同的指令就可以了。gradle内置的gradle wrapper可以帮我们生成gradle wrapper

    $ gradle wrapper
    

    可以发现生成如下目录

    gradle 
      --wrapper
        --gradle-wrapper.jar
        --gradle-wrapper.properties
    gradlew
    gradlew.bat
    

    gradlew 和gradlew.bat就是linux和windows下的执行脚本
    这个层级结构在我们的AS安卓项目里我们也可以看到,豁然开朗
    gradle-wrapper.properties就是gradle的配置文件了,我们可以做一些设置,可以对比项目里

    android.useDeprecatedNdk=true
    org.gradle.daemon=true
    zipStorePath=wrapper/dists
    org.gradle.parallel=true
    zipStoreBase=GRADLE_USER_HOME
    org.gradle.caching=true
    org.gradle.jvmargs=-Xmx5120M -XX\:MaxPermSize\=512m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
    //下载gradle的路径
    distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip
    org.gradle.configureondemand=true
    distributionPath=wrapper/dists
    //下载gradle解压后的主存储目录
    distributionBase=GRADLE_USER_HOME
    android.enableAapt2=false
    android.useAndroidX=false
    android.enableJetifier=false
    

    看名字含义就差不多了;
    当然我们也可以通过任务的形式配置wrapper

    task wrapper(type:Wrapper){
      gradleVersion = '4.8'
    distributionUrl='https\://services.gradle.org/distributions/gradle-4.8-all.zip'
    }
    

    日志类似于项目中 e ERROR q QUIT w WARNING i INFO d DEBUG

    logger.quit('这是一条重要的日志信息')
    

    查看所有可执行的tasks

    ./gradlew tasks
    ./gradlew -help
    ./gradlew --refresh-dependencies assemble //强制刷新依赖库,防止缓存很有用我们项目中就发生过小伙伴电脑编译没问题,其他人从GitHub拉下来的就编译不通过
    

    首先大家应该明白Project和Task的区别,Gradle可以包含多个Project,多模块项目,每个project包含多task,最后构成了整个gradle的构建,详情参照groovy官网groovy教程

    结合项目看看gradle的生命周期,根project下都有一个setting.gradle,build.gradle:

    include ':application', ':modules:xcf_annotation_processor', ':modules:xcf_annotation', ':modules:xcf_annotation_complier', ':modules:xcf_annotation_api'
    

    ·

    • 初始化创建Settings实例
    • 解析settings.gradle 构造各个Project实例
    • 解析每个Project对应的build.gradle,配置相应Project

    差不多了,先来看几种任务的写法

    //方式1
    task name<<{//<<其实是doLast的意思,最后执行,{}闭包
      description '添加描述'
    }
    //方式2
    tasks.create(name){
     description '添加描述'
      doLast{
      }  
    }
    //也可以
    name.doFrist{//开始执行
    }
    
    //自定义任务
    class CustomTask extends DefaultTask{
      @TaskAction
      def doSelf(){
        pritln 'do self'
      }
    }
    def Task mTask =task execTask(type:CustomTask){
      doFrist{ pritln 'doFrist' }
    }
    mTask.doLast{
    pritln 'doLast' 
    }
    
    ./gradlew -q execTask
    execTask.enable=false//可以禁用这个task
    
    execTask.onlyIf{//满足某些条件才能执行
      boolean
    }
    
    //多个任务排序
    ./gradlew task1 task2
    指定顺序可以使用 task2.mustRunAfter(task1)
    
    //任务依赖
    task mTask1<<{
        println 'hello'
    }
    task mTask2(dependsOn:mTask1){
        doLast{
          println 'world'
        }
    }
    ./gradlew -q mTask2
    hello world
    //还有另外一种写法,依赖多个task
    task mTask3<<{
    dependsOn:mTask1,mTask2
        println 'end'
    }
    //每个task其实也是project的一个属性
    project.hasdProperty('mTask3')
    
    

    gradle是基于groovy的,groovy也是基于jvm虚拟机的一种动态语言,语法跟Java相似,懂Java,学习groovy没有任何障碍,完全兼容Java,可以直接写Java代码。接下来是一些基本用法

    def str1='hello'
    def str2="hello"
    //行尾不必写分号
    //方法
    def method1(int a,int b){
      a+b//此处注意可以省略return 默认最后一行就是返回
    }
    //两种调用方式
    task mTask(){
      method1(2,3)
      method 1,2
    }
    
    //集合
    task listTask{
      def numList=[1,2,3]
       numList[1]
       numList[-1]
      //it类似Java集合的迭代器
      numList.each{ println it }
    }
    //map
    task mapTask{
      def map=['key':'value']
      map.each{
        println map['key']/map[key]
        println 'key'${it.key}
      }
    }
    //javabean
    class Person {
      private String name;
    }
    
    task beanTask{
      Person p=new Person
      p.name="hello"
    println "name:${p.name}"
    }
    
    //自定义属性,可以是project可以是task
    
    ext.age=18
    ext{
        sex='famle'
        phone='1234445'
    }
    
    task task1<<{
        println("phone:${phone}")
    }
    
    

    Gradle插件

    为什么我们几乎什么也不用关心就能在Android studio中构建我们安卓项目,这是因为Gradle默认实现了很多有用的插件;这些是我们常见的插件,他们帮我们做了哪些平常我们不需要深入关心的工作,比如编译,测试,打包,资源文件目录等等。
    buildscript{}块是在有个项目构建前,为项目准备初始化相关配置的地方,配置好依赖我们就可以使用插件了

    apply plugin: 'com.android.application'
    apply plugin: 'io.fabric'
    apply plugin: 'com.growingio.android'
    

    比如:com.android.application就是一个Android相关的插件,引入这个我们就可以使用Android{}代码块的先关配置,来帮助我们生成编译打包我们的Android工程;

    简单自定义插件,通过下面简单的自定义插件,可以帮助大家了解Android插件的工作方式,内部帮助我们实现了很多的task。

    在build文件中

    class CustomPlugin extends Plugin<Project>{
        void app(){
            project.task("task1")<<{
              println("hello task1")
            }
        }
    }
    apply plugin :CustomPlugin
    

    接下来可以分别简单介绍一下Java和Android插件:

    Java插件

    apply plugin : 'java'
    

    上述眼熟的代码起始就是大家新建Java模块时候依赖的Java插件,他来帮助我们自动构建我们的Java项目

    //添加依赖的时候告诉gradle去哪里找到这些依赖,设置依赖仓库
    repositories{
        repositories {
            mavenCentral()
            maven { url "https://jitpack.io" }
            maven { url "https://dl.bintray.com/thelasterstar/maven/" }
            jcenter()
        }
    }
    //告诉gradle我们依赖什么,group,name,version以冒号隔开
    dependencies {
        implementation 'com.alibaba:fastjson:1.1.46'
    }
    

    注:
    api 跟2.x的compile类似
    implementation 这个最常用,在当前模块内起作用,比如B模块依赖了Gson,A模块依赖B模

    有了上述构建的基本的以来就有了,对于项目本身的文件资源默认是在sourceSet中配置

    //这个就是Java工程的默认目录了,当然如果是需要自定义目录结构,就可以更高这里
    sourceSets{
        main{
            java{
                  srcDir 'src/java'
            }
            resources{
                  srcDir 'src/resources'
            }
        }
    }
    //大家可以打印一下,都有哪些属性
    task printSourceSet{
        sourceSets.all{
            println name
        }
    }
    
    

    当然这些都是常用的,要想编译运行我们的Java项目,还依赖于我们的tasks,默认的Java插件都帮我们实现完了,如果大家想看有哪些任务:./gradlew tasks查看所有的任务;
    还有几个常见属性和常用的任务:

    //编译Java源文件使用的Java版本
    sourceCompatibility Javaversion
    //编译生成类的Java版本
    targetCompatibility Javaversion
    //生成类库的目录
    libsDir File
    
    //打jar包
    task publishJar(type:Jar)
    
    artifacts{
        archives publishJar
    }
    
    //最有用的是上传任务,可以打完包配置直接上传maven,jcenter,详情可自行百度
    uploadArchIves{
    
    }
    

    Android插件

    这应该是我们平时使用和见的最多的

    apply plugin: "com.android.application"
    

    里面android{}就是我们配置Android gradle的总入口

    android {
        compileSdkVersion xx
        buildToolsVersion  'xxx'
    
        defaultConfig{
              applicationId 'xxx'
              xxxx
              xxxx
              //defaultConfig中可以显示的配置singningConfigs,否则会根据buildTypes自动release或者debug
              signingConfig singningConfigs.debug
         }
         //签名配置信息
         singningConfigs{
            release{
              storeFile file('xxxxxx.keystore')
              storePassword 'xxx'
              keyAlias 'xxx'
              keyPassword  'xxx'
            }
            debug{
              storeFile file('xxxxxx.keystore')
              storePassword 'xxx'
              keyAlias 'xxx'
              keyPassword  'xxx'
            }
        }
        
        buildTypes{
          release{
              // 此处可以配置签名配置
              signingConfig singningConfigs.debug
             // 是否需要混淆
              minifyEnable   boolean
              //设置为.debug那么打出的包名就是applicationId.debug
              applicationIdSuffix  'xxx'
              
              mutiDexEnable  boolean
    
              proguardFiles file
              //清除未使用的资源
              shrinkResources boolean
              //Android为我们提供的整理apk的工具,更快的读写apk中的资源,降低内训的使用,建议开启
              zipaligin boolean
          }    
          debug{}
        }
      //配置渠道包,常用
      productFlavors{
          google{}
          huawei{}
       }
    
    }
    
    

    Android项目gradle的加载流程setting.gradle--->root.gradle--->setting中配置的project
    所以我们在root.gradle做一些通用的配置

    buildscript {//gradle脚本执行的依赖,root中添加作用其他subject/moudles
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:1.2.3'
        }
    }
    
    allprojects {//项目本身需要的依赖,对所有projects都起作用
        repositories {
            mavenCentral()
        }
    }
    

    设置一个gradle基类,这个在多module中非常实用,创建common.gradle在根目录下:

    android {
        compileSdkVersion rootProject.ext.compileSdk
        buildToolsVersion rootProject.ext.buildTools
    
        defaultConfig {
            minSdkVersion rootProject.ext.minSdk
            targetSdkVersion rootProject.ext.targetSdk
        }
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
        dexOptions {
            javaMaxHeapSize "4g"
        }
        packagingOptions {
            exclude '.readme'
            exclude 'LICENSE.txt'
            exclude 'META-INF/dependencies.txt'
        }
    }
    
    //在其他模块中直接apply from 就可以继承上面所有的属性,不需要重复写
    apply from: rootProject.file('common.gradle')//其他目录就可以xxxx/xxx/common.gradle
    
    android {
        defaultConfig {
            applicationId rootProject.ext.packageName
            versionCode 1
            versionName "1.0"
        }
    }
    
    //还有一种写在公共模块的方式在root.gradle
    
    configure(project(':app').subprojects) {//相当于放在app下的build.gradle
      apply plugin :'xxx'
      android {
          defaultConfig{}
      }
      dependencies{}
    }
    
    

    抽取公共常量constant.gradle

    ext {
        android_const = [
                compileSdk : 28,
                minSdk     : 16,
                targetSdk  : 26,
                support    : "27.1.1",
                buildTools : "28.0.3",
                packageName: "com.xiachufang"
        ]
    
        dep_const = [
                glide      : "3.6.0",
                okio       : "1.4.0",
                okhttp     : "2.4.0",
                fabric     : "2.4.0",
                logansquare: "1.1.0",
                dagger     : "2.0.1",
                butterknife: "7.0.1",
                retrofit   : "2.0.0-beta2",
                greendao   : "2.0.0"
        ]
    
        app_dep = [
                "appcompat-v7"      : 'com.android.support:appcompat-v7:' + android_const.support,
                "design"            : 'com.android.support:design:' + android_const.support,
                "okio"              : 'com.squareup.okio:okio:' + dep_const.okio,
                "okhttp"            : 'com.squareup.okhttp:okhttp:' + dep_const.okhttp,
                "glide"             : 'com.github.bumptech.glide:glide:' + dep_const.glide,
                "butterknife"       : 'com.jakewharton:butterknife:' + dep_const.butterknife,
                "rxjava"            : 'io.reactivex:rxjava:1.0.10',
                "rxandroid"         : 'io.reactivex:rxandroid:0.24.0',
                "retrofit"          : 'com.squareup.retrofit:retrofit:' + dep_const.retrofit,
                "converter-gson"    : 'com.squareup.retrofit:converter-gson:' + dep_const.retrofit,
                "adapter-rxjava"    : 'com.squareup.retrofit:adapter-rxjava:' + dep_const.retrofit
        ]
    }
    
    //可以在每个模块中apply from:
    //也可以在root.gradle中apply,然后在其他模块中
    
    apply plugin: 'java'
    
    dependencies {
        compile rootProject.ext.app_dep.rxjava
    }
    
    

    说一个常用的属性BuildConfig,大家可能都使用过,来判断是都是Debug
    ,这个文件是不能更改的,是gradle帮我们生成的,那么我们想扩展先关字段怎么办?如果能扩展还是很方便的

    //我们使用这个扩展过线上和debug的地址
    productFlavors{
          google{
              buildConfigField 'String' 'WebUrl' 'www.google.com'
              //添加自定义资源
              resValue   'String' 'chanel_tips' 'google 欢迎你'
           }
          huawei{
               buildConfigField 'String' 'WebUrl' 'www.huawei.com'
           }
       }
    
    

    其他扩展

     //Java编译版本编码格式等等
    compileOptions{}
    adbOptions{}
    testOptions {}
    dexOptions{
        //配置dex命令时分配最大堆内存
        javaMaxHeapSize '4g'
        // Sets the maximum number of DEX processes
        maxProcessCount 8
      }
    packagingOptions {
            exclude '.readme'
            exclude 'LICENSE.txt
        }
    
    defaultConfig{
        //国际化只打中文资源
        resConfigs 'zh'
    }
    

    多渠道构建

    在gradle Android plugin中定义了一个Build variant的感念,翻译为构建变体。实际就是构建apk,实际也就是Build type+Product flavor=Build variant,Build type是构建类型,Product flavor就是多渠道配置,Build type也就是release,debug,自定义类型等,之前说过

    productFlavors{
        google{
            applicationId ''//指定渠道包名
            manifestPlaceholders.put("UMENG_CHANNEL","google")//修改
    AndroidManifest的值
            // app名称替换
            manifestPlaceholders = [app_name:"@string/app_name"]
            multiDexEnable//设置是否支持多dex
            proguardFiles//单独混淆
            signingConfig//单独的签名配置
            versionCode
            verisonName
        }
        huawei{}
    }
    
    //设置维度
    flavorDimensions 'abi' ,'version'
    productFlavors{
        free{
            dimensions 'version'
        }
        pay{
            dimensions 'version'
        }
        x86{
            dimensions 'abi'
        }
        arm{
            dimensions 'abi'
        }
    }
    
    //将会构建出x86free x86pay armfree armpay的包
    

    常用的结合的例子
    获取keystorePropertiesFile

    // Creates a variable called keystorePropertiesFile, and initializes it to the
    // keystore.properties file.
    def keystorePropertiesFile = rootProject.file("keystore.properties")
    
    // Initializes a new Properties() object called keystoreProperties.
    def keystoreProperties = new Properties()
    
    // Loads the keystore.properties file into the keystoreProperties object.
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    
    android {
      signingConfigs {
        config {
          keyAlias keystoreProperties['keyAlias']
          keyPassword keystoreProperties['keyPassword']
          storeFile file(keystoreProperties['storeFile'])
          storePassword keystoreProperties['storePassword']
        }
      }
      ...
    }
    ...
    

    FileProvider骚操作

    android {
      defaultConfig {
        def filesAuthorityValue = applicationId + ".files"
        manifestPlaceholders = [filesAuthority: filesAuthorityValue]
          buildConfigField("String",
                           "FILES_AUTHORITY",
                           "\"${filesAuthorityValue}\"")
      }
      }
    }
    
    //在AndroidManifest中使用
    <manifest>
      ...
      <application>
        ...
        <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="${filesAuthority}"
          android:exported="false"
          android:grantUriPermissions="true">
          ...
        </provider>
      </application>
    </manifest>
    //在Java代码中
    Uri contentUri = FileProvider.getUriForFile(getContext(),
      BuildConfig.FILES_AUTHORITY,
      myFile);
    

    根据git tag来生成版本号

    def getVersionCode = { ->
        try {
            def code = new ByteArrayOutputStream()
            exec {
                commandLine 'git', 'tag', '--list'
                standardOutput = code
            }
            return code.toString().split("\n").size()
        }
        catch (ignored) {
            return -1;
        }
    }
    
    def getVersionName = { ->
        try {
            def stdout = new ByteArrayOutputStream()
            exec {
                commandLine 'git', 'describe', '--tags', '--dirty'
                standardOutput = stdout
            }
            return stdout.toString().trim()
        }
        catch (ignored) {
            return null;
        }
    }
    android {
        defaultConfig {
            versionCode getVersionCode()
            versionName getVersionName()
        }
    }
    

    通过uploadArchives上传maven

    apply plugin: 'maven'
    apply plugin: 'signing' //使用signing plugin做数字签名
    
    //定义GroupID和Version,
    //ArtefactID会自动使用Project名
    group = 'com.github.xxx'
    version = '1.0.0'
    
    repositories {
        mavenCentral();
    }
    
    artifacts {
        archives file('xxx.aar')
    }
    signing {
        sign configurations.archives
    }
    
    uploadArchives {
        repositories {
            mavenDeployer {
                //为Pom文件做数字签名
                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
    
                //指定项目部署到的中央库地址,UserName和Password就是Part 1中注册的账号。
                repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                    authentication(userName: Username, password: Password)
                }
                snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
                    authentication(userName: ossrhUsername, password: ossrhPassword)
                }
    
                //构造项目的Pom文件,不要遗漏必填项
                pom.project {
                    name project.name
                    packaging 'aar'
                    description 'xxxxxx'
                    url 'https://github.com/xxx'
    
                    scm {
                        url 'scm:git@github.com:xxx.git'
                        connection 'scm:git@github.com:xxx.git'
                        developerConnection 'git@github.com:xxx.git'
                    }
    
                    licenses {
                        license {
                            name 'The Apache Software License, Version 2.0'
                            url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                            distribution 'xxxx'
                        }
                    }
    
                    developers {
                        developer {
                            id 'xxx'
                            name 'xxx'
                            email 'xxx@gmail.com'
                        }
                    }
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Gradle必备知识点

          本文链接:https://www.haomeiwen.com/subject/pqaexqtx.html