zoukankan      html  css  js  c++  java
  • 项目Gradle版本从4.4升级到4.6

    一、背景

    Gralde版本与AGP(Android Gradle Plugin)版本具有一定的对应关系,原因在于AGP实质上作为Gradle的插件,依赖于Gradle作为宿主。因此,不同的AGP版本需要与相应的Gralde版本相匹配。他们之间版本的对应关系如下:

    具体可以参照官方文档:
    developer.android.com/studio/rele…

    当前项目中使用Gradle版本是4.4,AGP版本是3.1.0。为遵循渐进式策略,本次升级,目标是将Gralde版本升级到4.6,与之对应的,AGP升级到3.2.1。

    主要考虑点:
    1,渐进式升级,只从4.4升级到4.6,兼顾版本升级的同时,确保项目稳定性;
    2,升级Gralde及AGP版本,有利于项目构建速度提升;
    3,为不久后的升级到AndroidX做准备。


    二、主要问题及解决

    鉴于以往的感受:每次升级都不仅仅是单纯的改一下版本号那么简单,每次升级也都会遇到一些问题需要处理。
    同样的,此次升级,还是遇到了一些问题,主要记录如下:

    2.1 项目自定义插件中的方法签名问题

    1,问题:
    修改gradle-wrapper.properties中Gradle版本,从4.4改成4.6

    ....
    distributionUrl=https://services.gradle.org/distributions/gradle-4.6-all.zip
    复制代码

    修改项目根目录下的build.gradle文件,将AGP从3.1.升级到3.2.1。

    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        ....
        ....
    }
    复制代码

    项目构建,发现出现如下错误:

    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
    ")
    
        Iterable<String> loader = ext.loader
        for (String pattern : loader) {
            if (pattern.endsWith("*")) {
                if (!pattern.endsWith("**")) {
                    pattern += "*"
                }
            }
            lines.append("-keep class " + pattern + " {
    " +
                    "    <init>(...);
    " +
                    "}
    ")
                    .append("
    ")
        }
    
    
        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以下手机上安装测试,可以正常运行。


    三、结语

    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项目开发中,涉及到各种版本的概念。项目不断迭代的同时,官方开发工具、对应配套环境、工具库、扩展库等,也在不断更新。为持续拥有更好的开发体验、编译速度和新功能支持,需要不断的适时升级相应版本。


    作者:HappyCorn
    链接:https://juejin.im/post/5d6510796fb9a06b2e3d02c8
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    JDBC批量删除某一用户下的触发器
    DWZ框架修改默认主页(转)
    JSP页面中的js方法遍历后台传来的自定义对象的List
    JDBC获取表注释
    你的显示方式安全么?JSTL中c:out标签介绍
    tomcat启动报错
    PPP协议体系的实现
    Linux下的虚拟Bridge实现
    三皇五帝
    贴近原理层的科技发展
  • 原文地址:https://www.cnblogs.com/lwbqqyumidi/p/11991779.html
Copyright © 2011-2022 走看看