需求
公司项目开发过程中会有一些公用的组件需要封装成SDK,方便给每个项目直接依赖使用。有个人的开源控件也一样。起初简单的控件SDK封装非常简单,不需要额外的依赖,直接使用Android原生的控件封装而成,或者是再加上一些support/androidx的依赖,还有就是三方库:RxJava、OkHttp、Glide等。
上面说的组件都是通过gradle-dependencies远程依赖的,我们应该知道一个区别:api和implementation之间的区别。
api:当前module可以使用,依赖当前module的module也可以使用。
implementation:只有当前module可以使用,其他module需要单独重新依赖才可以使用。
一般都用api,bintray上传的时候生成的pom文件会将api的依赖都写进去,这样当使用这个组件的时候,gradle会自动读取pom文件里面的额外依赖信息,自动将这些依赖组件下载到本地。
bintray上传插件:
问题
远程依赖会在pom文件中生成,但是aar依赖不会。例如这样:
api fileTree(dir: 'libs', include: ['*.aar'])
或者
api(name: 'aarFileName', ext: 'aar')
当你用正常上传方法,编译、上传后,新生成的aar文件解压后你是可以看到aarFileName.aar这个文件,但是你却使用不了里面的资源和类信息。
解决
我肯定不是第一个人遇到这种问题的人,但是为啥花费了我两天时间才搞明白这个呢?网上没有具体介绍这问题的解决方案,或者说我搜索的方式有问题?🤔🤔🤔总之没有一篇好的文章介绍这个问题。这也是我把标题写成这样的原因。。
强大的网友其实很早就已经遇到这个问题并有了解决方案,就是通过在gradle编译阶段增加合并aar的操作,将依赖的aar,aarFileName.aar解压后,把各种资源信息和自己开发的SDK组件内容合并放一块再打包成一个aar上传bintray。具体原理可以看gradle插件源代码,使用方法看README。
第一个最近更新是2017年,第二个近期都在维护但是我用起来R文件处理有问题,androidx包的资源id合并进来后总是报找不到的错误。所以推荐第三个。
第三个稍微也有个小问题,当它和bintray-release上传插件搭配的时候,会在pom.xml文件中默认加上aar依赖的信息,例子:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ming</groupId>
<artifactId>yan</artifactId>
<version>2.1.0</version>
<packaging>aar</packaging>
<dependencies>
<dependency>
<groupId>androidx.appcompat</groupId>
<artifactId>appcompat</artifactId>
<version>1.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.1.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>androidx.recyclerview</groupId>
<artifactId>recyclerview</artifactId>
<version>1.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<artifactId>Sophonsdk</artifactId>
<type>aar</type>
<scope>runtime</scope>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<artifactId>webrtclib</artifactId>
<type>aar</type>
<scope>runtime</scope>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
这样子的pom文件,当它被其他项目依赖的时候,因为aar依赖不能被获取,同步必定会失败,直接导致项目也就不能编译了。小明就绞尽脑汁看bintray-release插件的源代码,看他有没有对pom文件修改的方式。看了之后还真有,原理其实和gradle-bintray-plugin插件一样,因为用的api一样!都是maven-publish插件,此插件用法:
apply plugin: 'maven-publish'
直接上实现方式:
1.bintray-release
publish {
artifactId = this.status//项目名称
userOrg = rootProject.userOrg//bintray.com用户名
groupId = rootProject.groupId//jcenter上的路径
// publishVersion = rootProject.publishVersion//版本号
publishVersion = this.version//版本号
desc = rootProject.desc
website = rootProject.website
publications = ['MyPublication']
}
version '2.0.16-test'
status 'yan'
publishing {
publications {
MyPublication(MavenPublication) {
artifact("$buildDir/outputs/aar/${this.status}-release.aar")
groupId rootProject.groupId
artifactId this.status
version this.version
// Define this explicitly if using implementation or api configurations
pom.withXml {
Node dependenciesNode = asNode().getAt('dependencies')[0] ?: asNode().appendNode('dependencies')
// Iterate over the implementation dependencies (we don't want the test ones), adding a <dependency> node for each
configurations.api.allDependencies.each {
// Ensure dependencies such as fileTree are not included.
println it.name
if (it.name != 'unspecified') {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
}
}
}
2. gradle-bintray-plugin
bintray {
user = rootProject.user
key = rootProject.key
publications = ['MyPublication']
publish = true
pkg {
repo = 'maven'
name = this.status
userOrg = rootProject.userOrg
licenses = ['Apache-2.0']
vcsUrl = 'https://github.com/bintray/gradle-bintray-plugin.git'
version {
name = this.version
desc = 'Gradle Bintray Plugin 1.0 final'
released = new Date()
vcsTag = this.version
attributes = ['gradle-plugin': 'com.use.less:com.use.less.gradle:gradle-useless-plugin']
}
}
}
version '2.0.16-test'
status 'yan'
publishing {
publications {
MyPublication(MavenPublication) {
artifact("$buildDir/outputs/aar/${this.status}-release.aar")
groupId rootProject.groupId
artifactId this.status
version this.version
// Define this explicitly if using implementation or api configurations
pom.withXml {
Node dependenciesNode = asNode().getAt('dependencies')[0] ?: asNode().appendNode('dependencies')
// Iterate over the implementation dependencies (we don't want the test ones), adding a <dependency> node for each
configurations.api.allDependencies.each {
// Ensure dependencies such as fileTree are not included.
println it.name
if (it.name != 'unspecified') {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
dependencyNode.appendNode('scope', 'implementation')
}
}
}
}
}
}
下面两段POM配置是不是一模一样。。区别主要是SDK基础信息的配置。
gradle-bintray-plugin插件不同的是不配置publishing,pom文件就不会主动添加api修饰的远程依赖。这样当别人依赖你的组件的时候还需要自己手动添加一遍所需的SDK了。
总结
填坑小能手 小明