前言
在我们的项目架构中,一定存在一些基础的模块,这些模块可以在多个app上通用,这种情况我们一般会将这些模块封装成Android Library统一维护,并上传到仓库方便其他小组使用。仓库可以选择如mavenCentral这类公开的仓库,但是我们一般选择搭建自己的maven私有仓库,比如:Sonatype Nexus。本文就一步步的教大家如何将Android Library发布到maven私有仓库。
添加maven仓库配置
在项目的根目录下的gradle.properties中添加私有仓库的配置,如下:
# 包信息(包名,及Maven的group,必填) PROJ_GROUP=com.xxx.xxx # 项目的描述(描述性信息,不影响maven上传) PROJ_WEBSITEURL=http://xxxxx PROJ_ISSUETRACKERURL=http://xxxxx PROJ_VCSURL=xxxxx PROJ_DESCRIPTION=xxxx # Licence信息(严格按下面填写,不要变) PROJ_LICENCE_NAME=The Apache Software License, Version 2.0 PROJ_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt PROJ_LICENCE_DEST=repo # Developer 信息(开发者信息,不影响maven上传) DEVELOPER_ID=xxxx DEVELOPER_NAME=xxxx DEVELOPER_EMAIL=xxx@xxx.com #仓库地址(要提交的本地仓库地址) #快照库 SNAPSHOT_REPOSITORY_URL=http://xxxx/nexus/content/repositories/snapshots/ #正式库 RELEASE_REPOSITORY_URL=http://xxxx/nexus/content/repositories/releases/ 复制代码
将这部信息配置在根目录的gradle.properties中是因为我们一个项目可能存在多个Android Library需要上传到maven,这样就不用在每个module下都配置一遍。
另外还需要配置用户名和密码,但是因为这是敏感信息,一般我们放在local.properties中,这个文件一般会加入.gitignore被git忽略,这样就不会上传到代码仓库中
#maven账号 USERNAME=xxxx #maven密码 PASSWORD=xxxx 复制代码
最后还需要在Android Library下的gradle.properties中配置:
#名称(最好与PROJ_ARTIFACTID相同) PROJ_NAME=xxx #模块名(maven的artifactId) PROJ_ARTIFACTID=xxxx PROJ_POM_NAME=Local Repository 复制代码
编写发布代码
首先在Android Library下的build.gradle中添加maven插件
apply plugin: 'maven' 复制代码
然后就可以编写发布代码了,完整代码如下:
def isReleaseBuild() { return android.defaultConfig.versionName.contains("SNAPSHOT") == false } def sonatypeRepositoryUrl if (isReleaseBuild()) { sonatypeRepositoryUrl = RELEASE_REPOSITORY_URL } else { sonatypeRepositoryUrl = SNAPSHOT_REPOSITORY_URL } afterEvaluate { project -> uploadArchives { repositories { mavenDeployer { //beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } pom.artifactId = PROJ_ARTIFACTID Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) repository(url: sonatypeRepositoryUrl) { authentication(userName: properties.getProperty("USERNAME"), password: properties.getProperty("PASSWORD")) } pom.project { name PROJ_NAME groupId PROJ_GROUP version android.defaultConfig.versionName // scm { // url POM_SCM_URL // connection POM_SCM_CONNECTION // developerConnection POM_SCM_DEV_CONNECTION // } licenses { license { name PROJ_LICENCE_NAME url PROJ_LICENCE_URL distribution PROJ_LICENCE_DEST } } developers { developer { id DEVELOPER_ID name DEVELOPER_NAME } } } } } } // signing { // required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } // sign configurations.archives // } task androidJavadocs(type: Javadoc) { failOnError false source = android.sourceSets.main.java.source options { links "http://docs.oracle.com/javase/7/docs/api/" linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference" } classpath += project.android.libraryVariants.toList().first().javaCompile.classpath classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { classifier = 'javadoc' //basename = artifact_id from androidJavadocs.destinationDir } task androidSourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs } artifacts { //archives packageReleaseJar archives androidSourcesJar archives androidJavadocsJar } } 复制代码
发布到maven仓库
在Android studio右侧栏的gradle中选择要发布的Module,找到定义好的task,双击运行即可,如图
多个Android Library发布问题处理
上面我们提到,可以在一个项目中同时维护多个Android Library,但是按照上面的步骤发布的时候就会失败,问题如下:
Could not transfer artifact xxx from/to remote (http://xxx): Failed to transfer file: http://xxx. Return code is: 400, ReasonPhrase: Bad Request.
仔细观察gradle日志就会发现,当我们通过上面方式发布其中一个Android Library时,项目所有的Android Library都会重新编译并发布,但是其它Android Library并没有改变,所以没有升级版本,maven仓库如果发现发布了同样的版本(一般release仓库会有这样的设置,防止误操作导致问题)就会返回上面的错误。
一个解决方法是通过命令进行发布:
./gradlew xxx:uploadArchives 复制代码
这里xxx就是模块名,这样就会只编译发布这一个模块。
当然我们也可以通过修改发布代码来解决这个问题,在build.gradle中添加一个task如下:
task mavenUploadxxx (dependsOn: uploadArchives){ group 'upload' } 复制代码
同样这里xxx替换成模块名,这里我们将这个task放在了upload这个组里,如果不设置会默认放在other组里,但是这个组里task比较多,找起来不方便。
sync同步后在gradle的面板中对应的Module的upload组中就会发现多出一个mavenUploadxxx的task,双击执行这个task就会只编译发布这个Android Library。
使用Library
使用就比较简单了,首先添加仓库
allprojects { repositories { ... maven { url 'http://xxx/nexus/content/groups/public/' } } } 复制代码
然后在项目的build.gradle中添加依赖就可以了。
问题总结
在这个过程中也遇到了一些问题,这里简单总结一下:
1、发布到Snapshot的时候返回400错误:
Return code is: 400, ReasonPhrase: Bad Request.
这是因为版本名错了,发布到Snapshot的版本格式必须是x.x.x-SNAPSHOT,“-SNAPSHOT”必须在后面,否则会报400错误。
注意:相关错误,如发布到release的版本中有“-SNAPSHOT“也会报错;release不允许重复发布,所以如果已经有这个项目的这个版本,再次发布就会出错,而Snapshot一般支持重复发布
2、发布的时候返回401错误:
Return code is: 401, ReasonPhrase: Unauthorized
这是因为没有配置用户名密码,或配置错了。 Sonatype Nexus默认用户名admin密码admin123,但是建议及时修改。
3、Sonatype Nexus中仓库:
public:仓库组。代理其他仓库,用于外部引用。(即如果要使用Maven引入项目,则maven中心配置成这个仓库的url)
snapshot:快照库。用于提交快照版本,需要用户名密码。
release:正式库。用于提交正式版本,需要用户名密码。