自动检测ARouter路由地址分组使用冲突问题
背景
项目中使用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路由地址分组使用冲突问题的更多相关文章
- JavaScript实现http地址自动检测并添加URL链接
一.天生我材必有用 给http字符自动添加URL链接是比较常见的一项功能.举两个我最近常用到的自动检测http://地址并添加链接的例子吧,首先是QQ邮箱,在使用QQ邮箱时,如果输入了URL地址(ht ...
- 【转载】Windows检测到IP地址冲突
今天在使用电脑的过程中,突然弹出个提示,Windows检测到IP地址冲突,此网络中的另一台计算机与该计算机的IP地址相同.联系你的网络管理员解决此问题,有关详细信息,请参阅Windows系统日志.查阅 ...
- ARouter 路由 组件 跳转 MD
目录 简介 支持的功能 典型应用 简单使用 进阶使用 更多功能 其他 Q&A Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs bai ...
- 使用阿里ARouter路由实现组件化(模块化)开发流程
Android平台中对页面.服务提供路由功能的中间件,我的目标是 —— 简单且够用. 这是阿里对Arouter的定位,那么我们一起来梳理一下Arouter使用流程,和使用中我所遇到的一些问题! 先来看 ...
- paip.提高稳定性---自动检测sleep mysql数据库死连接以及kill
paip.提高稳定性---自动检测sleep mysql数据库死连接以及kill 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:ht ...
- IOS开发中如何实现自动检测更新APP
自动检测更新实现逻辑: 先上github地址:https://github.com/wolfhous/HSUpdateApp 1,获取当前项目APP版本号 2,拿到AppStore项目版本号 3,对比 ...
- 打造一个自动检测页面是否存在XSS的小插件
前言: 还记得刚玩Web安全时,就想着要是能有一个自动挖掘XSS漏洞的软件就好了.然后我发现了Safe3.JSky.AWVS.Netsparker等等,但是误报太多,而且特别占内存.后来发现了fidd ...
- iOS内存泄漏自动检测工具PLeakSniffer
新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer). 背景 前些天读 ...
- vue + element-ui 制作下拉菜单(可配置路由、可根据路由高亮list、可刷新自动展开定位路由)
本篇文章分享一篇关于 vue制作可路由切换组件.可刷新根据路由定位导航(自动展开).可根据路由高亮对应导航选项 一.实现的功能如下: 1.可折叠导航面板 2.点击导航路由不同组件 ...
随机推荐
- Servlet的生命周期以及线程安全问题
一:Servlet生命周期图,以及注意事项 二:代码演示 LifeCycleServlet.java package cn.woo.servlet; import java.io.IOExceptio ...
- localstorage本地存储的应用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- windows下 php集成环境如何通过cmd执行命令
---恢复内容开始--- php学习过程中 Windows环境下的php集成程序很多 这样方便了学习 但是在熟悉命令使用方面可以说是十分不便 本文将从两个方便 向大家介绍如何快速通过cmd命令实现命令 ...
- apply()技巧
apply技巧: 可以将数组的每一项分别作为参数传入函数. var value = [3,6,34,90]; alert(Math.max.apply(Math,value)); 这个技巧的关 ...
- windows phone 8.0 的网络图片异步加载方案
买了一本林政的8.1UI的书,看到一个使用弱引用对像来解决图片缓存的问题,刚好自已写的应用也遇到这个问题,于是小改动了一下代码,搬到了8.0版本来使用,代码由 zhxilin℃+ 大神提供了部分解决代 ...
- java基础——类加载与反射
第1章 类加载器 1.1 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. (1)加载 就是指将class文件读入内存,并为之创 ...
- Java实现随机出题,10道10以内加减法计算
package com.swift; import java.awt.Toolkit; import java.util.Scanner; public class PlusQuiz { public ...
- MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别
DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...
- Vue源码学习一 ———— Vue项目目录
Vue 目录结构 可以在 github 上通过这款 Chrome 插件 octotree 查看Vue的文件目录.也可以克隆到本地.. Vue 是如何规划目录的 scripts ------------ ...
- ZRDay6A. 萌新拆塔(三进制状压dp)
题意 Sol 这好像是我第一次接触三进制状压 首先,每次打完怪之后吃宝石不一定是最优的,因为有模仿怪的存在,可能你吃完宝石和他打就GG了.. 因此我们需要维护的状态有三个 0:没打 1:打了怪物 没吃 ...