一、背景

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

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

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

  1. dependencies {
  2. classpath 'com.android.tools.build:gradle:3.2.1'
  3. ....
  4. ....
  5. }
  6. 复制代码

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

  1. App:cornProdReleaseMultidexKeep (Thread[Task worker for ':' Thread 4,5,main]) started.
  2. :App:cornProdReleaseMultidexKeep
  3. Caching disabled for task ':App:cornProdReleaseMultidexKeep': Caching has not been enabled for the task
  4. Task ':App:cornProdReleaseMultidexKeep' is not up-to-date because:
  5. Task has not declared any outputs.
  6. try to update manifest_keep.txt
  7. 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: []
  8. :App:cornProdReleaseMultidexKeep FAILED
  9. :App:cornProdReleaseMultidexKeep (Thread[Task worker for ':' Thread 4,5,main]) completed. Took 0.071 secs.
  10. 复制代码

依据错误信息,是执行:App:cornProdReleaseMultidexKeeptask时,有调用到getManifestKeepListFile方法,因AGP版本升级,此处并没有做好对应的向历史兼容,直接报错。

2,解决:
当前项目分包直接采用Google官方multidex方案。经查,此处是项目团队自定义的插件,并提供了对外的配置项。目的是仿照tinker写法,在分包时将对应的maindex配置项通过追加到manifest_keep.txt中,以保留到对应的maindexlist.txt,从而对应的类会被打包到maindex中,5.0以下机型不至于出现ClassNotFoundException相关的错误。插件中将对应任务hook到了multidex对应的task环节,相当于完成了额外的maindex配置。

主体实现逻辑如下:

  1. OptMainDexTask.groovy
  2. @TaskAction
  3. def doAction() {
  4. def ext = project.extensions.findByName(OptMainDexExtension.NAME) as OptMainDexExtension
  5. if (!ext.enable) {
  6. project.logger.error("optMainDex enable set false!")
  7. return
  8. }
  9. project.logger.error("try to update manifest_keep.txt")
  10. StringBuffer lines = new StringBuffer()
  11. lines.append("#optMainDex.loader patterns here\n")
  12. Iterable<String> loader = ext.loader
  13. for (String pattern : loader) {
  14. if (pattern.endsWith("*")) {
  15. if (!pattern.endsWith("**")) {
  16. pattern += "*"
  17. }
  18. }
  19. lines.append("-keep class " + pattern + " {\n" +
  20. " <init>(...);\n" +
  21. "}\n")
  22. .append("\n")
  23. }
  24. File multiDexKeepProguard = null
  25. try {
  26. multiDexKeepProguard = applicationVariant.getVariantData().getScope().getManifestKeepListProguardFile()
  27. } catch (Throwable ignore) {
  28. try {
  29. multiDexKeepProguard = applicationVariant.getVariantData().getScope().getManifestKeepListFile()
  30. } catch (Throwable e) {
  31. project.logger.error("can't find getManifestKeepListFile method, exception:${e}")
  32. }
  33. }
  34. if (multiDexKeepProguard == null) {
  35. project.logger.error("auto add multidex keep pattern fail, you can only copy ${file} to your own multiDex keep proguard file yourself.")
  36. return
  37. }
  38. FileWriter manifestWriter = new FileWriter(multiDexKeepProguard, true)
  39. try {
  40. for (String line : lines) {
  41. manifestWriter.write(line)
  42. }
  43. } finally {
  44. manifestWriter.close()
  45. }
  46. }
  47. 复制代码
  1. cornPlugin.groovy
  2. @Override
  3. void apply(Project project) {
  4. ...
  5. initDex(project)
  6. ...
  7. }
  8. def initDex(Project project) {
  9. // 只支持Gradle 3.0以上
  10. project.extensions.create(OptMainDexExtension.NAME, OptMainDexExtension)
  11. def android = project.extensions.android
  12. project.afterEvaluate {
  13. OptMainDexExtension optMainDexExtension = project.extensions.getByName(OptMainDexExtension.NAME)
  14. if (!optMainDexExtension.enable) {
  15. return
  16. }
  17. android.applicationVariants.all { variant ->
  18. def variantOutput = variant.outputs.first()
  19. def variantName = variant.name.capitalize()
  20. def variantData = variant.variantData
  21. boolean multiDexEnabled = variantData.variantConfiguration.isMultiDexEnabled()
  22. if (multiDexEnabled) {
  23. OptMainDexTask dexConfigTask = project.tasks.create("corn${variantName}MultidexKeep", OptMainDexTask)
  24. dexConfigTask.applicationVariant = variant
  25. // for java.io.FileNotFoundException: app/build/intermediates/multi-dex/release/manifest_keep.txt
  26. // for gradle 3.x gen manifest_keep move to processResources task
  27. dexConfigTask.mustRunAfter variantOutput.processResources
  28. def multidexTask = TaskUtil.getMultiDexTask(project, variantName)
  29. if (multidexTask != null) {
  30. multidexTask.dependsOn dexConfigTask
  31. }
  32. def collectMultiDexComponentsTask = TaskUtil.getCollectMultiDexComponentsTask(project, variantName)
  33. if (collectMultiDexComponentsTask != null) {
  34. dexConfigTask.mustRunAfter collectMultiDexComponentsTask
  35. }
  36. }
  37. }
  38. }
  39. }
  40. 复制代码

OptMainDexTask中,是仿照之前tinker的写法,现在tinker的新版本中,此处也已经经过了修改,因为tinker也将AGP版本升级到了3.2.1,并支持了更高版本的使用。

developer.android.com/studio/buil…
参照multidex官方文档,实际上针对maindex的配置,是没必要从插件中绕一道的,直接通过multiDexKeepFilemultiDexKeepProguard在主工程中配置即可。

对应的,删除项目团队自己的插件中的maindex此处逻辑,升级插件版本,主工程重新引入,去掉主工程对应的配置,并将需要保留在maindex的配置对应的配置好在multiDexKeepProguard文件中,并引入。

  1. defaultConfig {
  2. ....
  3. ....
  4. multiDexEnabled true
  5. multiDexKeepProguard file('multidex-config.pro')
  6. ....
  7. ....
  8. }
  9. 复制代码

2.2 资源混淆工具AndResGuard异常

1,问题:

重新构建,出现如下错误信息:

  1. parse to get the exist names in the resouces.arsc first
  2. com.tencent.mm.androlib.AndrolibException: Could not decode arsc file
  3. at com.tencent.mm.androlib.res.decoder.RawARSCDecoder.decode(RawARSCDecoder.java:74)
  4. at com.tencent.mm.androlib.ApkDecoder.decode(ApkDecoder.java:190)
  5. at com.tencent.mm.resourceproguard.Main.decodeResource(Main.java:96)
  6. ....
  7. 复制代码

对应搜索,发现AndResGuard GitHub上也有不少人反馈,如对应issues: github.com/shwenzhang/…

2,解决:

原因在于升级后,系统默认升级了buildToolsVersion版本到28.0.3。从而导致对资源的解码出现问题。项目当前buildToolsVersion版本为27.0.3,直接去除,采用AGP对应的默认buildToolsVersion版本配置。

同时,AndResGuard最新版本已经解决了此问题,直接升级版本到当前最新版本。

  1. ....
  2. classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.17'
  3. ....
  4. 复制代码

再次构建,构建成功。

核验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工具,当前默认未开启,可以通过配置开启。

  1. android.enableR8 = true
  2. 复制代码

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

作者:HappyCorn
链接:https://juejin.im/post/5d6510796fb9a06b2e3d02c8
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

项目Gradle版本从4.4升级到4.6的更多相关文章

  1. 关于很怂地退回SDK,ndk,gradle版本这件事。。。(降版本fix项目异常)

    前言:说明一下,这篇文章对别人应该是没什么用的,单作为自己的记录吧,方便以后查询 电脑重装后没有再使用之前的studio2.3,而是直接下载了最新版的v3.1.2,同时升级了所有SDK(28),NDK ...

  2. 【Android Studio安装部署系列】二十四、Android studio中Gradle插件版本和Gradle版本关系

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 在从Android Studio3.0.0版本升级到Android Studio3.0.1版本的时候,出现了一个问题,需要升级Gra ...

  3. Gradle版本变更的问题

    了解相关三个概念 gradle .gradle wrapper . gradle plugin (1)Gradle  :  项目的构建工具,管理一个项目的依赖架包.性质和maven相似. (2)Gra ...

  4. RAD 版本迁移工具,不怕升级麻烦了。

    RAD 版本迁移工具,不怕升级麻烦了. http://community.embarcadero.com/blogs?view=entry&id=8865 migrationtool.exe ...

  5. AndroidStudio Gradle版本不匹配问题

    报错信息: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } Error:(1, 1) A problem occurr ...

  6. 大型项目 Gradle 的常用库和版本管理[转]

    http://www.tuicool.com/articles/vqQZBrm 大型项目 Gradle 的常用库和版本管理 时间 2016-03-15 06:44:00  Mystra 原文  htt ...

  7. 【Android 应用开发】 Android 各种版本简介 ( Support 支持库版本 | Android Studio 版本 | Gradle 版本 | jcenter 库版本 )

    初学者遇到 Android Studio, 导入工程后, 会出现各种奇葩错误, 如果管理好各个插件, gradle, SDK, SDK Tools, 各种官方依赖库 的版本, 会将错误大大的减少; 这 ...

  8. Android Studio之回退Gradle版本方法

    Android Studio之回退Gradle版本方法 (Minimum supported Gradle version is 4.10.1. Current version is 4.6.)   ...

  9. Android Studio中由于gradle插件版本和gradle版本对应关系导致的编译失败的问题

    今天在Android Studio中导入新项目,import之后编译报错,报错信息基本都是和版本相关,查询gradle版本相关知识,了解到gradle插件版本和gradle版本有相应的匹配关系,对应如 ...

随机推荐

  1. 洛谷 p1008三连击

    洛谷 p1008三连击 题目背景 本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序. 题目描述 将1,2, ⋯,9共99个数分成3组,分别组成3个三位数, ...

  2. 拥抱小程序,WeTest小程序全链路测试解决方案正式上线

    背景 随着微信开放小程序开发功能,迅速在各个实体店抢占流量入口,广大商家看到了在线和离线的机会整合,利用小程序版本特点低成本进入市场,达到流量的获取和转化. 伴随着资本的进入,小程序开发市场也因此越来 ...

  3. redis笔记3

    redis持久化机制 redis提供了两种持久化策略 RDB RDB的持久化策略: 按照规则定时将内存的数据同步到磁盘 snapshot redis在指定的情况下会触发快照 自己配置的快照规则 sav ...

  4. JS初始

      简单只和复杂值的区别 1.简单值 简单值表示JS中可用的数据或信息的最底层简单形式. 注:简单之不可被细化. 也就是说,数字是数字,字符是字符,布尔值是true或false,null和undefi ...

  5. 英文DIAMAUND钻石DIAMAUND词汇

    首先谈谈钻石和金刚石的名称.金刚石是一种天然矿物,是钻石的原石.习惯上人们常将加工过的金刚石称为钻石,而未加工过的称为金刚石(当然,有的金刚石不用加工便可应用).钻石是那些达到宝石级别的金刚石晶体切磨 ...

  6. 解决jmeter进行分布式测试,远程机器来运行脚本,在察看结果树中的响应数据项为空白

    下面为大家提供一个解决办法: 第一步:打开主控机的jmeter--bin目录下的jmeter.properties文件 第二步:查找到mode=Standard 项 第三步:将其前边的注释去掉,然后保 ...

  7. Rust自定义智能指针

    深了,真深了. use std::ops::Deref; struct MyBox<T>(T); impl<T> MyBox<T> { fn new(x: T) - ...

  8. JS高阶---作用域与执行上下文

    一句话介绍 .

  9. 201871010134-周英杰《面想对象程序设计(java)》第十一周学习总结

    项目 内容 <面向对象程序设计(java)> https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/ ...

  10. Vs2012安装介绍

    1.下载Vs2012旗舰版安装文件 http://download.microsoft.com/download/B/0/F/B0F589ED-F1B7-478C-849A-02C8395D0995/ ...