項目Gradle版本從4.4升級到4.6

1、背景

Gralde版本與AGP(Android Gradle Plugin)版本具備必定的對應關係,緣由在於AGP實質上做爲Gradle的插件,依賴於Gradle做爲宿主。所以,不一樣的AGP版本須要與相應的Gralde版本相匹配。他們之間版本的對應關係以下:java

具體能夠參照官方文檔:
developer.android.com/studio/rele…android

當前項目中使用Gradle版本是4.4,AGP版本是3.1.0。爲遵循漸進式策略,本次升級,目標是將Gralde版本升級到4.6,與之對應的,AGP升級到3.2.1。git

主要考慮點:
1,漸進式升級,只從4.4升級到4.6,兼顧版本升級的同時,確保項目穩定性;
2,升級Gralde及AGP版本,有利於項目構建速度提高;
3,爲不久後的升級到AndroidX作準備。github


2、主要問題及解決

鑑於以往的感覺:每次升級都不只僅是單純的改一下版本號那麼簡單,每次升級也都會遇到一些問題須要處理。
一樣的,這次升級,仍是遇到了一些問題,主要記錄以下:api

2.1 項目自定義插件中的方法簽名問題

1,問題:
修改gradle-wrapper.properties中Gradle版本,從4.4改爲4.6bash

....
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
複製代碼

修改項目根目錄下的build.gradle文件,將AGP從3.1.升級到3.2.1。app

dependencies {
    classpath 'com.android.tools.build:gradle:3.2.1'
    ....
    ....
}
複製代碼

項目構建,發現出現以下錯誤:ide

App:cornProdReleaseMultidexKeep (Thread[Task worker for ':' Thread 4,5,main]) started.
:App:cornProdReleaseMultidexKeep
Caching disabled for task ':App:cornProdReleaseMultidexKeep': Caching has not been enabled for the task
Task ':App:cornProdReleaseMultidexKeep' is not up-to-date because:
  Task has not declared any outputs.
try to update manifest_keep.txt
can't find getManifestKeepListFile method, exception:groovy.lang.MissingMethodException: No signature of method: com.android.build.gradle.internal.scope.VariantScopeImpl.getManifestKeepListFile() is applicable for argument types: () values: [] :App:cornProdReleaseMultidexKeep FAILED :App:cornProdReleaseMultidexKeep (Thread[Task worker for ':' Thread 4,5,main]) completed. Took 0.071 secs. 複製代碼

依據錯誤信息,是執行:App:cornProdReleaseMultidexKeeptask時,有調用到getManifestKeepListFile方法,因AGP版本升級,此處並無作好對應的向歷史兼容,直接報錯。

工具

2,解決:
當前項目分包直接採用Google官方multidex方案。經查,此處是項目團隊自定義的插件,並提供了對外的配置項。目的是仿照tinker寫法,在分包時將對應的maindex配置項經過追加到manifest_keep.txt中,以保留到對應的maindexlist.txt,從而對應的類會被打包到maindex中,5.0如下機型不至於出現ClassNotFoundException相關的錯誤。插件中將對應任務hook到了multidex對應的task環節,至關於完成了額外的maindex配置。開發工具

主體實現邏輯以下:

OptMainDexTask.groovy

@TaskAction
def doAction() {
    def ext = project.extensions.findByName(OptMainDexExtension.NAME) as OptMainDexExtension
    if (!ext.enable) {
        project.logger.error("optMainDex enable set false!")
        return
    }

    project.logger.error("try to update manifest_keep.txt")

    StringBuffer lines = new StringBuffer()
    lines.append("#optMainDex.loader patterns here\n")

    Iterable<String> loader = ext.loader
    for (String pattern : loader) {
        if (pattern.endsWith("*")) {
            if (!pattern.endsWith("**")) {
                pattern += "*"
            }
        }
        lines.append("-keep class " + pattern + " {\n" +
                " <init>(...);\n" +
                "}\n")
                .append("\n")
    }


    File multiDexKeepProguard = null
    try {
        multiDexKeepProguard = applicationVariant.getVariantData().getScope().getManifestKeepListProguardFile()
    } catch (Throwable ignore) {
        try {
            multiDexKeepProguard = applicationVariant.getVariantData().getScope().getManifestKeepListFile()
        } catch (Throwable e) {
            project.logger.error("can't find getManifestKeepListFile method, exception:${e}")
        }
    }
    if (multiDexKeepProguard == null) {
        project.logger.error("auto add multidex keep pattern fail, you can only copy ${file} to your own multiDex keep proguard file yourself.")
        return
    }
    FileWriter manifestWriter = new FileWriter(multiDexKeepProguard, true)
    try {
        for (String line : lines) {
            manifestWriter.write(line)
        }
    } finally {
        manifestWriter.close()
    }
}
複製代碼
cornPlugin.groovy

@Override
void apply(Project project) {
    ...
    initDex(project)
    ...
}

def initDex(Project project) {
    // 只支持Gradle 3.0以上
    project.extensions.create(OptMainDexExtension.NAME, OptMainDexExtension)
    def android = project.extensions.android

    project.afterEvaluate {
        OptMainDexExtension optMainDexExtension = project.extensions.getByName(OptMainDexExtension.NAME)

        if (!optMainDexExtension.enable) {
            return
        }

        android.applicationVariants.all { variant ->
            def variantOutput = variant.outputs.first()
            def variantName = variant.name.capitalize()
            def variantData = variant.variantData
            boolean multiDexEnabled = variantData.variantConfiguration.isMultiDexEnabled()

            if (multiDexEnabled) {
                OptMainDexTask dexConfigTask = project.tasks.create("corn${variantName}MultidexKeep", OptMainDexTask)
                dexConfigTask.applicationVariant = variant

                // for java.io.FileNotFoundException: app/build/intermediates/multi-dex/release/manifest_keep.txt
                // for gradle 3.x gen manifest_keep move to processResources task
                dexConfigTask.mustRunAfter variantOutput.processResources

                def multidexTask = TaskUtil.getMultiDexTask(project, variantName)
                if (multidexTask != null) {
                    multidexTask.dependsOn dexConfigTask
                }
                def collectMultiDexComponentsTask = TaskUtil.getCollectMultiDexComponentsTask(project, variantName)
                if (collectMultiDexComponentsTask != null) {
                    dexConfigTask.mustRunAfter collectMultiDexComponentsTask
                }
            }
        }
    }
}
    
複製代碼

OptMainDexTask中,是仿照以前tinker的寫法,如今tinker的新版本中,此處也已經通過了修改,由於tinker也將AGP版本升級到了3.2.1,並支持了更高版本的使用。

developer.android.com/studio/buil…
參照multidex官方文檔,實際上針對maindex的配置,是不必從插件中繞一道的,直接經過multiDexKeepFilemultiDexKeepProguard在主工程中配置便可。

對應的,刪除項目團隊本身的插件中的maindex此處邏輯,升級插件版本,主工程從新引入,去掉主工程對應的配置,並將須要保留在maindex的配置對應的配置好在multiDexKeepProguard文件中,並引入。

defaultConfig {
    ....
    ....
    multiDexEnabled true
    multiDexKeepProguard file('multidex-config.pro')
    ....
    ....
}
複製代碼

2.2 資源混淆工具AndResGuard異常

1,問題:

從新構建,出現以下錯誤信息:

parse to get the exist names in the resouces.arsc first
com.tencent.mm.androlib.AndrolibException: Could not decode arsc file
at com.tencent.mm.androlib.res.decoder.RawARSCDecoder.decode(RawARSCDecoder.java:74)
at com.tencent.mm.androlib.ApkDecoder.decode(ApkDecoder.java:190)
at com.tencent.mm.resourceproguard.Main.decodeResource(Main.java:96)
....
複製代碼

對應搜索,發現AndResGuard GitHub上也有很多人反饋,如對應issues: github.com/shwenzhang/…


2,解決:

緣由在於升級後,系統默認升級了buildToolsVersion版本到28.0.3。從而致使對資源的解碼出現問題。項目當前buildToolsVersion版本爲27.0.3,直接去除,採用AGP對應的默認buildToolsVersion版本配置。

同時,AndResGuard最新版本已經解決了此問題,直接升級版本到當前最新版本。

....
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.17'
....
複製代碼

再次構建,構建成功。

覈驗maindex分包相關的manifest_keep.txtmaindexlist.txt,與預期相符。在5.0如下手機上安裝測試,能夠正常運行。


3、結語

Gradle升級到4.6,AGP相應升級到3.2.1,主要的更新點:

1,buildToolsVersion開始採起默認版本策略,AGP會按照其自身版本對應配置buildToolsVersion版本,即便因特別須要,人爲也能夠去指定buildToolsVersion版本,但版本範圍仍是須要與AGP版本對應。

2,開始對遷移到AndroidX提供官方的直接支持。Google已經將android.*替換成androidx.*,並將再也不更新維護原來的擴展庫,所以,儘早將項目的擴展庫遷移成AndroidX形式,也是必要的。

3,D8中的Desugaring(脫糖)默認開啓,爲進一步使用Java8提供了支持。

4,新的代碼混淆工具,R8,以取代原有的ProGuard工具,當前默認未開啓,能夠經過配置開啓。

android.enableR8 = true
複製代碼

Andorid項目開發中,涉及到各類版本的概念。項目不斷迭代的同時,官方開發工具、對應配套環境、工具庫、擴展庫等,也在不斷更新。爲持續擁有更好的開發體驗、編譯速度和新功能支持,須要不斷的適時升級相應版本。

相關文章
相關標籤/搜索