5

我终于被 implementation 和 api 逼疯了

 2 years ago
source link: http://www.androidchina.net/10015.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

依赖产生问题

开发进行的很顺利,我们在自己的SDK module中添加了okhttp的依赖

dependencies {
    ...
    implementation 'com.squareup.okhttp3:okhttp:3.12.1'
}

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

dependencies {
    ...
    implementation project(':sdk-lib')
}

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

dependencies {
    ...
    implementation 'com.xxxx.xxxx:sdk-lib:1.0.0'
}

居然报出NoClassDefFoundError什么情况?!我不是在我的sdk-lib已经添加了OkHttp的依赖了吗?!

 java.lang.NoClassDefFoundError: Failed resolution of: Lokhttp3/MediaType;

implementation 和 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。

<?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,果然没问题,代码跑的飞起。

更复杂的情况

如果到这里基本已经结束了,那岂不是又是一篇水文?众所周知,我们在开发和发布的时候经常会有不同的依赖情况,比如开发的时候使用的是module依赖,发布的时候使用的线上Maven库依赖。比如需要发布的sdk-lib SDK依赖了一个自己开发core模块。

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

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

<?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仓库!让用户的代码跑的飞起!

作者:小肥阳
链接:https://juejin.im/post/5d19b6a2f265da1b942160f7
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载请注明:Android开发中文站 » 我终于被 implementation 和 api 逼疯了


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK