組件化架構(gòu)筆記(第三章)

Gradle基礎(chǔ)

Gradle的生命周期分為三個(gè)不同的階段:初始化 -》 配置 -》 構(gòu)建

初始化:settings.gradle

配置:build.gradle

構(gòu)建:gradle

初始化階段會(huì)讀取根目錄下setting.gradle的include信息,決定哪些工程會(huì)加入構(gòu)建過程,并且創(chuàng)建project實(shí)例。

配置階段會(huì)按引用樹去執(zhí)行所有工程的build.gradle腳本,配置project對(duì)象,一個(gè)對(duì)象由多個(gè)任務(wù)組成。

運(yùn)行階段會(huì)根據(jù)Gradle命令傳遞過來的Task名稱,執(zhí)行相關(guān)依賴任務(wù)。

版本參數(shù)優(yōu)化

每個(gè)module的build.gradle文件都擁有一些必要的屬性,同一個(gè)Android工程中,在不同的模塊中要求這些屬性一致,如果不一致會(huì)造成資源 的重復(fù),另一方面會(huì)降低編譯效率。那么就必須有一個(gè)統(tǒng)一的、基礎(chǔ)的gradle配置。

項(xiàng)目依賴統(tǒng)一管理方案

資源引用配置

1 使用sourceSets的方式來指定文件的路徑。

sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
}

2 可以動(dòng)態(tài)添加res資源,在buildtype 和productFlavor中定義resValue變量

resValue "string","app_name","xxx"

resValue只能動(dòng)態(tài)添加資源,無法替換資源。如果資源名重復(fù),Gradle會(huì)提示重復(fù)定義資源。

3可以指定特定尺寸的資源

resConfigs "hdpi","xhdpi","xxhdpi"

4 通過build.gradle編譯生成BuildConfig文件,可以直接讓代碼讀取到BuildConfig中的值。

buildConfigField("String","BASE_URL","\"https://xxx.com.cn\"")

在buildConfig文件中就會(huì)得到:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 10101;
  public static final String VERSION_NAME = "1.01.01";
  // Fields from build type: debug
  public static final String BASE_URL = "https://xxx.com.cn";
}
Gradle加載的優(yōu)先級(jí)

BuildType -> productFlavor -> Main -> dependencies

最左邊的優(yōu)先級(jí)越高

Build types

Gradle在Android中的build type是用來處理app或者library應(yīng)該被構(gòu)建成什么類型,在這個(gè)配置中,我們可以定義應(yīng)用的包名是什么,是否自動(dòng)去除掉沒有引用的資源,是否開啟混淆等等。

buildTypes {
        release {
            //設(shè)置正式包名稱
            applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    project.ext { appName = 'xxx' }
                    def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
                    outputFileName = new File(newName)
                }
            }
            //開啟混淆
            minifyEnabled true
            //Zipalign優(yōu)化
            zipAlignEnabled true
            //移除無用的resource文件
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            
        }
        debug {
            minifyEnabled false
            shrinkResources false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug
            applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    project.ext { appName = 'XXX' }
                    def newName = project.ext.appName +"-" + defaultConfig.versionName + "-" +buildTime() + ".apk"
                    outputFileName = new File(newName)
                }
            }
        }
Product flavors

與build type相反,build type用來構(gòu)建不同類型的app,debug版或release版,而produc flavors則是用來在同一個(gè)app上創(chuàng)建不同的版本,如付費(fèi)版和免費(fèi)版。一個(gè)非常常見的應(yīng)用場(chǎng)景就是我們創(chuàng)建了一個(gè)銀行管理的app給不同銀行提供服務(wù),但是不同的銀行App的logo不一樣,有produc flavors就能在基于一套代碼上創(chuàng)建不同版本的app或者library。

productFlavors {
           red {
               applicationId 'com.gradleforandroid.red'
               versionCode 3
            }
         blue {
               applicationId 'com.gradleforandroid.blue'
               minSdkVersion 14
               versionCode 4
            }
      }

Multiflavor variants

在某些情況下,我們可能需要進(jìn)行flavors的組合,比方說你的app有兩套主題,綠色主題和紅色主題,然后有兩個(gè)版本,付費(fèi)版和免費(fèi)版,你可能需要進(jìn)行組合,類似于紅色免費(fèi)版,紅色付費(fèi)版,綠色免費(fèi)版,綠色付費(fèi)版。通過使用flavorDimensions可以解決flavors組合的問題,

flavorDimensions "color", "price"
       productFlavors {
           red {
               flavorDimension "color"
           }
           blue {
               flavorDimension "color"
          }
         free {
               flavorDimension "price"
           }
            paid {
               flavorDimension "price"
         }
      }

Variant filters

在某些情況下,可能我們不想使用某種build variant,例如現(xiàn)在有debug和release的build type,red和blue的flavors,但是,blue還是測(cè)試環(huán)境根本現(xiàn)在用不到blue的release版本,那么我們可以直接過濾掉,在android studio中的buildVariants窗口就不會(huì)出現(xiàn)了,過濾可以在app模塊或者library模塊的build.gradle文件中加入如下代碼:

android.variantFilter { variant ->
    if (variant.buildType.name.equals('release')) {
        variant.getFlavors().each() { flavor ->
            if (flavor.name.equals('blue')) {
                variant.setIgnore(true);
            }
        }
    }
}   

gradle的依賴特性

1 implementation

會(huì)將指定的依賴添加到編譯路徑,并且會(huì)將該依賴打包到輸出,如apk中,但是這個(gè)依賴在編譯時(shí)不能暴露給其他模塊,例如依賴此模塊的其他模塊。這種方式指定的依賴在編譯時(shí)只能在當(dāng)前模塊中訪問。

例如:

有兩個(gè)模塊app 和test,模塊app依賴test,test添加了遠(yuǎn)程二進(jìn)制庫依賴joda-time,在test模塊中使用沒有問題,在app模塊中使用則報(bào)錯(cuò)。

2 api

使用api配置的依賴會(huì)將對(duì)應(yīng)的依賴添加到編譯路徑,并將依賴打包輸出,但是這個(gè)依賴是可以傳遞的,比如模塊A依賴模塊B,B依賴庫C,模塊B在編譯時(shí)能夠訪問到庫C,但是與implemetation不同的是,在模塊A中庫C也是可以訪問的。

3 compileOnly

compileOnly修飾的依賴會(huì)添加到編譯路徑中,但是不會(huì)打包到apk中,因此只能在編譯時(shí)訪問,且compileOnly修飾的依賴不會(huì)傳遞

4 runtimeOnly

這個(gè)與compileOnly相反,它修飾的依賴不會(huì)添加到編譯路徑中,但是被打包到apk中,運(yùn)行時(shí)使用。

5 annotationProcessor

用于注解處理器的依賴配置,像第三方庫 ButterKnife

Gradle的一些配置

開啟Gradle的守護(hù)進(jìn)程來構(gòu)建項(xiàng)目:

org.gradle.daemon=true

如果你要構(gòu)建一個(gè)多Module并且依賴關(guān)系比較復(fù)雜的項(xiàng)目,那么你可以使用并行項(xiàng)目執(zhí)行:

org.gradle.parallel=true

在Gradle主目錄中配置的屬性優(yōu)先級(jí)高于在項(xiàng)目中配置的屬性。當(dāng)你并不想一個(gè)個(gè)項(xiàng)目的去改動(dòng)配置時(shí),可以定義一份常用的Gradle配置文件放在Gradle的主目錄下

對(duì)于內(nèi)存較小的機(jī)器避免Gradle編譯卡頓

修改gradle.properties,避免影響其它人編譯速度,把修改的gradle.properties文件放到用戶文件夾.gradle下

#設(shè)置最大堆內(nèi)存為1.5g和最大非堆內(nèi)存0.5g
org.gradle.jvmargs=-Xmx1536m -XX\:MaxPermSize\=512m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8
#不啟用守護(hù)進(jìn)程
org.gradle.daemon=false
#不啟用并行編譯
org.gradle.parallel=false
#使用構(gòu)建緩存
android.enableBuildCache=true

修改build.gradle文件,如下:

dexOptions {
        //最大堆內(nèi)存
        javaMaxHeapSize "2g" // 1g should be also OK
}
壓縮Apk大小
加快Build速度

Gradle的Android插件在 buildType 上有一個(gè)名為 minifyEnabled 的布爾屬性,我們需要將其設(shè)置為true以啟用ProGuard:

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

壓縮Resource文件

自動(dòng)壓縮的方式很簡(jiǎn)單,就是在構(gòu)建中配置 shrinkResources 屬性。如果將此屬性設(shè)置為true,Android構(gòu)建工具將自動(dòng)檢測(cè)哪些資源未被使用,并且不會(huì)將它們包括在APK中。

android {
   buildTypes {
       release {
               minifyEnabled = true
               shrinkResources = true
        }
   }
}

使用 resConfigs 屬性配置要保留的資源,然后其余的將被拋出。

defaultConfig {
           resConfigs "en", "da", "nl"
           resConfigs "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
忽略Lint檢查

當(dāng)使用Gradle執(zhí)行構(gòu)建時(shí),Android構(gòu)建任務(wù)將會(huì)對(duì)代碼執(zhí)行Lint檢查。Lint是一個(gè)靜態(tài)代碼分析工具,用于標(biāo)記布局和Java代碼中的潛在錯(cuò)誤。在某些情況下,Lint一旦報(bào)錯(cuò),構(gòu)建就會(huì)停止。如果之前沒有在項(xiàng)目中使用Lint,并且我們想遷移到Gradle,Lint可能會(huì)出現(xiàn)很多錯(cuò)誤。為了使構(gòu)建工作不會(huì)因?yàn)長int檢查而中斷,你可以配置Gradle來忽略Lint錯(cuò)誤,并通過禁用 abortOnError 來阻止它們中止構(gòu)建。這只是一個(gè)臨時(shí)解決方案,因?yàn)楹雎訪int檢查可能會(huì)產(chǎn)生像丟失翻譯類似這樣的潛在錯(cuò)誤,這可能會(huì)導(dǎo)致應(yīng)用程序崩潰的問題。為了防止Lint阻塞構(gòu)建過程,可以像下面這樣禁用abortOnError:

android {
       lintOptions {
           abortOnError false
       }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容