一、前言
一个Android项目在不断地迭代之后,项目代码会变多,业务会膨胀,难免会去做一些组件化,插件化这些改造。就那组件化来说,我们需要剥离出各个业务模块,以及基础库,拆成一个个的组件,然后慢慢地因为代码变多,编译会时间变得越来越长,从而影响开发调试的效率。然后我们可能会将组件源码以aar的形式引入,加快编译速度,然而我们在开发调试的时候,使用aar的方式不是很方便,所以需要一个aar和源码之间切换的方案,下面就简单说一下。
二、开始吧
1、没有Maven仓库?
公司客户端可怜,没有自己的Maven仓库,只有一台打包机,之前使用这台机器搭建了Android项目的构建平台,看空间还有富裕,那就继续压榨它吧,再搭个maven仓库吧,简单说下搭建流程吧,我使用docker的方式安装的,docker的使用方式在juejin.cn/post/721920… ,juejin.cn/post/722999…都有提到。
1、拉取maven的镜像
docker pull sonatype/nexus3
镜像有很多,可以通过 docker search nexus 搜一下。
2、创建容器
docker run -d -p 8081:8081--name nexus --restart=always sonatype/nexus3
然后浏览器输入: http://localhost:8081 即可打开了,启动有点慢,所以显示打不开的时候多刷新一下。
打开后默认的登录账号:admin ,密码需要去查看下
find / -name 'admin.password'
根据提示的路径查看
cat xxx
3、创建总库
4、创建存储库
默认不然不能覆盖只能升版本,配置下可覆盖
获取最终的仓库地址,下面需要
5、gradle中配置publish
group "com.example.aar.resource.plugin"
version "1.0.1"
publishing { //当前项目可以发布到本地文件夹中
repositories {
maven {
//maven仓库的地址 上图中有
url = 'http://172.16.10.110:8081/repository/maven_test/'
allowInsecureProtocol = true
credentials {
username 'admin'
password 'qwertyu123'
}
}
}
publications {
// Release 版本发布任务
release(MavenPublication) {
groupId group
artifactId artifactId
version version
artifact("$buildDir/outputs/aar/child-release.aar")
}
// Debug 版本发布任务
debug(MavenPublication) {
groupId group
artifactId artifactId
version version
artifact("$buildDir/outputs/aar/child-debug.aar")
}
}
}
在对应moudle的build.gradle中apply上述groovy即可 (apply from: './publish.gradle')
然后再命令行执行publish命令即可
// debug
./gradlew publishDebugPublicationToMavenRepository
// release
./gradlew publishReleasePublicationToMavenRepository
//一起
./gradlew publish
2、实现方式
配置文件:
{
"libs": [
{
"projectName": "child",
"packageName": "com.example.aar.resource.plugin",
"use_aar": true,
"version": "1.0.1"
}
]
}
方式一 : 傻瓜式判断
//方式一
// 使用根目录的module_switch_config.json 来动态配置依赖库
dependencies {
def switchConfig = getModuleSwitchConfig()
def libs = switchConfig.libs
println(switchConfig)
libs.each { config ->
println(config)
if (config.use_aar) {
println("使用aar")
implementation("$config.packageName:$config.projectName:$config.version")
} else {
implementation project(":$config.projectName")
println("使用本地")
}
}
}
方式二 使用substitute
// 方式二
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
@Override
void beforeEvaluate(Project projectObj) {
}
@Override
void afterEvaluate(Project projectObj, ProjectState state) {
projectObj.configurations.all { config ->
config.resolutionStrategy.dependencySubstitution {
def switchConfig = getModuleSwitchConfig()
def libs = switchConfig.libs
println(switchConfig)
libs.each { lib ->
println(lib)
if (lib.use_aar) {
substitute project(":$lib.projectName") using module("$lib.packageName:$lib.projectName:$lib.version")
println("使用aar")
} else {
substitute module("$lib.packageName:$lib.projectName:$lib.version") using project(":$lib.projectName")
println("使用本地")
}
}
}
}
}
})
在对应app的build.gradle中apply上述groovy即可 (apply from: './../switch_aar.gradle')
关于resolutionStrategy 和 dependencySubstitution
resolutionStrategy
API 中常用的函数和配置选项:
-
failOnVersionConflict()
: 当发生版本冲突时,Gradle 将会停止构建并抛出异常。 -
preferProjectModules()
: 如果存在多个版本的同一库,Gradle 将会选择当前项目中的版本。 -
force(String... moduleIdentifiers)
: 强制使用指定的版本,忽略其他版本。可以传入一个或多个模块标识符,例如'com.google.guava:guava:25.0'
。 -
latestVersion()
: 使用最新版本的库。 -
highestVersion()
: 使用最高版本的库。 -
lowestVersion()
: 使用最低版本的库。 -
strictly(String... moduleIdentifiers)
: 强制使用指定版本,如果找不到则抛出异常。可以传入一个或多个模块标识符,例如'com.google.guava:guava:25.0'
。 -
componentSelection(Action<? super ComponentSelection> action)
: 可以对每个依赖项进行个性化配置,比如排除某个依赖项或强制使用某个版本等。需要传入一个Action
对象,其中的参数ComponentSelection
代表当前依赖项的组件选择信息,您可以在Action
中修改这些信息来实现个性化配置。例如:
dependencies {
// 全局配置依赖解决策略
resolutionStrategy {
failOnVersionConflict()
preferProjectModules()
force 'com.google.guava:guava:25.0'
}
// 单个依赖项指定特定版本
implementation('com.google.guava:guava:28.2-jre') {
force = true
}
// 对每个依赖项进行个性化配置
resolutionStrategy.componentSelection {
if (it.candidate.version == '1.0') {
it.reject('conflict with other dependency')
}
if (it.candidate.groupId == 'com.google.guava' && it.candidate.moduleId == 'guava') {
it.useVersion('25.0')
}
}
}
总之,resolutionStrategy
API 提供了多种选项来指定 Gradle 如何解决构建过程中的依赖冲突,您可以根据实际情况选择合适的选项来保证项目的稳定性和正确性。例如,您可以使用 failOnVersionConflict()
来确保所有依赖项的版本都能够正确匹配,或者使用 preferProjectModules()
来优先使用当前项目中的依赖项。如果您需要强制使用特定版本,可以使用 force()
,如果您需要使用最新版本或者最高/最低版本,可以使用 latestVersion()
、highestVersion()
或者 lowestVersion()
。如果您需要对某个依赖项进行特定的配置,例如排除某个依赖项或者强制使用某个版本,可以使用 componentSelection()
来实现个性化配置。
另外,需要注意的是 resolutionStrategy
中的选项会影响整个项目中的依赖解决策略,因此您需要谨慎使用这些选项,确保它们能够符合您的实际需求。如果您需要对某个依赖项进行特定的配置,建议使用 componentSelection()
来实现个性化配置,这样可以更加灵活地控制依赖项的解决策略。
关于 dependencySubstitution
dependencySubstitution
是 Gradle 构建工具中的一个 API,它可以用于替换依赖项。通过 dependencySubstitution
,您可以将一个依赖项替换为另一个依赖项或者一个本地文件。
下面是 dependencySubstitution
API 中常用的函数:
substitute(moduleNotation: String, target: Dependency)
:将指定依赖项替换为目标依赖项,其中moduleNotation
是要替换的依赖项的模块标识符,例如'com.google.guava:guava:28.2-jre'
;target
是目标依赖项,可以是另一个标准依赖项,也可以是一个本地文件依赖项。substitute(moduleNotation: String, dependencyNotation: String)
:将指定依赖项替换为目标依赖项,其中moduleNotation
是要替换的依赖项的模块标识符,例如'com.google.guava:guava:28.2-jre'
;dependencyNotation
是目标依赖项的依赖标记符,例如'com.google.guava:guava:25.0'
。substitute(moduleNotation: String, file: File)
:将指定依赖项替换为本地文件,其中moduleNotation
是要替换的依赖项的模块标识符,例如'com.google.guava:guava:28.2-jre'
;file
是本地文件对象。substitute(moduleNotation: Pattern, target: Dependency)
:将符合指定模式的依赖项替换为目标依赖项,其中moduleNotation
是一个正则表达式模式,例如~/com.google.guava:.*/
;target
是目标依赖项,可以是另一个标准依赖项,也可以是一个本地文件依赖项。substitute(moduleNotation: Pattern, dependencyNotation: String)
:将符合指定模式的依赖项替换为目标依赖项,其中moduleNotation
是一个正则表达式模式,例如~/com.google.guava:.*/
;dependencyNotation
是目标依赖项的依赖标记符,例如'com.google.guava:guava:25.0'
。substitute(moduleNotation: Pattern, file: File)
:将符合指定模式的依赖项替换为本地文件,其中moduleNotation
是一个正则表达式模式,例如~/com.google.guava:.*/
;file
是本地文件对象。
你可以在 dependencies
块中使用 dependencySubstitution
来全局配置依赖项替换规则,例如:
dependencies {
// 全局配置依赖项替换规则
dependencySubstitution {
substitute(module('com.google.guava:guava'), 'com.google.guava:guava:25.0')
substitute(module('com.example:lib'), files('/path/to/local/lib.jar'))
}
}
总之,dependencySubstitution
可以帮助您实现依赖项的替换,从而满足特定的需求。例如,您可以将某个依赖项替换为本地文件,以实现对某个库的修改或者调试。
三、最后
arr和源码切换的方式有很多,也可以不用substitute,自己定义规则,但最终离不来gradle提供的api,第一种需要在所有的有依赖配置的地方导入上述gradle文件,第二种导入一次就够了,最后安利个好玩链接github.com/xtekky/gpt4… 你懂的,里面有部署好的链接,也可以按照文档自己部署在本地就是有点丑