Android組件化架構學習筆記——Gradle優化

Gradle是Android項目開發環境的一部分,Android Studio每次配置編譯時都需要使用Gradle。

一.Gradle基礎:

Gradle本質上時一個自動構建工具,使用基於Groovy的特定領域語言(DSL)來聲明項目設置。使用Groovy最大哦的原因就是Groovy基本語法和Java一樣,最大程度適應Java開發。當利用Groovy編寫自定義插件時,語法並沒有太大差異,僅僅是配置機制需要調整。

Android Studio構建工程時,就是利用Gradle編寫的插件來加載工程配置和編譯文件。

  • 工程根目錄的build.gradle時配置整個工程引用的Gradle文件,能夠配置獲取Gradle引用倉庫的地址。
  • // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    buildscript {           //構建腳本引用
        repositories {      //插件倉庫配置
            google()
            jcenter()       //jcenter本質上是一個maven倉庫
            
        }
        dependencies {      //依賴插件
            classpath 'com.android.tools.build:gradle:3.4.1'
            classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
    
        }
    }
    
    allprojects {           //全部項目的配置
        repositories {      //全部項目引用的基礎倉庫配置
            google()
            jcenter()
            
        }
    }
    
    task clean(type: Delete) {          //聲明任務
        delete rootProject.buildDir     //刪除主路徑buildDir文件
    }
    
    dependencies {              //第三方庫的依賴
        compile 'com.alibaba:arouter-api:1.1.0'
        annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
        compile('com.facebook.fresco:fresco:0.10.0') {
            exclude group:''
        }
    
    
    }
    

根目錄的build.gradle文件會影響工程中其他模塊的build.gradle文件的引用倉庫的路徑

  • 當創建出一個新的module時,每個module都會有一個build.gradle文件。
  • apply plugin: 'com.android.application'     //引用編譯構建Gradle插件
    
    android {
        compileSdkVersion 28                    //編譯的工具對應版本
        buildToolsVersion "29.0.0"              //編譯工具對應版本
        defaultConfig {                         //默認配置
            applicationId "com.example.demo1"   
            minSdkVersion 15                    //最低支持版本
            targetSdkVersion 28                 //支持的目標版本
            versionCode 1                       //版本號
            versionName "1.0"                   //版本名
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"      //測試腳本
        }
        buildTypes {                    //構建類型
            release {                   //release版本配置
                minifyEnabled false     //是否打開混淆
                shrinkResources true    //是否打開資源混淆
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'     //混淆文件
                
            }
        }
    
        productFlavors {
            //用戶版本
            client {
                manifestPlacehoders = [
                    channel:"10086",     //渠道號
                    verNum:"1",          //版本號
                    app_name:"Gank"      //app名
                ]
            }
    
            //服務版本
            server {
                manifestPlacehoders = [
                        channel:"10087",     //渠道號
                        verNum:"1",          //版本號
                        app_name:"Gank服務版"      //app名
                ]
            }
    
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
        classpath 'com.android.tools.build:gradle:3.1.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
        implementation 'com.android.support:localbroadcastmanager:28.0.0'// add plugin
    //    implementation "io.reactivex.rxjava3:rxjava:3.x.y"
    
    
    }

build.gradle的第一行代碼重點引用了構建需要用到的Gradle插件工具庫。對比編寫Java代碼,可以認爲相當於"import"了一個Java工具庫。

每個build.gradle自身是一個Project對象,project.apply()會加載某個工具庫到project對象中;

apply plugin:"XXX"的方法會將project對象傳遞入工具庫,然後再通過插件中的Groovy文件來操作project對象的屬性,以完善配置初始化信息;

其中android{}和dependencies{}是函數方程式,使用閉包函數的編寫方式。其真實調用android{}和dependencies{}方法。方法中會設置project的屬性;

每個Project中包含很多Task的構建任務,每個Task中可以包含很多Action動作,每個Action相當於一個代碼塊,包含很多需要被執行的代碼。

  • Gradle對Android工程配置的地方,是主目錄中的settings.gradle的文件;
  • 當添加一個module時,Gradle會自動添加一個文件路徑到settings.gradle中的include函數中,聲明這些文件夾以一個模塊的形式存在,將此模塊引用到Gradle中進行編譯構建。如移除其中一項,對應的文件夾將不會被Gradle插件識別,Android  Studio也不會認爲此文件夾爲一個module目錄;
  • 每個Gradle文件都是一個project對象,Gradle管理這個project的生命週期

Gradle的生命週期settings.gradle(初始化)->build.gradle(配置)->gradle(構建):

1.初始化階段會讀取根目錄中的settings.gradle的include信息,決定哪些工程會加入構建過程,並且創建project實例;

2.配置階段會按引用樹去執行所有工程的build.gradle腳本,配置project對象,一個對象由多個任務組件。此階段也會去創建/配置Task及相關信息;

3.運行階段會根據Gradle命令傳遞過來的Task名稱,執行相關依賴。

二.版本參數優化:

每個module的build.gradle文件都擁有一些必要的屬性,同一個Android工程中,在不同模塊中要求這些屬性一致,如complieSDKVersion/buildToolVersion等。如引用不一致,屬性不會被合併引入工程中,這樣一方面會造成資源的重複/包量增大,另一方面會降低編譯效率。

那就必有一個統一的/基礎的Gradle配置,以下有三種方案可選:

第一種方式使用共同參數的方式進行配置:

  • 創建一個common_config.gradle文件;
  • 在common_config.gradle中編寫一些簡單的變量信息;
  • project.ext {
        complieSdkVersion = 28
        buildToolVersion = "29.0.0"
        minSdkVersion = 15
        targetSdkVersion = 28
        applicationId "com.example.demo1"
    }
    project.ext相當於一個變量類,其中屬性可以看作類中的靜態變量。
  • 在module的首行build.gradle中添加common_config文件,並通過引用類似引用靜態變量的方式來引用屬性。
  • apply plugin: 'com.android.library'
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用額外的配置
    android {
        compileSdkVersion project.ext.complieSdkVersion
        buildToolsVersion project.ext.buildToolVersion
    
    
        defaultConfig {
            minSdkVersion project.ext.minSdkVersion
            targetSdkVersion project.ext.targetSdkVersion
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'com.android.support:appcompat-v7:28.0.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    

第二種方式時使用Android對象配置:

因爲apply from引用了common_build.gradle,所以可以引用build.gradle中的Android對象。android{}中提供了android這個變量,可以進一步簡化android{}的參數編寫來簡化代碼。在common_build.gradle的project.ext中添加一個閉包方法來指定project對象變量。

  • setDefaultConfig = {
        extension ->        //閉包參數extension相當於android對象
            extension.compileSdkVersion compileSdkVersion
            extension.buildToolsVersion buildToolsVersion
            extension.defaultConfig {
                minSdkVersion minSdkVersion
                targetSdkVersion targetSdkVersion
    
                testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            }
            extension.dataBinging{
                enabled = true
            }
    }

然後在build.gradle中就可以使用setDefaultConfig了,類似屬性設置一樣,實質上是函數調用。

  • android {
        project.ext.setDefaultConfig android    //調用配置函數
        ....
    }

第三種方式時使用project對象配置:

  • //設置app 設置
    setAppDefaultConfig = {
        extension ->
            extension.apply plugin:'com.android.application'    //引入application插件庫
            extension.descriptaion "app"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }
    
    //設置Lib配置
    setLibDefaultConfig = {
        extension ->
            extension.apply plugin:'com.android.application'
            extension.descriptaion "lib"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }
    
    //設置Android配置
    setAndroidDefaultConfig = {
        extension ->
            extension.compileSdkVersion 28
            extension.buildToolsVersion "29.0.0"
            extension.defaultConfig {
                minSdkVersion 15
                targetSdkVersion 28
    
                testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
                javaCompileOptions {
                    annotationProcessorOptions {
                        arguments = [moduleName:extension.project.getName()]
                    }
                }
            }
            extension.dataBinging{
                enabled = true
            }
    }
    
    //設置依賴
    setDependencies = {
        extension ->
            extension.compile fileTree(dir: 'lib','include',['*.jar'])
            //每個module都需要引用路由apt插件庫才能生成相應的代碼,這裏無須重複編寫每個module
            extension.annotationProcessor 'com.alibaba:arouter-compiler:1.1.1'
    }

在build.gradle中只需要傳入project對象到閉包函數中即可:

  • //application module配置
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用額外的配置
    project.ext.setAppDefaultConfig project
    
    //library module配置
    apply plugin: '${rootProject.rootDir}/common_config.gradle'     //引用額外的配置
    project.ext.setLibDefaultConfig project

因爲組件化會用到application module和library module,所以需要分開編寫共性的方法,可以爲一些公用的庫添加引用。

三.調試優化:

業務模塊調試,將單一模塊做成app啓動,然後用於調試測試。這樣保證單獨模塊可以分離調試。

需要變更的地方:

  • 業務模塊是Library module,獨立調試需要將模塊做成application module才能引入app構建流程。在common_config.gradle中,只需替換對象即可。
  • 每個Application都需要配置ApplicationId

可以使用直接配置屬性:

applicationId project.ext.applicationId

也可以在common_config中添加函數配置:

  • setAppDefaultConfig = {
        extension ->
            ...
            extension.android.defaultConfig{
                applicationId applicationId+"."+extension.getName()
            }
            ...
    }

這裏extension.getName(),在默認ApplicationId後添加module名字,用於區分不同module產生的單獨的app。

  • 在src中建立debug文件夾,同main文件夾目錄類似,用於放置需要調試AndroidManifest.xml文件/Java文件/res資源文件。AndroidManifest文件需要設置默認啓動activity文件,不給啓動activity設置Default屬性,否則會導致安裝後activity被啓動的問題:
  •     <activity android:name=".DebugActivity"
                android:theme="@style/AppTheme">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
  • 在common_config中需要聲明單獨模塊調試變量,如:
  • project.ext{
        ...
        isNewDebug = false
        ...
    }

    在模塊build.gradle中變量isNewDebug作爲開關:

  •         if(project.ext.isNewDebug){
                project.setLibDefaultConfig project     //設置lib配置
            }else {
                project.setAppDefaultConfig project     //設置app配置
            }
    

    在sourceSets資源配置,配置AndroidManifest的地址及res資源地址,編譯構建是Gradle會選取內的資源:

  • sourceSets {
        main{
            if (project.ext.isNewDebug) {
                manifest.srcFile 'src/debug/AndroidManifest.xml'
                res.srcDirs = ['src/debug/res','src/main/res']
            }else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                resources {
                    //排除Java/debug文件夾下的所有文件
                    exclude 'src/debug/*'
                }
            }
        }
    }
  • app module需要移除已經單獨調試的模塊的依賴:
  • dependencies {
        if(!project.ext.isNewDebug){
            compile project(':news')
        }
    }
    

四.資源引用配置:

Gra​​​​​dle​​有多種引用的方式

  • 使用sourceSets的方式指定文件的路徑。sourceSets還可以指定更多的資源設置屬性的路徑:
  • sourceSets {
        main{
            manifest.srcFile 'src/debug/AndroidManifest.xml'    //指定AndroidManifest
            res.srcDirs = ['src/main/res']                      //指定Java文件路徑
            resources.srcDirs = ['src']                          //全部資源文件路徑
            aidl.srcDirs = ["src"]                              //指定aidl文件路徑
            renderscript.srcDirs = ['src']                      //指定renderscript文件路徑
            res.srcDirs = ['src']                               //res資源文件路徑
            assets.srcDirs = ['assets']                         //指定資產文件路徑
            
        }
    }
  • 可以動態添加res資源,在buildtype和productFlavor中定義resValue:
  • resValue "string","app_name",....
  • 可以指定特定尺寸的資源,也可以在buildType和productFlavor中定義:
  • resConfigs "hdpi","xhdpi","xxhdpi"
  • Gradle加載優先級爲BuildType->productFlavor->main->dependencies。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章