Android SDK开发 bintray aar嵌套aar aar合并 so库

需求

公司项目开发过程中会有一些公用的组件需要封装成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上传插件:

  1. bintray-release
  2. gradle-bintray-plugin

问题

远程依赖会在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。

  1. android-fat-aar
  2. fat-aar-android
  3. fat-aar(推荐)

第一个最近更新是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了。

总结

填坑小能手 小明

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。