1、Gradle是什么,有什么作用

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。

它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。面向Java应用为主。

当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。基于 groovy 脚本构建,其 build 脚本使用 groovy 语言编写。

android studio 中 Gradle 可以帮我们编译 构建 打包项目 可以配置自己的task任务,可以很方便的去引用第三方的类库

2、Gradle在Android studio的具体用法

太杂了,我直接贴代码吧,加有注释 build.gradle

/**
 * Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具。
 * 它使用一种基于 Groovy 的特定领域语言(DSL)来声明项目设置,抛弃了基于 XML 的各种繁琐配置。
 *
 * 简单来说,Gradle 是一种项目构建工具, 它可以帮你管理项目中的
 * 差异、依赖、编译、打包、部署 ......,你可以定义满足自己需要的构建逻辑,
 * 写入到 build.gradle 中供日后复用。
 *
 * Gradle 是一个构建工具,但它需要特定的插件来工作。Android Plugin for Gradle 即是 Gradle 的 Android 插件。
 * Android Studio 构建系统基于 Gradle,Gradle 的 Android 插件 添加了特定于构建 Android 应用程序的几项功能。
 * 虽然 Android 插件通常以 Android Studio 的锁定步骤更新,
 * 但插件(以及其余的 Gradle 系统)可以独立于 Android Studio 运行,并单独更新。
 *
 * Gradle是一个独立运行的程序,不但可以与AndroidStudio协同工作还可以和Eclipse等IDE配合使用。
 * 但由于Gradle发展速度比较快,导致Gradle版本不一,
 * 故每个 Android 插件版本(Android Plugin for Gradle)需要与特定的 Gradle 版本相匹配才能编译成功。
 * 为了获得最佳性能,应该使用最新版本的 Gradle 和 Android 插件。
 */
plugins {
    id 'com.android.application'//应用com.android.application 插件构建此模块
}
//开始配置安卓特定的编译选项
android {
    namespace 'com.example.gradledemo'
    compileSdk 33   //编译的SDK版本,最佳选择为最新的API级别
//    buildToolsVersion //编译的Tools版本,最佳选择为最新的API级别

    //封装默认设置和编译变量,能根据编译系统动态得重写AndroidManifest.xml中的属性
    defaultConfig {
        applicationId "com.example.gradledemo"  //应用程序的包名
        minSdk 24       //支持的最低版本,操作系统会拒绝将应用安装在系统版本低于此标准的设备上
        targetSdk 33    //支持的目标版本,最佳选择为最新的API级别
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //允许自动化测试
        versionCode 1   // 版本号
        versionName "1.0"   // 版本名
        multiDexEnabled true //开启分包
        ndk { // 设置支持的SO库架构 这些叫 ABI,每一种都对应一种 CPU 指令集
            /**
             * Android 平台 CPU 有三大类:ARM、x86、MIPS,其中 x86、MIPS 已经被彻底淘汰了,大家集成 .so 只要考虑 ARM 平台架构就行了
             * ARM 平台架构主要有3种,下面说的代对应的是架构:
             * armeabi: 第5代、第6代 ARM 处理器,早期 android 手机用,A5/7/8/9 核心用的都是这个架构
             * armeabiv-v7a: 第7代、32位 ARM 处理器架构,带浮点数计算能力。A15/17 核心用的都是这个架构,一般现在也少见了,也都淘汰了
             * arm64-v8a: 第8代、64位 ARM 处理器架构,A32/35/53/57/72/73 核心用的都是这个架构,一般现在的 ARM 处理器都在这个范围内
             */
            abiFilters 'armeabi', 'armeabi-v7a', 'arm64- v8a', 'x86', 'x86_64'
        }
        multiDexEnabled true    //是否支持分包
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"//junit单元测试
        resConfigs 'en'//中文资源
        resConfigs "xhdpi" //只使用xhdpi 下的资源文件
        multiDexEnabled true //分包,指定某个类在main dex
        multiDexKeepProguard file('multiDexKeep.pro') // 打包到main dex的这些类的混淆规制,没特殊需求就给个空文件
        multiDexKeepFile file('maindexlist.txt') // 指定哪些类要放到main dex
    }
    //开启databind支持
    dataBinding {
        enabled = true
    }

    //签名信息
    signingConfigs {
        production {
            //签名文件路径
            storeFile rootProject.ext.signing.storeFile
            //密码
            storePassword rootProject.ext.signing.storePassword
            //别名
            keyAlias rootProject.ext.signing.keyAlias
            //别名密码
            keyPassword rootProject.ext.signing.keyPassword
        }
    }

    //构建类型,生成包的配置
    buildTypes {

        // 开发环境
        debug {
            debuggable true // 是否支持断点调试 默认false
            jniDebuggable true // 是否可以调试NDK代码 默认false
            renderscriptDebuggable true // 是否开启渲染脚本RenderScript调试功能,默认为false
            zipAlignEnabled true // 是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率 默认true
            minifyEnabled true // 是否对代码进行混淆,默认false
            shrinkResources true// 移除无用的资源文件 是否自动优化未使用的资源,该配置生效的前提是minifyEnabled必须为true,默认false
            // proguardFiles 指定混淆的规则文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            versionNameSuffix "-debug"//可以版本名称后面追加相关信息
            applicationIdSuffix ".debug"//包名添加后缀 可以控制不同构建类型不同的包名
            //自定义资源信息相当于value 下的String.xml里的内容   debug环境下 定义响应的项目名称
            resValue "string", "app_name", rootProject.ext.android.debugAppName
            //manifest 参数配置项目图标  debug环境下的桌面图标显示 在 manifest 清单文件中引用
            manifestPlaceholders = [app_icon: rootProject.ext.android.debugAppIcon]
            //自定义参数 在 Buildconfig使用   这里不同的环境定义不同的url
            buildConfigField("String", "API_URL", rootProject.ext.apiUrl.debugUrl)
            //配置签名信息
            signingConfig signingConfigs.production
            externalNativeBuild {
                ndkBuild {
                    arguments 'NDK_DEBUG=1'
                }
            }
        }
        //预上线
        preRelease {
            resValue "string", "app_name", rootProject.ext.android.preReleaseAppName
            manifestPlaceholders = [app_icon: rootProject.ext.android.preReleaseAppIcon]
            zipAlignEnabled true
            shrinkResources true
            versionNameSuffix "-preRelease"
            applicationIdSuffix ".preRelease"
            signingConfig signingConfigs.production
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField("String", "API_URL", rootProject.ext.apiUrl.preRelease)
        }

        release {// 线上正式
            resValue "string", "app_name", rootProject.ext.android.releaseAppName
            manifestPlaceholders = [app_icon: rootProject.ext.android.releaseAppIcon]
            zipAlignEnabled true
            shrinkResources true

            signingConfig signingConfigs.production
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField("String", "API_URL", rootProject.ext.apiUrl.release)
        }
    }

    /**
     * productFlavors 字面翻译是产品口味,在多渠道打包用的比较多,或者是针对同一款应用不同的使用限制。
     * 在productFlavors 中可以重写 defaultConfig 中的配置。在默认情况下编译系统是没有创建 productFlavors 的。
     * 这里示范创建了付费和免费两种产品特性,每种特性定义了不同的应用id,所以同一款手机可以同时安装者款应用
     */
    productFlavors {
        free {
            applicationId 'com.example.myapp.free'
        }

        paid {
            applicationId 'com.example.myapp.paid'
        }
    }

    /**
     * 拆分专用版本的apk,以减小应用的提交
     * 比如:jni时分别拆分成arm版和x86版或者根据屏幕密度拆分
     */
    splits {
        // 屏幕密度分割设置
        density {
            // 启用或禁用密度分割机制
            enable false
            // 从分割中排除这些密度
            exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
        }
    }

    // 打包完成后的一些copy操作和修改apk名字或路径等操作
    android.applicationVariants.all { variant ->
        // delete previous files first
        delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"

        variant.mergeAssets.doLast {
            def sourceDir = "${buildDir}/../../../../.."

            copy {
                from "${sourceDir}"
                include "assets/**"
                include "src/**"
                include "jsb-adapter/**"
                into outputDir
            }

            copy {
                from "${sourceDir}/main.js"
                from "${sourceDir}/project.json"
                into outputDir
            }
        }

        //修改apk包名
        variant.outputs.all { output ->
            outputFileName = "app-${variant.name}-${defaultConfig.versionName}-${defaultConfig.versionCode}.apk"
        }

        //混淆对应文件输出
        variant.outputs.each { output ->
            if (variant.getBuildType().isMinifyEnabled()) {
                variant.assemble.doLast{
                    copy {
                        from variant.mappingFile
                        into "${projectDir}/mappings"
                        rename { String fileName ->
                            "mapping-${variant.name}.txt"
                        }
                    }
                }
            }
        }
    }

    // 声明本地 aar 文件地址
    repositories {
        flatDir {
            dirs 'libs'
        }
    }

    //jdk 配置
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    //lib包配置 设置 .so 资源路径
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    // 多渠道/多环境 的不同配置
    flavorDimensions("default")
    productFlavors {
        qudao1 {
            dimension "default"
            //自定义项目名称
            resValue "string", "app_name", "渠道1"
            //自定义参数  在BUildConfig 里调用
            buildConfigField("String", "orgId", '""')
        }
        qudao2 {
            dimension "default"
            resValue "string", "app_name", "渠道2"
            buildConfigField("String", "orgId", rootProject.ext.channel.csOrgId)
        }
    }

    //执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。
    lintOptions {
        abortOnError false
        checkReleaseBuilds false
    }

    //文件重复
    packagingOptions {
        exclude 'lib/arm64-v8a/ffmpeg.so'
    }

    configurations {
        //编译期排除commons模块
        compile.exclude module: 'commons'
        //在整个构建过程中排除com.squareup.retrofit2:adapter-rxjava
        all*.exclude group: 'com.squareup.retrofit2', module: 'adapter-rxjava'
    }

    //全局强制使用
    configurations.all {
        resolutionStrategy {
            force 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
        }
    }
}

/**
 * Gradle依赖管理是依靠俩个classpath:compileClasspath、runtimeClasspath
 * compileClasspath:编译时能使用的代码和类,当一个组件参与编译时,Gradle会将其放在compileClasspath中
 * runtimeClasspath:运行时使用的代码和类,当一个组件参与打包时,Gradle就会将其放在runtimeClasspath中
 * 编译时:代码还在编写阶段,只要还没有编译为class,就是编译时
 * 运行时:当编译成class文件,在机器上运行的时候叫做运行时
 * compileClasspath中含有的代码和类库,是我们在编写代码的时候需要使用到的类库,如果这里面没有的类库,我们编写时是会找不到该类的
 * runtimeClasspath这个里面主要包括app运行时需要的类库,如果这个里面没有包含的库,那么运行时找不到类而crash
 * implementation、api 这些操作符只是对依赖库不同的操作方式,其核心的逻辑就是,从远程拉下来的库到底是放在compileClasspath中还是runtimeClasspath还是俩个都放
 */


/**
 * 配置项目的依赖关系
 * 三种依赖方法:1.本地依赖,2.库依赖,3.远程依赖
 * 两种依赖方式:
 *
 * 1.implementation,会添加依赖到编译路径,并且会将依赖打包输出到aar/apk,但编译时不会把依赖暴露给其他moudle
 * 比如:A implementation B B implementation C,
 * 在B中,可以使用C中类库,
 * 在A中,不能使用C只给的类库,但是可以使用B中类库
 * 这是因为implementation引入的依赖,会把C加入B的compileClasspath和runtimeClasspath,会把C加入A的runtimeClasspath
 * 因为C没有加入A的compileClasspath,所以A没有办法在编译时访问C中的类库,又是因为C加入A的runtimeClasspath,所以A可以在运行时访问C类库
 *
 * 2.api,会添加依赖到编译路径,并且把依赖打包输出到aar/apk,依赖可以传递
 * 比如:A implementation B B api C,
 * 在B中,可以使用C中类库
 * 在A中,可以使用B中类库,也可以使用C中类库
 * 因为api引入的依赖,会把C加入B的compileClasspath和runtimeClasspath,
 * 同时会把C加入A的compileClasspath和runtimeClasspath,所以A也可以在编译时访问C中类库
 *
 * 3.compileOnly,依赖只在编译时使用,不会打包到aar/apk运行时不能使用
 * 比如:A implementation B B compileOnly C
 * A访问不到C的代码,B可以访问C,且C不会打包到apk中
 *
 * 4.runtimeOnly,依赖编译时不能使用,只会打包到aar/apk运行时使用
 * 比如:A implementation B B compileOnly C
 * AB都不可以调用C中代码,但是C会打包到APK中
 *
 * 5.annotationProcessor,用于注解处理器的依赖配置
 * 6.testImplementation,用于指定在测试代码的依赖。
 * 7.androidTestImplementation,用于指定在测试代码的依赖。
 * 8.debugImplementation,
 * 9.releaseImplementation,
 * 10.unitTestImplementation,
 *
 * isForce, 表示强制使用该版本的依赖
 * strictly, 一种强力版本约束,可以使用(!!)简写
 * exclude, 移除一个依赖,设置忽略指定的依赖,被忽略的依赖就被视为从来没有依赖,目前我测试的情况看来,这个只适用于远程依赖
 * transitive, 是否允许依赖传递
 * jar冲突, 如果app引用一个aar,arr中有一个xx.jar,而app中又再次引用这个xx.jar,
 * 这个时候就需要让aar中引用jar的操作符用 compileOnly 代替 implementation
 *
 * 版本号法则:
 * 1.3, 1.3.0-beta3 --> 固定版本号
 * [1.0.0, 1.3.0) --> >= 1.0.0 < 1.3.0 ,[ 含 = ,) 不含 =
 * 1.+, [1.0,) --> >= 1.0 版
 * latest.integration、latest.release --> 最新版本
 */
dependencies {
    // 库依赖
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    //测试需要的依赖包,大部分仅支持debug模式下,relase可调用不到哦!
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    //动态版本号
    implementation 'com.android.support.constraint:constraint-layout:+'
    // 本地依赖,'../libs'下所有的.jar和.aar文件都添加到项目构建中
    implementation fileTree(dir: '../libs', include: ['*.jar', '*.aar'])
    // 本地依赖,将指定文件添加到依赖中
    implementation file('libs/aaa.jar')
    // 本地依赖,依次将多个指定文件添加到依赖中
    implementation files('libs/aaa.jar', 'libs/bbb.jar')
    // 本地依赖,添加AndroidLibrary类型的Module到依赖中
    implementation project(':libcocos2dx')
    // 远程依赖的日常写法 第三方开源库
    implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
    // 远端依赖的完整写法
    implementation group: 'com.tencent.mm.opensdk', name: 'wechat-sdk-android-without-mta', version: '6.8.0'

    api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
    compileOnly 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
    runtimeOnly 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
    annotationProcessor 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'

    implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0') {
        isForce = true//在版本冲突的情况下优先使用3.1版本
    }
    implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta') {
        version {
            strictly("6.8.0")
        }
    }
    implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0') {
        //排除特定的依赖
        exclude module: 'cglib' //by artifact name
        exclude group: 'org.jmock' //by group
        exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
    }
    //group和module代表的意义
    implementation("org.hibernate:hibernate:3.1")
    group = org.hibernate
    module = hibernate
    version = 3.1

    api('org.hibernate:hibernate:3.1') {
        // 禁用依赖传递
        // 传递依赖:A => B => C ,B 中使用到了 C 中的依赖,
        // 如果打开传递依赖,则 A 能使用到 B中所使用的 C 中的依赖,
        // 默认都是打开,即 true
        transitive = false
    }

    //重复引用问题
    compile ('com.squareup.retrofit2:adapter-rxjava:2.1.0'){
        // 冲突时优先使用该版本
        force = true
        // 依据构建名称排除
        exclude module: 'rxjava'
        // 依据组织名称排除
        exclude group: 'com.squareup.retrofit'
        // 依据组织名称+构件名称排除
        exclude group: 'com.squareup.retrofit', module: 'rxjava'
        // 为本依赖关闭依赖传递特性
        transitive = false
    }
}