【Gradle KTS】一次发布 Android SDK 到 maven 仓库的经验总结
作者:访客发布时间:2023-12-28分类:程序开发学习浏览:97
前言
近期接到需求,将此前一个项目的部分功能封装成 SDK
对外提供,我在 SDK
开发方面没有经验,借着这个需求,了解了 SDK
开发的一些技巧,也爬了很多的坑,梳理出这篇文章,把一些经验分享给大家。
如有不足或者谬误,还请各位同行大哥们多多指教。
jar VS aar
jar 包
jar(Java ARchive)
是 java
归档文件,对于我们 Android
开发来说,通俗的理解就是这是一个单纯提供业务能力的 SDK
,只有 class
文件与清单文件,不涉及任何的页面,不包含资源文件。
aar 包
aar(Android ARchive)
同理,是 Android
归档文件,也就是除了 class
文件和清单文件之外,还会包含一些 Android
页面,资源文件,SDK
本身就具备 UI
交互能力。
我这次接到的需求就是包含 UI
交互的封装,因此本文后续都将围绕 aar
展开内容。
构建并产出 aar
包
这一部分我不做详细阐述,因为类似的文章很容易检索到,我也会在文末贴一些相关的文章链接
创建 library module
我看有些文章,是把 application
项目改成 libaray
,我个人的情况还是提取封装部分功能,所以这里还是演示新建 libaray
1. File
--> New
--> New Module
2. 配置自己的项目参数
3. 顺带提一下 application
和 library
的 gradle
配置区别
-
插件从
com.android.application
变成了com.android.library
-
library
模块不需要,也不应该配置applicationId
,targetSdk
,versionCode
,versionName
产出 aar
包
产出的方式有很多,这里提供常见的 2 种
1. gradlew
命令产出(我喜欢用的)
./gradlew :SdkDemo:assembleRelease
# 如果你配置了 variant,不确定具体的产出命令,也可以先使用 tasks 命令查看所有命令,从中找到你需要的
./gradlew :SdkDemo:tasks
这里命令中的 SdkDemo
对应着我的 module
名称,具体到你的项目中,换成你的即可,下文同理。
2. AS
自带的 gradle
插件产出
最终 aar
包体都会产出在 SdkDemo/build/outputs/aar/
路径下
发布 aar
包
通常情况下,此时直接产出 aar
包输出使用的话,大概率会报找不到类的异常,原因很简单:打包时没有包含使用的依赖,或者宿主项目中没有所需要的依赖。基于上述的原因也会有两种不同的解决方案:
将依赖打进 aar
包后再发布
我们平时使用的依赖,很多也是以 aar
包的形式从远端仓库,下载到我们本地,然后再参与遇到编译流程中去的。
那将依赖打进 aar
其实也就是将多个 aar
合并成一个,这种方式,Google 目前默认是不是支持的,需要使用第三方的 gradle
插件来实现
fat-aar-android
这个插件做的事情简单来说就是把多个 aar
包解包,然后合并诸如 Manifest
,res 资源
,R 文件
,assets
,libs
,jni
等各类文件,其中合并 R文件
是最重要的一步。
1. 添加 fat-aar
插件
在 project
的 build.gradle.kts
添加 fat-aar
插件
buildscript {
dependencies {
···
classpath("com.github.kezong:fat-aar:1.3.8")
// 本插件作者已停更,如果你和我一样使用 agp 8.0 及之后版本,可使用其他贡献者适配的版本
// classpath("com.github.aasitnikov:fat-aar-android:ce932b38ef")
}
}
在 SDKDemo
module 的 build.gradle.kts
(本节后文同) 添加 fat-aar
插件
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
id("maven-publish")
}
2. Embed dependencies
embed
你所需要合并打入的依赖, 用法类似 implementation
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to "*.jar")))
// java dependency
embed(project(path = ":lib-java", configuration = "default"))
// aar dependency
embed(project(path = ":lib-aar", configuration = "default"))
// aar dependency
embed(project(path = ":lib-aar2", configuration = "default"))
// local full aar dependency, just build in flavor1
flavor1Embed(project(path = ":lib-aar-local", configuration = "default"))
// local full aar dependency, just build in debug
debugEmbed(mapOf("name" to "lib-aar-local2", "ext" to "aar"))
// remote jar dependency
embed("com.google.guava:guava:20.0")
// remote aar dependency
embed("com.facebook.fresco:fresco:1.12.0")
// don't want to embed in
implementation("androidx.appcompat:appcompat:1.2.0")
}
3. 执行 assemble
命令
# assemble all
./gradlew :SDKDemo:assemble
最终合并产物会覆盖原有aar,同时路径会打印在log信息中.
4. 多级传递
本地依赖
如果你想将本地所有相关的依赖项全部包含在最终产物中,你需要在你主library中对所有依赖都加上embed
关键字
比如,mainLib依赖lib1,lib1依赖lib2,如果你想将所有依赖都打入最终产物,你必须在mainLib的build.gradle
中对lib1以及lib2都加上embed
关键字
远程依赖
如果你想将所有远程依赖在pom中声明的依赖项同时打入在最终产物里的话,你需要在build.gradle
中将transitive值改为true,例如:
fataar {
/**
* If transitive is true, local jar module and remote library's dependencies will be embed.
* If transitive is false, just embed first level dependency
* Local aar project does not support transitive, always embed first level
* Default value is false
* @since 1.3.0
*/
transitive = true
}
如果你将transitive的值改成了true,并且想忽略pom文件中的某一个依赖项,你可以添加exclude
关键字,例如:
embed("com.facebook.fresco:fresco:1.11.0") {
// exclude any group or module
exclude(group = "com.facebook.soloader", module = "soloader")
// exclude all dependencies
isTransitive = false
}
接下来你需要做的可能是和你的乙方联调确认依赖是否有冲突问题,如果有并且对方不能修改,那我建议看看下面的 maven
发布方式
发布到 maven
平台托管依赖
相比于前一种将多个 aar
重组打成一个包,发布到 maven
平台具有:
- 包体体积更小;
- 版本管理更加灵活可靠可追溯;
- 发布管理方便
等优点,缺点嘛,我觉得也是有的,配置上要更麻烦一点,尤其是当你跟我一样,项目全 kotlin
化的,kts
的 gradle
可是费了我不少时间,那下面就听我给你细说。
1. 添加 maven-publish
插件
在 SDKDemo
module 的 build.gradle.kts
(本节后文同) 添加 maven-publish
插件
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
id("maven-publish")
}
2. 先打印一下 module
的 variant
配置,并配置发布的 variant
在 build.gradle.kts
的 最外层 android
节点同级添加 afterEvaluate
并打印 variant
配置信息
afterEvaluate {
publishing {
publications {
// 注意,这里的 release 是为发布任务定义的
create<MavenPublication>("release") {
components.forEach {
System.out.println(it.name)
}
}
}
}
在确认了你的 variant
名称之后,继续配置 MavenPublication
afterEvaluate {
publishing {
publications {
create<MavenPublication>("release") {
// components.forEach {
// System.out.println(it.name)
// }
// 注意,这里的 Release 本发布任务对应的 variant,从上一步打印的 variant 中选择填写
from(components.getByName("Release"))
groupId = "com.randalldev.sdkdemo" // 唯一标识(通常为模块包名,也可以任意)
artifactId = "sdkdemo" // 项目名称(通常为类库模块名称,也可以任意)
version = "v1.0.0" // 版本号
}
}
}
3. 此时你就可以先尝试执行发布本地 maven
再次执行查看 gradle
任务命令,查找 maven
发布命令
./gradlew :SdkDemo:tasks
应该会看到 publishReleasePublicationToMavenLocal
的命令
执行一下,确认没有报错,然后继续后续的配置
4. 添加你的 maven
仓库及账户配置
afterEvaluate {
publishing {
···
repositories {
maven {
// 如果你的仓库地址是私服且没有配置 https 证书,那就需要添加这行
isAllowInsecureProtocol = true
// 这里的名字自定义即可,用来标识你的仓库,会在 gradle 命令体现
name = "maven"
url = uri("你的仓库地址")
credentials {
username = "你的账户"
password = "你的密码"
}
}
}
}
}
5. 执行发布命令
再次执行查看 gradle
任务命令,查找 maven
发布命令
./gradlew :SdkDemo:tasks
应该会看到 publishReleasePublicationToMavenRepository
的命令
这一步完成,在前置步骤均顺利的情况下,就可以完成 module
的 maven
发布了
6. 建议调整一下依赖的编译 scope
publishing.publications.configureEach {
pom.withXml {
asNode().dependencies.'*'.findAll() {
it.scope.text() == 'runtime' && project.configurations.implementation.allDependencies.find { dep ->
println("replace dependency name from ${dep.name} to ${it.artifactId.text()}")
dep.name == it.artifactId.text()
}
}.each {
println("replace dependency scope from ${it.scope*.value} to compile")
it.scope*.value = 'compile'
}
}
}
这部分代码,我目前还没能实现 kts
化,所以暂时需要单独创建一个 SDKDemo
目录下的 scope.gradle
并 apply
进 的 maven
配置相关代码
afterEvaluate {
publishing {
publications {
···
}
apply(from = "scope.gradle")
repositories {
···
}
}
}
看下执行发布命令后产生的影响
- before
- after
所谓 scope
是 pom
管理文件中用于定义依赖关系的标签,它规定了依赖的作用域,即依赖在何时可用、以及在构建的不同阶段中是否被包含。而 pom
是用来描述项目构建的基本信息,可以简单理解为 pom
文件中管理着所有依赖及其作用域。
以下是 maven
中常见的依赖作用域:
作用域 | 编译 | 测试 | 运行 | 包含到 JAR/WAR | 备注 |
---|---|---|---|---|---|
compile | 是 | 是 | 是 | 是 | 默认作用域,适用于所有阶段。 |
provided | 是 | 是 | 否 | 是 | 编译和测试时需要,运行时由容器提供。 |
runtime | 否 | 是 | 是 | 是 | 编译时不需要,但在运行时需要。 |
test | 否 | 是 | 否 | 否 | 仅在测试阶段使用,不包含到最终构建。 |
system | 否 | 否 | 是 | 是 | 与 provided 类似,但需要显式提供路径。 |
import | - | - | - | - | 仅在 <dependencyManagement> 中使用。 |
我们 Android
项目以来添加,常使用 implementation
,其对应着 runtime scope
,通过将 scope
修改为 compile
可以避免一些依赖冲突问题,比如 duplicated class *******
7. 添加依赖即可使用了
将仓库地址和可访问的账户提供给使用者,其在项目的 settings.gradle.kts
中配置 maven
仓库
dependencyResolutionManagement {
···
repositories {
···
maven {
// 非 https 地址需要添加
allowInsecureProtocol(true)
credentials {
username = "乙方的账户"
password = "乙方的密码"
}
url = uri("maven 仓库地址")
}
}
}
并在需要使用的 module
中添加依赖
implementation("com.randalldev.sdkdemo:sdkdemo:v1.0.0")
参考文章
Maven Publish Plugin
使用maven-publish插件发布Android工件(kts)
fat-aar实践及原理分享
相关推荐
- 轻松上手:
(三)笔记可再编辑 - 如何在iPhone,iPad和Android上使用WordPress应用程序
- 一款简单高效的Android异步框架
- [Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- Android---View中的setMinWidth与setMinimumWidth的踩坑记录
- Android广播如何解决Sending non-protected broadcast问题
- 有关Android Binder面试,你未知的9个秘密
- 开启Android学习之旅-2-架构组件实现数据列表及添加(kotlin)
- Android低功耗蓝牙开发总结
- Android 通知文本颜色获取
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 9Android广播如何解决Sending non-protected broadcast问题
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版