Gradle - 構(gòu)建的基本知識(shí)

本文是官網(wǎng)的個(gè)人簡(jiǎn)略版。

構(gòu)建過(guò)程

官網(wǎng)上的圖:

image.png

在生成最終的 APK 之前,packager 還會(huì)用 zipalign 來(lái)對(duì) app 進(jìn)行優(yōu)化以減少運(yùn)行時(shí)的占用內(nèi)存。

自定義構(gòu)建配置

利用 Gradle 和 Android 插件,可以從以下幾方面對(duì)編譯進(jìn)行配置:

  • Build Types
    通常用于不同開(kāi)發(fā)周期的配置,Android Studio 默認(rèn)會(huì)創(chuàng)建 debug 和 release 兩種編譯類(lèi)型。
  • Product Flavors
    用于為用戶(hù)提供不同的 app 版本,如免費(fèi)和收費(fèi)版。
  • Build Variants
    Gradle 用于編譯 app 的配置,build variant 由 build type 和 product flavor 共同產(chǎn)生。我們不直接配置 build variant,但通過(guò) build type 和 product flavor 將生成 build variant。
  • Manifest Entries
    我們可以在 build variant 配置(也就是 build type 和 product flavor 的配置)中指定 manifest 文件某些屬性的值,如應(yīng)用名、最小 SDK、target SDK 等。
  • Dependencies
    本地或遠(yuǎn)程依賴(lài)。
  • Signing
    在編譯配置中指定簽名設(shè)置并在構(gòu)建過(guò)程中自動(dòng)為 apk 簽名。
  • ProGuard
    可以為不同的 build variant 指定不同的混淆規(guī)則。
  • Multiple APK Support
    編譯不同的 apk,這些 apk 只包含特定屏幕尺寸或 abi 所需要的代碼和資源。

編譯配置文件

一個(gè) Android Studio 工程目錄如下:

image.png

在編譯配置文件中,普通文本文件使用 DSL(Domain Specific Language) 來(lái)描述配置,而操作編譯邏輯使用的 Groovy。

Gradle 設(shè)置文件

工程根目錄的 settings.gradle 用于告訴 Gradle 編譯時(shí)需要包含哪些 module。如:

include ‘:app’

頂層的編譯文件

工程根目錄的 build.gradle 文件,定義了應(yīng)用于工程中所有 module 的編譯配置。默認(rèn)的,它使用 buildscript 塊來(lái)確定所有 module 的 Gradle 倉(cāng)庫(kù)和依賴(lài)。
如:

/**
 * buildscript 塊用于配置 Gradle 自身的倉(cāng)庫(kù)和依賴(lài)。
 * 如它依賴(lài)的 Android plugin 將為 Gradle 提供編譯 Android app 模塊所需的額外指令。
 */

buildscript {

    /**
     * Gradle 搜索和下載依賴(lài)所用的倉(cāng)庫(kù)。Gradle 預(yù)配置的有 JCenter、MavenCentral、Ivy。
     */

    repositories {
        jcenter()
    }

    /**
     * Gradle 編譯工程所需要的依賴(lài)。
     */

    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}

/**
 * allprojects 塊用來(lái)配置所用 module 使用的倉(cāng)庫(kù)和依賴(lài)。
 */

allprojects {
   repositories {
       jcenter()
   }
}

配置工程范圍的屬性

我們可以在頂層的 build.gradle 中添加一個(gè) ext 塊來(lái)配置額外屬性,這些屬性將在所有 module 中共享。
如:

buildscript {...}

allprojects {...}

// ext 塊包含自定義屬性并對(duì)所有 module 可用。
ext {
    // The following are only a few examples of the types of properties you can define.
    compileSdkVersion = 26
    buildToolsVersion = "26.0.1"
    // You can also create properties to specify versions for dependencies.
    // Having consistent versions between modules can avoid conflicts with behavior.
    supportLibVersion = "26.1.0"
    ...
}
...

在 module 的 build.gradle 文件中可以使用以下語(yǔ)法來(lái)訪問(wèn)這些屬性:

android {
  // Use the following syntax to access properties you defined at the project level:
  // rootProject.ext.property_name
  compileSdkVersion rootProject.ext.compileSdkVersion
  buildToolsVersion rootProject.ext.buildToolsVersion
  ...
}
...
dependencies {
    compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    ...
}

注意:應(yīng)避免這種用法,因?yàn)樗鼘?dǎo)致使用這些屬性的 module 耦合在一起。

Module 層的編譯文件

每一個(gè) module 目錄的 build.gradle 文件。
如:

/**
 * 第一行將 Android plugin 應(yīng)用到編譯該 module 的 Gradle,這樣 android 塊才可用于指定 Android特定的編譯項(xiàng)。
 */

apply plugin: 'com.android.application'

/**
 * android 塊用于配置所有的 Android 特定編譯項(xiàng)。
 */

android {

  /**
   * buildToolsVersion:SDK build tools 的版本。
   */

  compileSdkVersion 26
  buildToolsVersion "26.0.1"

  /**
   * The defaultConfig 塊包含了所有 build variant 的默認(rèn)配置,編譯系統(tǒng)可以動(dòng)態(tài)
     * 覆蓋 main/AndroidManifest.xml 的默寫(xiě)屬性。我們也可以在 product flavors 中為不同版本的 app 重寫(xiě)這些值。 
   */

  defaultConfig {

    /**
     * 發(fā)布的包的唯一標(biāo)識(shí),但源碼仍會(huì)引用定義在 main/AndroidManifest.xml 文件中的包名。
     */

    applicationId 'com.example.myapp'

    minSdkVersion 15

    targetSdkVersion 26

    versionCode 1

    versionName "1.0"
  }

  /**
   * buildTypes 塊用于配置多種 build type。
   * 編譯系統(tǒng)默認(rèn)會(huì)定義兩種 build type:debug和release。debug 版本不會(huì)顯式地顯示在默認(rèn)的編譯配置中,但
   * 它包含了調(diào)試工具并會(huì)使用 debug 密鑰進(jìn)行簽名。
   * release 版本會(huì)使用混淆設(shè)置并且默認(rèn)沒(méi)有簽名。
     * (這里指的是默認(rèn)生成的文件內(nèi)容,實(shí)際中往往會(huì)做修改,如為 release 配置簽名)
   */

  buildTypes {

    release {
        minifyEnabled true // Enables code shrinking for the release build type.
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  /**
   * productFlavors 塊用于配置多種的 product flavors。編譯系統(tǒng)默認(rèn)生成的文件沒(méi)有創(chuàng)建這部分。
   */

  productFlavors {
    free {
      applicationId 'com.example.myapp.free'
    }

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

  /**
   * splits 塊配置不同的 apk 編譯,每一個(gè)將只包含所支持的屏幕尺寸或 abi 的源碼和資源。
   */

  splits {
    // 設(shè)置基于屏幕尺寸的 multiple apk
    density {

      // 是否編譯 multiple apk
      enable false

      // 在編譯 multiple apk 時(shí)排除這些密度
      exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
    }
  }
}

/**
 * module 級(jí)別依賴(lài)
 */

dependencies {
    compile project(":lib")
    compile 'com.android.support:appcompat-v7:26.1.0'
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Gradle 屬性文件

gradle.properties
配置工程范圍的 Gradle 設(shè)置,如 Gradle 進(jìn)程的最大堆大小。

local.properties
為編譯系統(tǒng)配置本地環(huán)境變量,如 SDK 安裝目錄。該目錄內(nèi)容一般由 Android Studio 自動(dòng)生成,所以通常不應(yīng)該手動(dòng)修改或者引入版本控制系統(tǒng)(不過(guò)因?yàn)闆](méi)必要引入 VCS 中,所以我們可以在這里配置簽名信息)。

Source Sets 源集

Android Studio將每一個(gè) module 的代碼和資源歸到一個(gè)源集中,一個(gè) module 的 main/ 源集包含了所有 build variant 共用的代碼和資源。
我們可以為不同的 build variant 添加額外的源集目錄:

  • src/main/
  • src/buildType/
  • src/productFlavor/
  • src/productFlavorBuildType/

例如,在生成一個(gè)「fullDebug」版本應(yīng)用時(shí),編譯系統(tǒng)將從以下目錄合并代碼、設(shè)置、資源

  • src/fullDebug/ (build variant 源集)
  • src/debug/ (build type 源集)
  • src/full/ (product flavor 源集)
  • src/main/ (main 源集)

如果不同源集中包含了同一文件的不同版本,Gradle 將采用以下的優(yōu)先級(jí)順序:
build variant > build type > product flavor > main source set > library dependencies

參考:
build process

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容