一、背景

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\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以下手机上安装测试,可以正常运行。

三、结语

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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

项目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. SqlServer数据库优化之添加主键和自增长

    今天需要给有500万条数据的表添加主键和自增长列,其中最大的难度在于如何UPDATE这500万多条数据,开始吧! 1.先给表添加一个字段叫ID,并允许空 2.查询表,我想到了使用其中的时间列排序来创建 ...

  2. SQL中的视图(极客时间)

    视图 视图也就是虚拟表, 本身不具备数据, 是SQL中的一个变红要概念. 如图 视图可以帮助我们使用表的一部分, 而不是所有的表, 另一方面可以针对不同的用户制定不同的查询视图. 创建, 更新与删除视 ...

  3. EM算法直观认识

    Expectation Maximization, 字面翻译为, "最大期望". 我个人其实一直都不太理解EM算法, 从我个人的渊源来看, 之前数理统计里面的参数估计, 也是没有太 ...

  4. osi7层

  5. 解决IDEA springBoot读取*.properties文件中文内容乱码的问题

    1. 配置 properties 文件 2. 读取 sex 属性输出到页面, 中文乱码 3. file --> settings 4. Editor --> File Encodings ...

  6. URL处理----拼接和编码

    ps:浪了好几周,我的锅... 前几天想爬取一个用户网站自动创建每个用户的资料方便注册一些账号,想写一个通用点的爬虫程序爬取只要配置一些爬取规则.爬取深度就ok,避免代码改动,由于时间关系只完成的个半 ...

  7. python中线程和进程的简单了解

    python中线程和进程的简单了解   一.操作系统.应用程序 1.硬件:硬盘.cpu.主板.显卡........ 2.装系统(本身也是一个软件): 系统就是一个由程序员写出来的软件,该软件用于控制计 ...

  8. 201871010132--张潇潇--《面向对象程序设计(java)》第十二周学习总结

    博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...

  9. linux的cpu使用率

    linux 上一个核占满是 100%,双核机器占满整个 CPU 是 200%

  10. cf1207解题报告

    cf1207解题报告 A 模拟 #include <bits/stdc++.h> #define ll long long using namespace std; ll T,a,b,c, ...