亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Gradle 運用在組件化中

前面幾節我們學習了 Gradle 的任務,命令已經學會了自定義插件。那么下面我們就來學習以下如何將前面所學的 Gradle 知識運用在組件化架構中。我們現在的項目基本都是組件化的架構。但是我們真的了解組件化嗎?我們通過這節學習,希望能夠幫助到大家在組件化開發中有更高的效率。

1. 組件化與集成化

我們的項目最開始創建時是集成化模式的,但是由于我們一個團隊,有很多人在同時開發一個項目,但是大家都負責各自的模塊。這樣在集成化的模式下,大家要編譯跟大家不相關的別的模塊相關的代碼。所以就出現的組件化模式。在組件化模式下,各個模塊可以獨立運行。

集成化模式: 就是打包整個項目,編譯出一個全業務功能的 apk 文件。各個子模塊不能夠獨立運行,只能依賴于宿主 App。
組件化模式: 就是每個子模塊都能夠獨立運行,不需要依賴宿主 APP 殼。而且每個模塊都能夠編譯出 apk 文件。

2. Android 項目中組件化運用

我們下面來具體看下 Android 項目中我們怎么來實施組件化。我們知道我們發布市場肯定是要打一個全功能的 apk 包,也就是發布市場時是需要集成化的打包模式,而我們開發過程中是需要組件化模式的,所以我們需要一個開關來控制組件化和集成化打包模式。我們各個模塊都會有編譯工具版本,SDK 的版本,support 庫的版本號等。我們可以將這些抽離出來,單獨建立一個 Gradle 文件來配置這些全局變量。

2.1 config.gradle

我們創建一個單獨的config.gradle文件,定義全局變量,如下所示:

ext {

    // 定義一個項目全局變量isRelease,用于動態切換:組件化模式 / 集成化模式
    // false: 組件化模式(子模塊可以獨立運行),true :集成化模式(打包整個項目apk,子模塊不可獨立運行)
    isRelease = false

    // 建立Map存儲,對象名、key可以自定義
    androidId = [
            compileSdkVersion: 28,
            buildToolsVersion: "29.0.0",
            minSdkVersion    : 19,
            targetSdkVersion : 28,
            versionCode      : 1,
            versionName      : "1.0"
    ]

    appId = ["app"     : "com.bthvi.modular",
             "order"   : "com.bthvi.modular.order",
             "personal": "com.bthvi.modular.personal"]

  
    supportLibrary = "28.0.0"
    dependencies = [
            // ${supportLibrary}表示引用一個變量
            "appcompat"      : "com.android.support:appcompat-v7:${supportLibrary}",
            "recyclerview": "com.android.support:recyclerview-v7:${supportLibrary}",
            "constraint"     : "com.android.support.constraint:constraint-layout:1.1.3",
            "okhttp3"        : "com.squareup.okhttp3:okhttp:3.10.0",
            "retrofit"       : "com.squareup.retrofit2:retrofit:2.5.0",
            "fastjson"       : "com.alibaba:fastjson:1.2.58",
    ]
}

2.2 在 build.gradle 中引用 config.gradle

我們要引用我們上面定義的 config.gradle 文件,就需要在項目的根目錄下的 build.gradle 中加入以下代碼

apply from: "config.gradle"

2.3 在 module 中引用公共變量

前面我們在 config 定義了我們各個模塊可能都會用到的依賴庫,編譯版本,sdk 版本版本號等一些公共變量。下面我們就需要將這些變量在 module 的 build.gradle 中引入。這里我創建了一個項目有 common,order,person 以及主模塊 app 四個 module,下面我們以 order 為例。

def rootAndroidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies

android {
    compileSdkVersion rootAndroidId.compileSdkVersion
    buildToolsVersion rootAndroidId.buildToolsVersion
    defaultConfig {
        if (!isRelease) { // 如果是集成化模式,不能有applicationId
            applicationId appId.order // 組件化模式能獨立運行才能有applicationId
        }
        minSdkVersion rootAndroidId.minSdkVersion
        targetSdkVersion rootAndroidId.targetSdkVersion
        versionCode rootAndroidId.versionCode
        versionName rootAndroidId.versionName
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //當前項目的build.config文件里添加了一個boolean類型的變量 
        buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // 循環引入第三方庫
    support.each { k, v -> implementation v }
    implementation project(':common') // 公共基礎庫
}

Tips:這里我們在前面加入了buildConfigField,這個的作用是在當前模塊的 build.config 中加入一個 isRelease 的布爾型變量。因為 src 代碼中有可能需要用到跨模塊交互,如果是組件化模塊顯然不能跨模塊交互的。

2.4 在 module 的 build.gradle 中使用 isRelease 開關

我們引入定義的變量后,我們就需要在 module 中引入組件化開關,這里我們用 isRelease 表示,如果 isRelease 為 true,則表示當前為集成化模式,否則當前為組件化模式,各模塊可相互獨立。

Tips: 我們知道默認創建項目只有 app 模塊才能運行,那么我們現在組件化中需要各個模塊都能獨立運行,那么我們就需要根據 isRelease 開關來控制了。能夠獨立運行取決于為 build.gradle 第一行引入的是com.android.library還是com.android.application,只有引入后者module才能獨立運行。
根據上面的知識,我們應該在 module 中加入:

if (isRelease) { // 如果是生產發布版本時,各個模塊都不能獨立運行
    apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'
}

2.5 配置資源路徑

由于組件化和集成化模式中,module 的 AndroidManifest.xml 文件是不同的,組件化時,module 可以獨立運行,AndroidManifest.xml 中需要配置 appliation、啟動 activity 等。而集成化運行時只有主模塊可以配置。所以這里我們就需要這么配置。

// 配置資源路徑
    sourceSets {
        main {
            if (!isRelease) {
                // 如果是組件化模式,需要單獨運行時
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                // 集成化模式,整個項目打包apk
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }

2.6 配置組件化測試

我們在開發中可能都會遇到,自己的模塊運行需要別的模塊的數據,當沒有集成別的模塊的數據時,我們可以寫一些自己的測試數據,或是資源文件等等。就是只有在組件化中能夠用到,但是不需要出現在集成化打包后的生產包中的,我們可以單獨創建一個文件夾,集合化時使用exclude不要讓這個文件夾合并到項目中。具體如下所示:

    // 配置資源路徑
    sourceSets {
        main {
            if (!isRelease) {
                // 如果是組件化模式,需要單獨運行時
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                // 集成化模式,整個項目打包apk
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java {
                    // release 時 debug 目錄下文件不需要合并到主工程
                    exclude '**/debug/**'
                }
            }
        }
    }

Tips: exclude 的妙用非常多,如果我們一些測試代碼,測試數據,或是組件化單獨的資源文件我們都可以放在 debug 文件下。編譯的時候 exclude 會將這個模塊所有的 debug 文件夾下的文件不會合并到整個項目中去。

2.7 完整的 module 的配置

前面我們的配置都是將 order 模塊的 build.config,單獨拆各個模塊來講的??赡艽蠹矣悬c亂。下面我們看下完整的配置應該是怎樣的。

if (isRelease) { // 如果是發布版本時,各個模塊都不能獨立運行
    apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'
}

def rootAndroidId = rootProject.ext.androidId
def appId = rootProject.ext.appId
def support = rootProject.ext.dependencies

android {
    compileSdkVersion rootAndroidId.compileSdkVersion
    buildToolsVersion rootAndroidId.buildToolsVersion
    defaultConfig {
        if (!isRelease) { // 如果是集成化模式,不能有 applicationId
            applicationId appId.order // 組件化模式能獨立運行才能有 applicationId
        }
        minSdkVersion rootAndroidId.minSdkVersion
        targetSdkVersion rootAndroidId.targetSdkVersion
        versionCode rootAndroidId.versionCode
        versionName rootAndroidId.versionName
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    // 配置資源路徑
    sourceSets {
        main {
            if (!isRelease) {
                // 如果是組件化模式,需要單獨運行時
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                // 集成化模式,整個項目打包apk
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java {
                    // release 時 debug 目錄下文件不需要合并到主工程
                    exclude '**/debug/**'
                }
            }
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // 循環引入第三方庫
    support.each { k, v -> implementation v }
    implementation project(':common') // 公共基礎庫
}

3. 小結

本節,我們帶大家學習了 Gradle 在 Android 項目組件化中的運用。主要知識點有以下幾點:

  • 配置公共的依賴 jar 包,編譯版本,構建版本,版本號等。
  • 用 buildConfigField 將組件化開關添加到 build.config 中,這樣 Java 代碼也就可以使用組件化開關。
  • 配置資源文件,可以將我們的測試資源、代碼放在一個單獨的目錄下,使用 exclude,將這個目錄下的文件不合并到項目。