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

Gradle基礎

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

初始化:settings.gradle

配置:build.gradle

構建:gradle

初始化階段會讀取根目錄下setting.gradle的include信息,決定哪些工程會加入構建過程,并且創建project實例。

配置階段會按引用樹去執行所有工程的build.gradle腳本,配置project對象,一個對象由多個任務組成。

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

版本參數優化

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

項目依賴統一管理方案

資源引用配置

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 可以動態添加res資源,在buildtype 和productFlavor中定義resValue變量

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

resValue只能動態添加資源,無法替換資源。如果資源名重復,Gradle會提示重復定義資源。

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

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

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

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

在buildConfig文件中就會得到:

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加載的優先級

BuildType -> productFlavor -> Main -> dependencies

最左邊的優先級越高

Build types

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

buildTypes {
        release {
            //設置正式包名稱
            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優化
            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用來構建不同類型的app,debug版或release版,而produc flavors則是用來在同一個app上創建不同的版本,如付費版和免費版。一個非常常見的應用場景就是我們創建了一個銀行管理的app給不同銀行提供服務,但是不同的銀行App的logo不一樣,有produc flavors就能在基于一套代碼上創建不同版本的app或者library。

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

Multiflavor variants

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

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

Variant filters

在某些情況下,可能我們不想使用某種build variant,例如現在有debug和release的build type,red和blue的flavors,但是,blue還是測試環境根本現在用不到blue的release版本,那么我們可以直接過濾掉,在android studio中的buildVariants窗口就不會出現了,過濾可以在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

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

例如:

有兩個模塊app 和test,模塊app依賴test,test添加了遠程二進制庫依賴joda-time,在test模塊中使用沒有問題,在app模塊中使用則報錯。

2 api

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

3 compileOnly

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

4 runtimeOnly

這個與compileOnly相反,它修飾的依賴不會添加到編譯路徑中,但是被打包到apk中,運行時使用。

5 annotationProcessor

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

Gradle的一些配置

開啟Gradle的守護進程來構建項目:

org.gradle.daemon=true

如果你要構建一個多Module并且依賴關系比較復雜的項目,那么你可以使用并行項目執行:

org.gradle.parallel=true

在Gradle主目錄中配置的屬性優先級高于在項目中配置的屬性。當你并不想一個個項目的去改動配置時,可以定義一份常用的Gradle配置文件放在Gradle的主目錄下

對于內存較小的機器避免Gradle編譯卡頓

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

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

修改build.gradle文件,如下:

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

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

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

壓縮Resource文件

自動壓縮的方式很簡單,就是在構建中配置 shrinkResources 屬性。如果將此屬性設置為true,Android構建工具將自動檢測哪些資源未被使用,并且不會將它們包括在APK中。

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

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

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

當使用Gradle執行構建時,Android構建任務將會對代碼執行Lint檢查。Lint是一個靜態代碼分析工具,用于標記布局和Java代碼中的潛在錯誤。在某些情況下,Lint一旦報錯,構建就會停止。如果之前沒有在項目中使用Lint,并且我們想遷移到Gradle,Lint可能會出現很多錯誤。為了使構建工作不會因為Lint檢查而中斷,你可以配置Gradle來忽略Lint錯誤,并通過禁用 abortOnError 來阻止它們中止構建。這只是一個臨時解決方案,因為忽略Lint檢查可能會產生像丟失翻譯類似這樣的潛在錯誤,這可能會導致應用程序崩潰的問題。為了防止Lint阻塞構建過程,可以像下面這樣禁用abortOnError:

android {
       lintOptions {
           abortOnError false
       }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容