我终于被 implementation 和 api 逼疯了

背景

本人是一枚Android SDK开发程序猿,就是开发SDK以提供给客户使用。之前咱们SDK开发本着能不依赖第三方就不依赖第三方的原则,使用的全是原生提供的API。因为上次通过爬虫 Android Push哪家强——分析豌豆荚1400个APP 获得使用OkHttp的APP占比已经很高了,再加上看到国外的SaaS服务公司提供的SDK对于接入第三方开源SDK非常开放。因此咱们也想将底层网络库从传统的HttpURLConnection切换为OkHttp3。然而这才是噩梦的开始……php

依赖产生问题

开发进行的很顺利,咱们在本身的SDK module中添加了okhttp的依赖java

dependencies {
    ...
    implementation 'com.squareup.okhttp3:okhttp:3.12.1'
}
复制代码

在测试demo APP中添加了SDK module依赖node

dependencies {
    ...
    implementation project(':sdk-lib')
}
复制代码

嗯,demo APP运行的很完美,代码是跑的飞起。 可是当咱们发布到Maven上去,而后新建一个APP直接添加咱们的依赖的时候,出现问题了。android

dependencies {
    ...
    implementation 'com.xxxx.xxxx:sdk-lib:1.0.0'
}
复制代码

竟然报出NoClassDefFoundError什么状况?!我不是在个人sdk-lib已经添加了OkHttp的依赖了吗?!apache

java.lang.NoClassDefFoundError: Failed resolution of: Lokhttp3/MediaType;
复制代码

implementation 和 api的区别

根据官网依赖项配置的介绍api

implementation 只是不对外暴露依赖的SDK的API而已呀,为何主APP没有产生依赖呢?不是说运行时会提供?咱们来看看最后Maven仓库中的pom文件

<?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.xxxx.xxxx</groupId>
  <artifactId>sdk-lib</artifactId>
  <version>1.0.0</version>
  <packaging>aar</packaging>
  <dependencies>
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.12.1</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>
复制代码

咱们看到scope的类型是runtime。百度后基本的作法就是在主APP的依赖中从新添加OkHttp的依赖,或者使用api替代implementation。好,那咱们使用api依赖后再看看依赖的pom文件,发现scope的类型是compile。android-studio

<?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.xxxx.xxxx</groupId>
  <artifactId>sdk-lib</artifactId>
  <version>1.0.0</version>
  <packaging>aar</packaging>
  <dependencies>
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.12.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
复制代码

从新新建一个APP并依赖新的sdk-lib,果真没问题,代码跑的飞起。bash

更复杂的状况

若是到这里基本已经结束了,那岂不是又是一篇水文?众所周知,咱们在开发和发布的时候常常会有不一样的依赖状况,好比开发的时候使用的是module依赖,发布的时候使用的线上Maven库依赖。好比须要发布的sdk-lib SDK依赖了一个本身开发core模块。网络

dependencies {
    ...
    debugApi project(':core-lib')
    releaseApi "com.xxxx.xxxx:core:$coreVersion"
}
复制代码

当咱们使用gradle的generatePomFileForReleasePublication Task生成Pom文件发现,并无core-lib的依赖,什么鬼?!不是说好用api就好了吗?!app

<?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.xxxx.xxxx</groupId>
  <artifactId>sdk-lib</artifactId>
  <version>1.0.0</version>
  <packaging>aar</packaging>
</project>
复制代码

解决问题

没办法,看来gradle的发布插件maven-publish已经知足不了咱们了,那就本身编写pom依赖吧,把全部的 implementation 和 api 依赖都添加进去。以下,在APP的build.gradle中添加

publishing {
    publications {
        mavenAgent(MavenPublication) {
            artifact "${project.buildDir}/outputs/aar/${project.name}-release.aar"
            groupId yourGroupId
            artifactId yourArtifactId
            version yourVersion
            pom.withXml {
                writePom(asNode())
            }
        }
    }
}

void writePom(node) {
    def allDependencies = new HashSet<DependencySet>()
    allDependencies.addAll(configurations.api.allDependencies)
    allDependencies.addAll(configurations.releaseApi.allDependencies)
    allDependencies.addAll(configurations.implementation.allDependencies)
    allDependencies.addAll(configurations.releaseImplementation.allDependencies)
    def iterator = allDependencies.iterator()
    while (iterator.hasNext()) {
        def dep = iterator.next()
        //移除project类型的依赖
        if (dep.name == "unspecified" || dep.version == "unspecified") {
            iterator.remove()
        }
    }

    def depsNode = node.appendNode('dependencies')
    allDependencies.each { dep ->
        def depNode = depsNode.appendNode('dependency')
        depNode.appendNode('groupId', dep.group)
        depNode.appendNode('artifactId', dep.name)
        depNode.appendNode('version', dep.version)
        depNode.appendNode('scope', 'compile')
    }
}
复制代码

咱们在gradle任务列表中执行下属两个任务(其中mavenAgent是你本身取的发布别名),并查看依赖状况。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.xxxx.xxxx</groupId>
  <artifactId>sdk-lib</artifactId>
  <version>1.0.0</version>
  <packaging>aar</packaging>
  <dependencies>
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.12.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.xxxx.xxxx</groupId>
      <artifactId>core</artifactId>
      <version>1.0.0</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
复制代码

好,大功告成,发布到线上jcenter仓库!让用户的代码跑的飞起!

相关文章
相关标签/搜索