Android Gradle 持續(xù)集成構(gòu)建優(yōu)化

[TOC]

gradle 任務(wù)優(yōu)化

gradle 是基于 tasks 的,每個(gè)task作為一個(gè)構(gòu)建耗時(shí)單元,task就是構(gòu)建優(yōu)化的單元
gradle 編譯優(yōu)化就是對(duì)

  • 構(gòu)建鏈的task組合方式
  • 鏈上節(jié)點(diǎn)task耗時(shí)優(yōu)化
  • 鏈上節(jié)點(diǎn)task性能優(yōu)化

查看任務(wù)

# 查看某個(gè)模塊的任務(wù)
./gradlew :[moduleName]:task
# 等效
./gradlew :[moduleName]:tasks
# 查看所有任務(wù)
./gradlew tasks --all

查看當(dāng)前構(gòu)建耗時(shí)

./gradlew [task] --profile

在工程的根目錄的 build/reports/profile/ 下有最新一次構(gòu)建的耗時(shí)統(tǒng)計(jì)

針對(duì)不同的耗時(shí)問題,可以對(duì)構(gòu)建需要優(yōu)化的 task 進(jìn)行優(yōu)化

輸入獨(dú)立產(chǎn)品線,構(gòu)建類型

gradle :[moduleName]:assemble[產(chǎn)品線][構(gòu)建類型]

./gradlew :app:assembleTestDebug
./gradlew :app:assembleTestRelease

多產(chǎn)品線 productFlavors 使用后,會(huì)明顯加大構(gòu)建時(shí)間,因?yàn)槊總€(gè)產(chǎn)品線是單獨(dú)做 資源依賴調(diào)整,資源依賴檢查,資源依賴合并,編譯,合包,簽名的
故多一條產(chǎn)品線,將多出20%到40%的額外出包時(shí)間

增加構(gòu)建內(nèi)存

  • 內(nèi)存不夠報(bào)錯(cuò)
android studio java.lang.OutOfMemoryError: Java heap space

解決方法 工程根 gradle.properties 加入配置

# JNI編譯支持過時(shí)API
# android.useDeprecatedNdk=true
# 守護(hù)進(jìn)程
# org.gradle.daemon=true
# 按需編譯
# org.gradle.configureondemand=true
org.gradle.parallel=true
# 設(shè)置編譯jvm參數(shù)
org.gradle.jvmargs=-Xmx2048m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# org.gradle.jvmargs=-Xmx5120M -XX:+HeapDumpOnOutOfMemoryError -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=90m

舊方式其實(shí)是無效的,警告如下

Warning:The `android.dexOptions.incremental` property is deprecated and it has no effect on the build process.

原因是在build.gradle加入

  dexOptions {
      incremental true
      javaMaxHeapSize "4g"
  }

這個(gè)配置其實(shí)可以刪除

按需禁用不必要的 task 加速

例如

android {
    buildTypes {
        debug {
            project.gradle.startParameter.excludedTaskNames.addAll([
                    'lint',
                    'check',
            ])
        }
}

意思是在 android 構(gòu)建的debug模式下,禁止 帶有 lint check 的任務(wù)

禁用 Lint 檢查加速構(gòu)建

Android Lint是在ADT16引入的一個(gè)新工具,它能夠掃描到安卓項(xiàng)目中的潛在bug,它既可以作為命令行使用,也可以在eclipse和as等集成環(huán)境中使用

http://tools.android.com/tips/lint

Lint 可以檢查的問題有

  • Missing translations (and unused translations)
  • Layout performance problems (all the issues the old layoutopt tool used to find, and more)
  • Unused resources
  • Inconsistent array sizes (when arrays are defined in multiple configurations)
  • Accessibility and internationalization problems (hardcoded strings, missing contentDescription, etc)
  • Icon problems (like missing densities, duplicate icons, wrong sizes, etc)
  • Usability problems (like not specifying an input type on a text field)
  • Manifest errors

Lint 工具是與集成開發(fā)環(huán)境無關(guān),本身檢查會(huì)比較耗時(shí),可以禁用掉

禁用Lint會(huì)導(dǎo)致一些副作用,比如開發(fā)者寫作垃圾代碼之類

Android 插件下禁用

在需要禁用的子模塊 build.gradle 中添加

android {
    lintOptions {
        abortonError false
    }
}

或者

android {
    lintOptions {
        tasks.lint.enabled = false
    }
}

gradle DSL 方式禁用

工程 根目錄 build.gradle 中添加

task lintCheck() {
    getAllTasks(true).each {
        def lintTasks = it.value.findAll { it.name.contains("lint") }
        lintTasks.each {
            it.enabled = false
        }
    }
}

或者 在需要禁用的子模塊 build.gradleapply plugin: 'com.android.application'之前

beforeEvaluate {
    if (task.name.contains("lint")) {
        task.enabled = false
    }
}

// 這段可能報(bào)錯(cuò),建議用上面的
tasks.whenTaskAdded { task ->
    if (task.name.equals("lint")) {
        task.enabled = false
    }
}

gradke 編譯依賴優(yōu)化

管理依賴配置

在工程根目錄創(chuàng)建文件 package.gradle,內(nèi)容為

subprojects {
    apply plugin: 'maven'
    apply plugin: 'idea'

    ext {
        test_depends = [
                junit                        : 'junit:junit:4.6',
                mockito_core                  : 'org.mockito:mockito-core:2.7.22',
                robolectric                  : 'org.robolectric:robolectric:3.3.2',
                robolectric_shadows_support_v4: 'org.robolectric:shadows-support-v4:3.3.2',
                easymock                      : 'org.easymock:easymock:3.4',
                powermock_core                : 'org.powermock:powermock-core:1.6.5',
                powermock_module_junit4      : 'org.powermock:powermock-module-junit4:1.6.5',
                powermock_api_easymock        : 'org.powermock:powermock-api-easymock:1.6.5',
        ]
        android_test_depends = [
                robotium_solo: 'com.jayway.android.robotium:robotium-solo:5.5.4'
        ]
        apt_compiler = [
                butterknife_compiler: 'com.jakewharton:butterknife-compiler:8.1.0',
        ]
        provided_depends = [
        ]
        depends = [
                com_android_support_support_v4        : 'com.android.support:support-v4:25.0.1',
                com_android_support_appcompat_7        : 'com.android.support:appcompat-v7:25.0.1',
                com_android_support_support_annotations: 'com.android.support:support-annotations:25.0.1',
                com_android_support_recyclerview_v7    : 'com.android.support:recyclerview-v7:25.0.1',
                com_android_support_cardview_v7        : 'com.android.support:cardview-v7:25.0.1',
                com_android_support_design            : 'com.android.support:design:25.0.1',
                com_android_constraint_layout          : 'com.android.support.constraint:constraint-layout:1.0.2',
                butterknife                            : 'com.jakewharton:butterknife:8.1.0',
        ]
        component_depends = [
                recyclerview_helper: 'com.define.android:recyclerview-helper:1.1.1',
                define_dialog      : 'com.define.android:define-dialog:1.1.0',
        ]
        res_provided = [
        ]
        res_depends = [
        ]
    }
}

開發(fā)依賴庫被分為 三級(jí),分別是

  • depends 三方依賴 provided_depends 三方非執(zhí)行依賴
  • component_depends 組件依賴
  • res_depends 資源模塊依賴 res_provided 資源模塊非執(zhí)行依賴

分類的依賴的目的是為了便于管理,語義化依賴結(jié)構(gòu)

工程根目錄的 build.gradle 第一行添加

apply from: rootProject.file("package.gradle")

所有模塊 build.gradle 中就可以使用package.gradle配置的

dependencies {
// implementation fileTree(include: ['*.jar'], dir: 'libs')
    // test start
    testImplementation test_depends.junit,
                test_depends.mockito_core,
                test_depends.robolectric,
                test_depends.robolectric_shadows_support_v4
    androidTestImplementation android_test_depends.robotium_solo
    // test end
    apt apt_compiler.butterknife_compiler
    implementation depends.com_android_support_support_v4,
            depends.com_android_support_appcompat_7,
// implementation.com_android_support_recyclerview_v7,
// implementation.com_android_support_cardview_v7,
// implementation.com_android_support_design,
            depends.butterknife,
            project(':yourMoudle')
    implementation component_depends.recyclerview_helper
}

查詢依賴配置

./gradlew -q :[module]:dependencies  --refresh-dependencies

可以去掉 --refresh-dependencies 強(qiáng)制更新最新依賴

查詢某個(gè)生產(chǎn)線的編譯依賴

這個(gè)需求在 多生產(chǎn)線 productFlavors 構(gòu)建時(shí)特別重要

因?yàn)楫a(chǎn)品線的依賴,是在真實(shí)構(gòu)建合并依賴并輸出的,不是配置什么就依賴什么!

# 查詢輸出模塊 app 下所有的生產(chǎn)線的編譯依賴名稱
./gradlew app:dependencies | grep CompileClasspath
# 查詢輸出模塊 app 下所有的生產(chǎn)線的發(fā)布模式編譯依賴名稱
./gradlew app:dependencies | grep ReleaseCompileClasspath
# 輸出生產(chǎn)線 gray 發(fā)布模式編譯依賴詳情,configuration 后面跟的參數(shù)輸入必須在查詢中存在
./gradlew app:dependencies --configuration grayReleaseCompileClasspath

鎖定依賴提高編譯效率

不要在 gradle 中配置動(dòng)態(tài)版本的依賴,如下這幾種寫法

    implementation group.id.1.+;
    implementation group.id.latest.integration;
    implementation group.id.latest.release;

因?yàn)檫@個(gè)會(huì)大大提高依賴查找的復(fù)雜度,導(dǎo)致gradle在編譯準(zhǔn)備起大量超時(shí),如果是做了生產(chǎn)線分離的項(xiàng)目,耗時(shí)尤其突出

一種解決方案是 去掉所有的動(dòng)態(tài)版本標(biāo)識(shí)
另一種,使用 gradle 在 2.0 以后提供的依賴鎖功能

configurations.all {
    resolutionStrategy {
        force 'group:id:x.x.x'
    }
}

依賴鎖官方文檔

快照版本的依賴更新緩慢

在工程的根下配置,設(shè)置動(dòng)態(tài)版本只在 10min 內(nèi)有效

configurations.all {
  resolutionStrategy {
    // cache dynamic versions for 10 minutes
    cacheDynamicVersionsFor 10*60, 'seconds'
    // don't cache changing modules at all
    cacheChangingModulesFor 10*60, 'seconds'
  }
}

或者,每次包含編譯任務(wù)的task執(zhí)行 --refresh-dependencies

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

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