使用 AAR 和源 JAR 将 Android 库发布到 Maven
Posted
技术标签:
【中文标题】使用 AAR 和源 JAR 将 Android 库发布到 Maven【英文标题】:Publish an Android library to Maven with AAR and sources JAR 【发布时间】:2014-11-11 21:01:20 【问题描述】:有人可以告诉我如何使用 maven-publish
Gradle 插件发布带有 AAR 和源 jar 的 com.android.library
项目/模块吗?我可以使用旧的 maven
插件来做到这一点 - 但我想使用新的 maven-publish
插件。
【问题讨论】:
见this similar post。 【参考方案1】:这是使用新的maven-publish
插件的示例。
apply plugin: 'maven-publish'
task sourceJar(type: Jar)
from android.sourceSets.main.java.srcDirs
classifier "sources"
publishing
publications
bar(MavenPublication)
groupId 'com.foo'
artifactId 'bar'
version '0.1'
artifact(sourceJar)
artifact("$buildDir/outputs/aar/bar-release.aar")
repositories
maven
url "$buildDir/repo"
使用./gradlew clean build publish
发布
【讨论】:
生成的pom中好像没有记录依赖。 使用这个插件,它也会生成依赖到 pom 中:github.com/wupdigital/android-maven-publish 在我将classifier "source"
替换为classifier "sources"
后,这对我有用。
无效发布“库”:具有相同扩展名和分类器(“aar”、“null”)的多个工件。
我也收到了Invalid publication 'library': multiple artifacts with the identical extension and classifier ('aar', 'null').
消息。 @mudit_sen,你找到解决这个问题的方法了吗?【参考方案2】:
当前答案
有了Android Gradle Plugin 7.1,现在可以很简单地做到这一点,不需要任何复杂的脚本。 AGP 现在还处理创建源和 javadocs jar。
您不需要任何单独的脚本,只需将所有内容写入模块的 build.gradle
文件即可:
plugins
...
id 'maven-publish'
android
...
publishing
singleVariant("release")
// if you don't want sources/javadoc, remove these lines
withSourcesJar()
withJavadocJar()
afterEvaluate
publishing
publications
release(MavenPublication)
from components.release
groupId 'com.example'
artifactId 'mylibrary'
version = android.defaultConfig.versionName // or manually '1.0'
另见:https://developer.android.google.cn/studio/build/maven-publish-plugin
旧答案
2020 年 3 月 3 日更新:
自 Android Studio 3.6 发布以来,对构建 AAR(甚至是 APK 和 AAB)的支持已在 Android Gradle 插件 3.6.0(及更高版本)中实现。
我们不再需要处理 XML 依赖和自己的东西了。
这是我为 Android Studio 3.6.0 更新的 Gist:https://gist.github.com/Robyer/a6578e60127418b380ca133a1291f017
来自 gist 的代码:
apply plugin: 'maven-publish'
task androidJavadocs(type: Javadoc)
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all variant ->
if (variant.name == 'release')
owner.classpath += variant.javaCompileProvider.get().classpath
exclude '**/R.html', '**/R.*.html', '**/index.html'
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs)
archiveClassifier.set('javadoc')
from androidJavadocs.destinationDir
task androidSourcesJar(type: Jar)
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
// Because the components are created only during the afterEvaluate phase, you must
// configure your publications using the afterEvaluate() lifecycle method.
afterEvaluate
publishing
publications
// Creates a Maven publication called "release".
release(MavenPublication)
// Applies the component for the release build variant.
from components.release
// Adds javadocs and sources as separate jars.
artifact androidJavadocsJar
artifact androidSourcesJar
// You can customize attributes of the publication here or in module's build.gradle file (if you save this as script and include it build.gradle file, then you can just replicate this whole block there only with changed fields).
//groupId = 'com.example'
//artifactId = 'custom-artifact'
version = android.defaultConfig.versionName // or just '1.0'
旧答案:
这是我根据其他答案改进的解决方案。
要点: https://gist.github.com/Robyer/a6578e60127418b380ca133a1291f017
其他答案的变化:
已更改classifier
- 必须是 "sources"
(不是 "source"
)
处理依赖关系
还支持@aar
和transitive: false
。在这种情况下,我们在 POM 中设置排除以忽略此依赖项的所有传递依赖项。
还支持对依赖项的自定义排除规则,例如:
compile('com.example:something:1.0',
exclude group: 'com.exclude.this', module: 'some-module'
)
不需要手动指定工件路径。
更新日志:
27.3.2018 - 在新 Gradle 中添加了对 api / implementation 依赖项的支持 23.11.2018 - 将bundleRelease
重命名为 bundleReleaseAar
,因为它在新 Gradle 中已更改(请参阅 this answer)
23.11.2018 - 将 getAllDependencies
更改为 getDependencies
以修复重复的结果条目(如我 Gist 中的 cmets 所述)。
23.04.2019 - 包裹在 project.afterEvaluate...
中,为新的 Gradle 修复它。
apply plugin: 'maven-publish'
task androidJavadocs(type: Javadoc)
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all variant ->
if (variant.name == 'release')
owner.classpath += variant.javaCompile.classpath
exclude '**/R.html', '**/R.*.html', '**/index.html'
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs)
classifier = 'javadoc'
from androidJavadocs.destinationDir
task androidSourcesJar(type: Jar)
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
project.afterEvaluate
publishing
publications
maven(MavenPublication)
//groupId 'cz.example'
//artifactId 'custom-artifact'
//version = android.defaultConfig.versionName
artifact bundleReleaseAar
artifact androidJavadocsJar
artifact androidSourcesJar
pom.withXml
final dependenciesNode = asNode().appendNode('dependencies')
ext.addDependency = Dependency dep, String scope ->
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
return // ignore invalid dependencies
final dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
dependencyNode.appendNode('scope', scope)
if (!dep.transitive)
// If this dependency is transitive, we should force exclude all its dependencies them from the POM
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
exclusionNode.appendNode('groupId', '*')
exclusionNode.appendNode('artifactId', '*')
else if (!dep.properties.excludeRules.empty)
// Otherwise add specified exclude rules
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
dep.properties.excludeRules.each ExcludeRule rule ->
exclusionNode.appendNode('groupId', rule.group ?: '*')
exclusionNode.appendNode('artifactId', rule.module ?: '*')
// List all "compile" dependencies (for old Gradle)
configurations.compile.getDependencies().each dep -> addDependency(dep, "compile")
// List all "api" dependencies (for new Gradle) as "compile" dependencies
configurations.api.getDependencies().each dep -> addDependency(dep, "compile")
// List all "implementation" dependencies (for new Gradle) as "runtime" dependencies
configurations.implementation.getDependencies().each dep -> addDependency(dep, "runtime")
【讨论】:
def dependencyNode = dependenciesNode.appendNode('dependency')
抛出异常Could not get unknown property 'dependenciesNode' for object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.
更改了分类器 - 它必须是“来源”(而不是“来源”)对我有很大帮助!
在新的 gradle 中,bundleReleaseAar
再次抛出错误,但似乎我们只需要将整个 publishing
块包装到 project.afterEvaluate publishing ...
中。然后它再次工作。 (我刚刚更新了答案)
我刚刚更新了用于 Android Studio 3.6 的脚本。
@androiddeveloper androidJavadocs
创建 javadocs,androidJavadocsJar
从中创建一个 *.jar 文件用于发布。这可能不适用于 Kotlin 代码,但有人分叉了我的要点以添加一些支持。见那里:gist.github.com/Robyer/…【参考方案3】:
通过正确的依赖生成对 dskinners 的回答稍作调整:
apply plugin: 'maven-publish'
task sourceJar(type: Jar)
from android.sourceSets.main.java.srcDirs
classifier "source"
publishing
publications
bar(MavenPublication)
groupId 'com.foo'
artifactId 'bar'
version '0.1'
artifact(sourceJar)
artifact("$buildDir/outputs/aar/bar-release.aar")
pom.withXml
def dependenciesNode = asNode().appendNode('dependencies')
//Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each
configurations.compile.allDependencies.each
if(it.group != null && (it.name != null || "unspecified".equals(it.name)) && it.version != null)
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
repositories
maven
url "$buildDir/repo"
您可以通过定义更改version
和groupId
:
version = '1.0.0'
group = 'foo.bar'
【讨论】:
可以使用artifact bundleRelease
,而不是硬编码aar文件名。此外,(it.name != null || "unspecified".equals(it.name))
的条件看起来也不正确。你的意思是(it.name != null && "unspecified" != it.name)
?
如何包含对项目模块的依赖?【参考方案4】:
如果你想避免样板代码,因为maven-publish
插件不会将依赖项写入 pom.xml
试试这个插件:android-maven-publish
publishing
publications
mavenAar(MavenPublication)
groupId 'com.example'
artifactId 'mylibrary'
version '1.0.0'
from components.android
repositories
maven
url "$buildDir/releases"
更新:
android-maven-publish 插件已弃用,因为 AGP 正式支持 maven-publish。
【讨论】:
感谢链接 bvarga。该插件是否负责在生成的 pom 文件中添加依赖排除项? bvarga,我刚试过,是的!感谢您让我注意到这个插件。它就像一个魅力! 这是迄今为止该问题的最佳解决方案。应该接受 IMO。 @HermanZun 查看更新后的答案。您可以在任何地方指定存储库。android-maven-publish
插件已弃用,因为 AGP 正式支持 maven-publish
。使用 AGP 3.6.0 或更高版本。【参考方案5】:
您也可以使用android maven plugin。它创建 .aar、javadoc.jar、sources.jar 和 .pom 并在将文件上传到 maven 存储库后更新 maven-metadata.xml。我也把脚本放在GitHub上。
apply plugin: 'com.android.library'
apply plugin: 'maven'
//Your android configuration
android
//...
//maven repository info
group = 'com.example'
version = '1.0.0'
ext
//Specify your maven repository url here
repositoryUrl = 'ftp://your.maven.repository.com/maven2'
//Or you can use 'file:\\\\C:\\Temp' or 'maven-temp' for a local maven repository
//Upload android library to maven with javadoc and android sources
configurations
deployerJars
//If you want to deploy to an ftp server
dependencies
deployerJars "org.apache.maven.wagon:wagon-ftp:2.2"
// custom tasks for creating source/javadoc jars
task javadoc(type: Javadoc)
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
destinationDir = file("../javadoc/")
failOnError false
task javadocJar(type: Jar, dependsOn: javadoc)
classifier = 'javadoc'
from javadoc.destinationDir
//Creating sources with comments
task androidSourcesJar(type: Jar)
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
//Put the androidSources and javadoc to the artifacts
artifacts
archives androidSourcesJar
archives javadocJar
uploadArchives
repositories
mavenDeployer
configuration = configurations.deployerJars
repository(url: repositoryUrl)
//if your repository needs authentication
authentication(userName: "username", password: "password")
用
调用它./gradlew uploadArchives
【讨论】:
问题的重点是使用 maven-publish 插件,而不是使用 maven 插件的旧方式。【参考方案6】:这就是我使用 Kotlin DSL (build.gradle.kts) 包含 Dokka(查看 online)和为我的 Android Kotlin library 提供 JAR 的方式:
plugins
// ...
id("org.jetbrains.dokka") version "1.4.32"
id("maven-publish")
lateinit var sourcesArtifact: PublishArtifact
lateinit var javadocArtifact: PublishArtifact
tasks
val sourcesJar by creating(Jar::class)
archiveClassifier.set("sources")
from(android.sourceSets["main"].java.srcDirs)
val dokkaHtml by getting(org.jetbrains.dokka.gradle.DokkaTask::class)
val javadocJar by creating(Jar::class)
dependsOn(dokkaHtml)
archiveClassifier.set("javadoc")
from(dokkaHtml.outputDirectory)
artifacts
sourcesArtifact = archives(sourcesJar)
javadocArtifact = archives(javadocJar)
publishing
// ...
publications
create<MavenPublication>("MyPublication")
from(components["release"])
artifact(sourcesArtifact)
artifact(javadocArtifact)
// ...
【讨论】:
以上是关于使用 AAR 和源 JAR 将 Android 库发布到 Maven的主要内容,如果未能解决你的问题,请参考以下文章
Android 库 (jar/aar) 可以用于 Xamarin 中的 iOS
Android如何将一个Demo或者app打包成aar或jar提供给其他应用使用
Android 库:使用 proguard 时释放 .aar 使 classes.jar 为空
[Android][Android Studio] *.jar 与 *.aar 的生成与*.aar导入项目方法