简介

gradle关于maven-publish的官方文档
maven-publish是gradle自带的插件,不需要在buildscript添加额外的dependencies,通过maven-publish进行配置后,可迅速的将aar或jar包发布到maven仓库

实现步骤

  1. 引入插件
    在module的gradle中添加引入:

    apply plugin: 'maven-publish'

    或建立新的gradle文件,通过apply from: '相对路径'进行引入

  2. 重写publishing节点,在节点中添加对repositories和publications两个节点的定义

  3. 在repositories节点中通过maven节点对maven仓库进行定义
    url赋值为需要上传的maven仓库路径,如果需要用户名和密码通过credentials节点定义
    url可以指定为本地路径,一般测试阶段进行使用

    publishing {
    repositories {
    maven {
    def repo = true //远程还是本地
    def localRepositoryUrl = 'file:E://Users/admin/Documents/Android/repo/' //本地仓库
    def repositoryUrl = "http://server:port/repository/maven-releases/" //远程仓库
    def repositoryUserName = 'username'
    def repositoryPassword = 'password'

    if (repo) {
    url = repositoryUrl
    credentials {
    username repositoryUserName
    password repositoryPassword
    }
    } else {
    url = localRepositoryUrl
    }
    }
    }
    }
  4. 在publications节点中定义publish任务
    任务的名称为合法标识符即可,但必须包含参数MavenPublication

    • 其中必须包含对artifactId的定义
    • 使用artifact指定上传包含的文件
    • 如果发布的内容中需要包含源码需要自定义任务,并通过artifact包含
      task sourcesJar(type: Jar) {        //打包源码的任务
      from android.sourceSets.main.java.srcDirs
      archiveClassifier.convention('sources')
      archiveClassifier.set('sources')
      }

      publishing {
      publications {
      upload(MavenPublication) {
      artifactId = "${project.name}" //artifactId一般和module的名称相同

      artifact "build/outputs/aar/${project.name}-release.aar" //指定aar路径
      artifact sourcesJar //包含源码
      }
      }
      }
  5. group和version的定义
    group和version可以在publications下自己添加的节点中通过对属性groupIdversion进行赋值定义,也可以在gradle文件中直接使用setGroup和setVersion定义,后者表示对maven节点中定义的所有任务的公共设置
    如果要将version定义的和versionName一样赋值为android.defaultConfig.versionName即可

    单个publish任务指定

    publishing {
    publications {
    xxx(MavenPublication) {
    groupId = 'com.xxx'
    artifactId = 'xxx'
    version = android.defaultConfig.versionName
    }
    }
    }

    全局定义:

    group = 'com.xxx'
    version = android.defaultConfig.versionName
  6. 处理pom文件
    POM是项目对象模型(Project Object Model)的简称,使用XML表示,包含各种信息和url以及依赖关系等内容
    定义作者和licenses和自定义属性等的内容在官网中都有模板也较简单,这里主要是处理类库的依赖
    处理方式:

    1. 获取gradle的dependencies节点
    2. 处理使用api和implementation定义的依赖
    3. 过滤kotlin相关的依赖
    4. 通过过滤version为unspecified的内容,过滤类似implementation fileTree(include: ['*.jar'], dir: 'libs')的依赖
      publishing {
      publications {
      upload(MavenPublication) {
      pom.withXml {
      def dependenciesNode = asNode().appendNode('dependencies')
      configurations.api.allDependencies.each {
      if (!(it instanceof ProjectDependency)) {
      if (it.group != null && (it.name != null || "unspecified" == it.name)
      && !it.group.contains("org.jetbrains.kotlin") //过滤kotlin依赖
      && it.version != null && "unspecified" != it.version) { //过滤无用依赖
      def dependencyNode = dependenciesNode.appendNode('dependency')
      dependencyNode.appendNode('groupId', it.group)
      dependencyNode.appendNode('artifactId', it.name)
      dependencyNode.appendNode('version', it.version)
      print it.toString()
      print "it.group = ${it.group} it.name = ${it.name} it.version = ${it.version} groupId = $groupId"
      if (it.group == groupId && project.getRootProject().aarMap.contains(it.name)) {
      dependencyNode.appendNode('type', 'aar')
      }
      }
      }

      }
      configurations.implementation.allDependencies.each {
      if (!(it instanceof ProjectDependency)) {
      def contains = false
      for (apiDependencies in configurations.api.allDependencies) { //以免重复添加
      if (apiDependencies.group == it.group && apiDependencies.name == it.name
      && apiDependencies.version == it.version) {
      contains = true
      break
      }
      }
      if (!contains) {
      if (it.group != null && (it.name != null || "unspecified" == it.name)
      && !it.group.contains("org.jetbrains.kotlin")
      && it.version != null && "unspecified" != it.version) {
      def dependencyNode = dependenciesNode.appendNode('dependency')
      dependencyNode.appendNode('groupId', it.group)
      dependencyNode.appendNode('artifactId', it.name)
      dependencyNode.appendNode('version', it.version)
      if (it.group == groupId && project.getRootProject().aarMap.contains(it.name)) {
      dependencyNode.appendNode('type', 'aar')
      }
      }
      }
      }
      }
      }
      }
      }
      }

指令

完成gradle文件的添加后,对应module的gradle的tasks下会多生成publishing命令集,也可以在对应project下在命令行中通过gradlew.bat或gradlew(linux) + module + : + 对应指令触发运行
命令解释:

  • generatePomFileForPubNamePublication 生成pom文件
  • publishXXXXPublicationToRepoNameRepository 将对应名称的任务发布到远程maven仓库,
    XXXX表示PubName,是在publications下定义的参数为MavenPublication名称的节点,类似节点可以定义多个,下同
  • publishXXXXPublicationToMavenLocal 将对应名称的任务发布到本地maven仓库
  • publishToMavenLocal 将所有定义的任务发布到本地maven仓库
  • publish 将所有定义的任务发布到远程maven仓库

测试和发布

通过assembleDebug或assembleRelease生成对应版本的aar包,使用本地仓库进行测试,可以在定义的路径下查看到最终上传的文件和生成的pom
确定内容无问题后,修改本地仓库为远程仓库有后,运行publish任务,即可进行maven仓库的发布.

模板总概览

tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}

task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
archiveClassifier.convention('sources')
archiveClassifier.set('sources')
}

artifacts {
archives sourcesJar
}

apply plugin: 'maven-publish'

group = 'com.xxx'
version = android.defaultConfig.versionName

publishing {
repositories {
maven {
def repo = true
def localRepositoryUrl = 'file:E://Users/admin/Documents/Android/repo/'
def repositoryUrl = "http://server:port/repository/maven-releases/"
def repositoryUserName = 'username'
def repositoryPassword = 'password'

if (repo) {
url = repositoryUrl
credentials {
username repositoryUserName
password repositoryPassword
}
} else {
url = localRepositoryUrl
}
}
}
publications {
upload(MavenPublication) {
artifactId = "${project.name}"

artifact "build/outputs/aar/${project.name}-release.aar"
artifact sourcesJar

pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.api.allDependencies.each {
if (!(it instanceof ProjectDependency)) {
if (it.group != null && (it.name != null || "unspecified" == it.name)
&& !it.group.contains("org.jetbrains.kotlin")
&& it.version != null && "unspecified" != it.version) {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
print it.toString()
print "it.group = ${it.group} it.name = ${it.name} it.version = ${it.version} groupId = $groupId"
if (it.group == groupId && project.getRootProject().aarMap.contains(it.name)) {
dependencyNode.appendNode('type', 'aar')
}
}
}

}
configurations.implementation.allDependencies.each {
if (!(it instanceof ProjectDependency)) {
def contains = false
for (apiDependencies in configurations.api.allDependencies) {
if (apiDependencies.group == it.group && apiDependencies.name == it.name
&& apiDependencies.version == it.version) {
contains = true
break
}
}
if (!contains) {
if (it.group != null && (it.name != null || "unspecified" == it.name)
&& !it.group.contains("org.jetbrains.kotlin")
&& it.version != null && "unspecified" != it.version) {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
if (it.group == groupId && project.getRootProject().aarMap.contains(it.name)) {
dependencyNode.appendNode('type', 'aar')
}
}
}
}
}
}
}
}
}