背景

项目中使用ARouter进行路由,由于不同上层业务模块都可能会使用到同一目标的路由地址,因此,将所有业务模块的路由地址以一种类似静态常量的方式设置在Base模块中。这样,在实际目前上加上对应此地址的注解,就可以将其对应加入到路由中。使用方通过ARouter对应的地址方式去路由,即可访问到对应的目标。

以Activity路由为例,通过注解,编译后在对应模块路径下生成的文件名为Arouter$$Group$$GroupName1.java文件。其中GroupName1为分组名。 具体路径为:

/build/generated/source/kapt/变体/com/alibaba/android/arouter/routes/
复制代码

原则上,不同模块应该注解到不同的路由地址分组。否则不同的模块下编译后会生成相同的Arouter$$Group$$GroupName1.java文件,在项目构建安装后,会发生不可预期的路由地址失败问题(如其中一个Arouter$$Group$$GroupName1.java文件中的路由生效,另一个直接路由失败)。

网上查了下,发现同样问题,其他人也有遇到,具体问题描述GitHub上ARouter项目中issues等: github.com/alibaba/ARo…
github.com/alibaba/ARo…
github.com/alibaba/ARo…

近期,项目中在进行模块化改进时,由于部分注解了路由地址的目标文件被从一个模块移动到另一个模块,导入出现同样问题发。原因在于,如果直接通过Android Studio中的三角形绿色图标直接run android app时,对于不同模块下生成的同名java文件在编译及打包组装过程中是不会提示如下信息的:

* What went wrong:
Execution failed for task ':app:transformClassesWithJarMergingForDevDebug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/alibaba/android/arouter/routes/ARouter$$Group$$trans_second.class
复制代码

但如果直接通过./gradlew命令方式构建,是可以直接出现如上错误提示的。大多数情况下,项目开发中直接通过run构建,使得此问题直接被隐藏。

分析与解决

对比两者实际上构建流程上的差异,发现通过./gradlew命令方式构建,在执行taskapp:transformClassesWithJarMergingForDevDebug时会抛出duplicate entry class错误,但Android Studio直接run则没有执行。

为了兼容Android Studio直接run形式,在开发人员开发阶段早些发现此类问题,可以自己实现一个task,加入到构建过程中的适当阶段,以自动检测在不同模块下ARouter生成的文件重复问题。

具体思路:
分别统计项目中各个模块中ARouter生成的java文件,并计次数(需要区分构建类型,一个构建类型算唯一的一次即可,否则对于多个变体情况下会重复计算),对于同一构建类型,同样的文件名,生成的文件次数多余1,显然应该直接构建失败,并给出具体提示。

实现:
1,首先自定义task,实现次数检测和统计:

task checkARouterDuplicatedJavaFiles {
doLast {
def fileMap = [:]
def buildTypeList = []
def hasPathBuildTypeList = [] project.extensions.findByName("android").applicationVariants.all { variant ->
def buildTypeName = variant.buildType.name
if(!buildTypeList.contains(buildTypeName)) {
buildTypeList.add(buildTypeName)
}
} project.rootProject.subprojects { subProject ->
def subProjectBuildDir try {
subProjectBuildDir = subProject.buildDir if (subProjectBuildDir == null) return subProjectBuildDir.eachFileRecurse(FileType.DIRECTORIES) { dir ->
if (dir.path.contains("/generated/source/kapt/") && dir.path.endsWith("com/alibaba/android/arouter/routes")) {
def filePrefix = ""
for (buildType in buildTypeList) {
if(dir.path.toLowerCase().contains(buildType + "/")
&& !hasPathBuildTypeList.contains(subProject.getName() + "/generated/source/kapt/" + buildType + "/")){ filePrefix = buildType + "/"
dir.eachFile(FileType.FILES) { file ->
if (fileMap[filePrefix + file.name] == null) {
fileMap[filePrefix + file.name] = 0
}
fileMap[filePrefix + file.name]++
} hasPathBuildTypeList.add(subProject.getName() + "/generated/source/kapt/" + filePrefix)
return
}
}
}
}
} catch (Exception e) {
// ignore
println e.toString()
}
} fileMap.each { key, value ->
if (value > 1) {
throw new GradleException("ARouter: " + key + " fileCount: " + value + " ,路由地址设置有误!")
}
}
}
}
复制代码

上述代码中的hasPathBuildTypeList逻辑是因为app module中的变体与library module中的变体设置不一样,以处理对应的兼容逻辑。

2,将此task加入到构建流程的适当阶段。通过对比实际的构建过程中执行的task列表,最终决定将名称为“assembleDevDebug”的task依赖自定义的checkARouterDuplicatedJavaFilestask,并将自定义的task依赖名称为“transformClassesWithCom.alibaba.arouterForDevDebug”的task。 具体实现为:

project.tasks.whenTaskAdded { Task task ->
if (task.name == "assembleDevDebug") {
task.dependsOn(checkARouterDuplicatedJavaFiles)
} else if (task.name == "transformClassesWithCom.alibaba.arouterForDevDebug") {
checkARouterDuplicatedJavaFiles.dependsOn(task)
}
}
复制代码

其中,DevDebug为我们开发环境下默认的构建变体。

最终可以确保自定义的checkARouterDuplicatedJavaFilestask可以在构建过程中完成对应的检测。 如果通过./gradlew命令构建,依然可以达到以系统taskapp:transformClassesWithJarMergingForDevDebug为先。

通过Android Studio run,如果重现此类情形,最终效果为:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:checkARouterDuplicatedJavaFiles'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
...
at java.lang.Thread.run(Thread.java:745)
Caused by: org.gradle.api.GradleException: ARouter: release/ARouter$$Group$$GroupName1.java fileCount: 2 ,路由地址设置有误!
at build_4p6esrqwzg61igroldd1aht2w$_run_closure5$_closure42.doCall(/Users/corn/AndroidStudioProjects/MyCorn/app/build.gradle:395)
... 复制代码

构建失败,并给出提示。

结语

ARouter官方建议在不同的模块下本就不应该使用同样的分组,分组名可以使用模块名或其他名称,但分组名与模块本质上是一种映射关系,无论如何设置,考虑到其他模块需要使用到此路由地址,当这种映射关系与模块化相结合时,这一可能存在冲突的矛盾直接在分组名的定义上,通过技术手段是无法直接完全隔离开的。因此,考虑通过自定义task并加入到构建过程中的适当阶段,以自动检测潜在的可能的人为失误,是一种有效方案。

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

自动检测ARouter路由地址分组使用冲突问题的更多相关文章

  1. JavaScript实现http地址自动检测并添加URL链接

    一.天生我材必有用 给http字符自动添加URL链接是比较常见的一项功能.举两个我最近常用到的自动检测http://地址并添加链接的例子吧,首先是QQ邮箱,在使用QQ邮箱时,如果输入了URL地址(ht ...

  2. 【转载】Windows检测到IP地址冲突

    今天在使用电脑的过程中,突然弹出个提示,Windows检测到IP地址冲突,此网络中的另一台计算机与该计算机的IP地址相同.联系你的网络管理员解决此问题,有关详细信息,请参阅Windows系统日志.查阅 ...

  3. ARouter 路由 组件 跳转 MD

    目录 简介 支持的功能 典型应用 简单使用 进阶使用 更多功能 其他 Q&A Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs bai ...

  4. 使用阿里ARouter路由实现组件化(模块化)开发流程

    Android平台中对页面.服务提供路由功能的中间件,我的目标是 —— 简单且够用. 这是阿里对Arouter的定位,那么我们一起来梳理一下Arouter使用流程,和使用中我所遇到的一些问题! 先来看 ...

  5. paip.提高稳定性---自动检测sleep mysql数据库死连接以及kill

    paip.提高稳定性---自动检测sleep mysql数据库死连接以及kill 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:ht ...

  6. IOS开发中如何实现自动检测更新APP

    自动检测更新实现逻辑: 先上github地址:https://github.com/wolfhous/HSUpdateApp 1,获取当前项目APP版本号 2,拿到AppStore项目版本号 3,对比 ...

  7. 打造一个自动检测页面是否存在XSS的小插件

    前言: 还记得刚玩Web安全时,就想着要是能有一个自动挖掘XSS漏洞的软件就好了.然后我发现了Safe3.JSky.AWVS.Netsparker等等,但是误报太多,而且特别占内存.后来发现了fidd ...

  8. iOS内存泄漏自动检测工具PLeakSniffer

    新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer). 背景 前些天读 ...

  9. vue + element-ui 制作下拉菜单(可配置路由、可根据路由高亮list、可刷新自动展开定位路由)

    本篇文章分享一篇关于 vue制作可路由切换组件.可刷新根据路由定位导航(自动展开).可根据路由高亮对应导航选项 一.实现的功能如下: 1.可折叠导航面板 2.点击导航路由不同组件           ...

随机推荐

  1. pat甲级1139

    1139 First Contact(30 分) Unlike in nowadays, the way that boys and girls expressing their feelings o ...

  2. Django Form 表单

    Form 表单功能 生成HTML表单元素检查表单元素的合法性验证如果错误,重复显示表单数据类型转换 Form相关的对象 Widget 渲染成HTML元素的工具Field Form对象中的一个字段For ...

  3. 【洛谷1110】[ZJOI2007] 报表统计(两棵平衡树)

    点此看题面 大致题意: 有一个序列,三种操作.\(INSERT\)操作是在原数列第\(i+1\)个元素之前插入一个新元素\(k\),\(MIN\)\(GAP\)操作是查询相邻两个元素的之间差值的最小值 ...

  4. 动态规划专题(一)——状压DP

    前言 最近,决定好好恶补一下我最不擅长的\(DP\). 动态规划的种类还是很多的,我就从 状压\(DP\) 开始讲起吧. 简介 状压\(DP\)应该是一个比较玄学的东西. 由于它的时间复杂度是指数级的 ...

  5. 【ML】聊天机器人

    继做过了泰语分词,自动对对对联后对聊天机器人产生了浓厚的兴趣.ChatBot集合了NLP,DL等多领域的应用. https://deeppavlov.ai/ https://www.rasa.com/ ...

  6. 注册Windows service及其相关

    注册Windows service,.net写的 net stop "xxxxxx""%SYSTEMROOT%\Microsoft.NET\Framework\v2.0. ...

  7. python_72_json序列化2

    #序列化(json是最正规的) import json info={ 'name':'Xue Jingjie', 'age':22 } f=open('第72.text','w') print(jso ...

  8. 【luogu P3608 [USACO17JAN]Balanced Photo平衡的照片】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3608 乍一看很容易想到O(N^2)的暴力. 对于每个H[i]从i~i-1找L[i]再从i+1~n找R[i], ...

  9. 分享12款最佳的Bootstrap设计工具

    设计师总会渴望有一些新奇有趣的设计工具来提高工作效率,而Bootstrap就是您的不二选择.2013年Bootstrap得到了广泛普及, 它是开发者较为常用的框架之一,本文我们将分享12款最佳的Boo ...

  10. Ubuntu解决winscp连接不上虚拟机问题

    前几天在配置虚拟机的时候,尝试用winscp连接Ubuntu,结果连接被拒绝.原因:Ubuntu的ssh服务需要自己安装和启动,在没启动之前,是无法连接上去的 解决方案: 我们可以输入:ssh loc ...