Android GradleAndroid

Gradle 基础知识与原理(3)-- build.gradle

2022-08-25  本文已影响0人  沐风雨木

学习了 Gradle 的基础知识与原理,咱们再来看 build.gradle 的配置详解,见下方内容:

一、Project 的 build.gradle 文件

// Top-level build file where you can add configuration options common to all sub-projects/modules.
// 翻译:顶级生成文件,您可以在其中添加所有子项目/模块通用的配置选项。

buildscript {//这里是gradle脚本执行所需依赖,分别是对应的maven库和插件
    ext.kotlin_version='1.5.30'
    repositories {
        google()//从Android Studio3.0后新增了google()配置,可以引用google上的开源项目
        jcenter()//是一个类似于github的代码托管仓库,声明了jcenter()配置,可以轻松引用 jcenter上的开源项目
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'////此处是android的插件gradle,gradle是一个强大的项目构建工具
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {//这里是项目本身需要的依赖,比如项目所需的maven库
    repositories {
        google()
        jcenter()
    }
}

// 运行gradle clean时,执行此处定义的task任务。
// 该任务继承自Delete,删除根目录中的build目录。
// 相当于执行Delete.delete(rootProject.buildDir)。
// gradle使用groovy语言,调用method时可以不用加()。
task clean(type: Delete) {
    delete rootProject.buildDir
}

1. buildscript{}

闭包里是 gradle 脚本执行所需依赖,分别是对应的 maven 库和第三方插件。

1.1 repositories{} 闭包:

配置远程仓库,该闭包中声明了 jcenter()google() 的配置,其中 jcenter 是一个代码托管仓库,上面托管了很多 Android 开源项目,在这里配置了 jcenter 后我们可以在项目中方便引用 jcenter 上的开源项目,从 Android Studio3.0 后新增了 google() 配置,可以引用 google 上的开源项目。

1.2 dependencies{} 闭包:

配置构建工具,该闭包使用 classpath 声明了一个 Gradle 插件,由于 Gradle 并不只是用来构建 Android 项目,因此此处引入相关插件来构建 Android 项目,其中 '3.0.0' 为该插件的版本号,可以根据最新的版本号来调整。

2. allprojects{}

闭包里是项目本身需要的依赖,比如项目所需的 maven 库。

问:
为什么同一个 build.gradle(Project)文件中 buildscript 和 allprojects 里面的内容基本上是一样的呢,
他们的区别在哪?

答:
buildscript 中的声明是 gradle 脚本自身需要使用的资源,
就是说他是 gradle 自己需要的资源,跟 module 其实并没有什么关系。
而 allprojects 声明的却是你所有 module 所需要使用的资源,
就是说如果你的每个 module 都需要用同一个第三库的时候,你可以在 allprojects 里面声明。

3. task clean(type: Delete){}**

运行 gradle clean 时,执行此处定义的 task。该任务继承自 Delete,删除根目录中的 build 目录。相当于执行 Delete.delete(rootProject.buildDir)。其实这个任务的执行就是可以删除生成的 Build 文件的,跟 Android Studioclean 是一个道理。

4. ext

ext 是自定义属性,现在很多人都喜欢把所有关于版本的信息都利用 ext 直接在此文件中用(咱们的项目就这样用的),或者放在另一个自己新建的 gradle 文件(version.gradle)中集中管理,这样在 build.gradle 文件中输入了 apply from:'version.gradle' 这句话,我们就可以读取到该文件下 ext 的信息,version.gradle 内容如下:

讲完 Projectbuild 文件,就来讲讲最后也是内容最多的文件了。

二、Module 的 build.gradle 文件:

从文件内容可以看出,主要分为三大部分,如下图所示:

//--------------------------------------------------第一部分----------------------------------------
plugins {
    id 'com.android.application'
}
//或 apply plugin: 'com.android.application'

//--------------------------------------------------第二部分----------------------------------------
android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.lifecycledemo"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
        ndk {
            abiFilters('armeabi-v7a', 'arm64-v8a')
        }

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    //目录指向配置
    sourceSets {
        main {
          //指定lib库目录
          jniLibs.srcDirs = ['libs']
        }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    // 配置 Java 编译(编码格式、编译级别、生成字节码版本)
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
//--------------------------------------------------第三部分----------------------------------------
dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

1. plugins{}

在讲 AGP 的时候有讲到一丢丢,就是通过 plugins {...} 引入插件。
这种叫做引入 Gradle 插件,而 Gradle 插件大致分为分为两种:

虽然脚本插件不是一个真正的插件,但是不能忽视它的作用.它是脚本文件模块化的基础,我们可以把庞大的脚本文件进行分块、分段整理,拆分成一个个共用、职责分明的文件,然后使用 apply from 来引用它们,比如我们可以把常用的函数放在一个 Utils.gradle 脚本里,供其他脚本文件引用。示例中我们把 App 的版本名称和版本号单独放在一个脚本文件里,清晰、简单、方便、快捷.我们也可以使用自动化对该文件自动处理,生成版本。
看下面代码:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'walle'
apply from: 'walle.gradle'
apply plugin: 'com.huawei.agconnect'

这里就引用了脚本插件:walle.gradle,可去项目中看源码。

说说 Gradle 插件的作用

把插件应用到你的项目中,插件会扩展项目的功能,帮助你在项目的构建过程中做很多事情。

然后我们说说 'com.android.application'

Android Gradle 插件的分类其实是根据 Android 工程的属性分类的。在 Andriod 中有 3 类工程,一类是 App 应用工程,它可以生成一个可运行的apk应用;一类是 Library 库工程,它可以生成 AAR 包给其他的 App 工程公用,就和我们的 Jar 一样,但是它包含了 Android 的资源等信息,是一个特殊的 Jar 包;最后一类是 Test 测试工程,用于对 App 工程或者 Library 库工程进行单元测试。

一般一个项目只会设置一个 App 插件,而 module 一般是会设置为 Library 插件

2. android{}

Android 插件提供的一个扩展类型,可以让我们自定义 Android Gradle 工程,是 Android Gradle 工程配置的唯一入口。

2.1 compileSdkVersion

是编译所依赖的 Android SDK 的版本,这里是 API Level

2.2 buildToolsVersion

是构建该 Android 工程所用构建工具的版本。

2.3 defaultConfig{}

譬如像上面代码,配置 jniLibs.srcDirs = ['libs'],可以在 Android studioAndroid 视图下生成 jniLibs 文件夹,可以方便我们存放 jar 包和库文件,其中 Android 视图下的 jniLibsproject 视图下的 libs 指向同一文件夹(app → libs),如下图所示:

2.4 productFlavors

在我看来他就是 Gradle 的多渠道打包,你可以在不同的包定义不同的变量,实现自己的定制化版本的需求。
比如设置不同的包名、应用名等。场景:当我们使用友盟统计时,通常需要设置一个渠道 ID ,那么我们就可以利用 productFlavors 来生成对应渠道信息的包,如:

android {
    productFlavors {
        wandoujia {
            //豌豆荚渠道包配置
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
            //manifestPlaceholders的使用在后续章节(AndroidManifest里的占位符)中介绍
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
            applicationId "com.wiky.gradle.xiaomi" //配置包名

        }
        _360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
        }
        //...
    }
}

当然也有更简洁的方式:

android {
    productFlavors {
        wandoujia {}
        xiaomi {}
        _360 {}
       //...
    }

    productFlavors.all {
        //批量修改,类似一个循序遍历
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
}

看看上图,我们就能发现我们在 productFlavors 中定义 manifestPlaceholders = [APP_NAME: "(测试)"] 之后,在 AndroidManifestlabel 加上 "${APP_NAME}",我们就能控制每个包打出来的名字是我们想要不同的名字,譬如测试服务器和生产服务器的包应该名字不一样。

2.5 buildTypes{}
 buildTypes {// 生产/测试环境配置
        release {// 生产环境
            buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://release.cn/\"")// 配置URL前缀
            minifyEnabled false//是否对代码进行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            signingConfig signingConfigs.release//设置签名信息
            pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
            zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
            applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
        }
        debug {// 测试环境
            buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
            buildConfigField("String", "URL_PERFIX", "\"https://test.com/\"")// 配置URL前缀
            minifyEnabled false//是否对代码进行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            signingConfig signingConfigs.debug//设置签名信息
            debuggable false//是否支持断点调试
            jniDebuggable false//是否可以调试NDK代码
            renderscriptDebuggable false//是否开启渲染脚本就是一些c写的渲染方法
            zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
            pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
            applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
        }
    }

构建类型,在 Android Gradle 工程中,它已经帮我们内置了 debugrelease 两个构建类型,两种模式主要车别在于,能否在设备上调试以及签名不一样,其他代码和文件资源都是一样的。一般用在代码混淆,而指定的混淆文件在下图的目录上,minifyEnabled=true 就会开启混淆:

常用关键字:

关键字 解释
buildConfigField 自定义函数变量
applicationIdSuffix 应用id后缀
versionNameSuffix 版本名称后缀
debuggable 是否生成一个debug的apk
minifyEnabled 是否混淆
proguardFiles 混淆文件
signingConfig 签名配置
manifestPlaceholders 是否去除未利用的资源,默认false,表示不去除
zipAlignEnable 是否使用zipalign工具压缩
multiDexEnabled 是否拆成多个Dex
multiDexKeepFile 指定文本文件编译进主Dex文件中
multiDexKeepProguard 指定混淆文件编译进主Dex文件中
2.6 signingConfigs

签名配置,一个 app 只有在签名之后才能被发布、安装、使用,签名是保护 app 的方式,标记该 app 的唯一性。如果 app 被恶意删改,签名就不一样了,无法升级安装,一定程度保护了我们的 app。而 signingConfigs 就很方便为我们提供这个签名的配置。storeFile 签名文件,storePassword 签名证书文件的密码,storeType 签名证书类型,keyAlias 签名证书中秘钥别名,keyPassword 签名证书中改密钥的密码。

默认情况下,debug 模式的签名已经被配置好了,使用的就是 Android SDK 自动生成的 debug 证书,它一般位于$HOME/.android/debug.keystore,其 key 和密码是已经知道的,一般情况下我们不需要单独配置 debug 模式的签名信息。

2.7 dexOptions{}

我们知道,Android 中的 Java 源代码被编译成 class 字节码后,在打包成 apk 的时候
被dx命令优化成 Android 虚拟机可执行的 DEX 文件。
DEX 文件比较紧凑,Android 费尽心思做了这个 DEX 格式,就是为了能使我们的程序在 Android 中平台上运行快一些。对于这些生成 DEX 文件的过程和处理,Android Gradle 插件都帮我们处理好了,Android Gradle 插件会调用 SDK 中的 dx 命令进行处理。

但是有的时候可能会遇到提示内存不足的错误,大致提示异常是 java,lang.OutOfMemoryError: GC overhead limit exceeded,为什么会提示内存不足呢?

其实这个 dx 命令只是一个脚本,它调用的还是 Java 编写的 dx.jar 库,是 Java 程序处理的,所以当内存不足的时候,我们会看到这个 Java 异常信息.默认情况下给 dx 分配的内存是一个 G8 ,也就是 1024MB
所以我们只需要把内存设置大一点,就可以解决这个问题,如下代码,我们把内存设置为 4g

android {
...
    dexOptions {
        javaMaxHeapSize "4g"
    }
...
}

dependencies{}
我们平时用的最多的大概就这个了,看下图:

  1. 首先第一句 compile fileTree(include: ['.jar'], dir: 'libs')*,这样配置之后本地 libs 文件夹下的扩展名为jar的都会被依赖,非常方便。
  2. 如果你要引入某个本地 module 的话,那么需要用 compile project('×××')
  3. 如果要引入网上仓库里面的依赖,我们需要这样写 compile group:'com.squareup.okhttp3',name:'okhttp',version:'3.0.1' ,当然这样是最完整的版本,缩写就把 group、name、version 去掉,然后以 ":" 分割即可。

但是到了 gradle3.0 以后 build.gradle 中的依赖默认为 implementation ,而不是
之前的 compile 。另外,还有依赖指令 api

问题:gradle 3.0中依赖implementation、api的区别:
其实 api 跟以前的 compile 没什么区别,将 compile 全部改成 api 是不会错的;
implementation 指令依赖是不会传递的,也就是说当前引用的第三方库仅限于本 module 内使
可参考:
android gradle依赖:implementation 和compile的区别

3. Gradle 实用技巧

比如:

可参考:
7个你应该知道的Gradle实用技巧

上一篇 下一篇

猜你喜欢

热点阅读