我刚创建了一个库并上传到bintray和jcenter。
在我的测试应用中,此库作为模块添加:
implementation project(':dropdownview')
一切都很好。
将库模块上传到jcenter后,我改为使用它:
implementation 'com.asksira.android:dropdownview:0.9.1
当库试图调用依赖于另一个库的方法时,会发生运行时错误:
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.transitionseverywhere.TransitionSet" on path: DexPathList[[zip file "/data/app/com.asksira.dropdownviewdemo-6fj-Q2LdwKQcRAnZHd2jlw==/base.apk"],nativeLibraryDirectories=[/data/app/com.asksira.dropdownviewdemo-6fj-Q2LdwKQcRAnZHd2jlw==/lib/arm64, /system/lib64, /system/vendor/lib64]]
(我正在关注this guide发布库。我在使用相同的方法之前发布了3个库,它们都运行得很好;但这是我第一次在我的程序中包含了另一个第三方库依赖项自己的图书馆。)
然后我尝试从
更改我的库的第三方库依赖项 implementation 'com.andkulikov:transitionseverywhere:1.7.9'
到
compile 'com.andkulikov:transitionseverywhere:1.7.9'
(请注意,这不是应用程序对我的库的依赖,而是我的库到另一个库)
然后再次上传到版本0.9.2的bintray。
implementation 'com.asksira.android:dropdownview:0.9.2
这次工作了吗?!
这是Android Studio / Gradle的某种错误(但Google表示他们将在2018年底删除compile
...),或者我做错了什么?
可以找到v0.9.1的完整源代码here。
请注意,我没有直接从app
到TransitionsEverywhere
访问任何方法。具体来说,当我点击ClassNotFoundException
和DropDownView
调用DropDownView
这是一个expand()
内部方法时,会发生public
。
为了消除其他因素,以下是我在将implementation
更改为compile
之前尝试过的事情,一切都没有运气:
答案 0 :(得分:2)
我现在有完全相同的问题,根据您的评论,我真的怀疑这是应该的方式。我的意思是用implementation
替换库中的所有api
对于干净的抽象是没有意义的。为什么在不需要/有时甚至不允许使用我的库的已使用依赖项给使用者/应用程序的情况下
我还检查了生成的APK是否确实包含它抱怨找不到的类。
由于我之前遇到依赖性问题,所以我记得自己为该库改进了生成的POM。
在我对其进行改进之前,生成的pom看起来像这样:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tld.yourdomain.project</groupId>
<artifactId>library-custom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<packaging>aar</packaging>
<dependencies/>
</project>
我使用以下脚本添加了依赖关系,并基于implementation
或api
向其添加了正确的作用域(based on that nice info)
apply plugin: 'maven-publish'
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
archiveClassifier = "sources"
}
task listDependencies() {
// Curious, "implementation" also contains "api"...
configurations.implementation.allDependencies.each { dep -> println "Implementation: ${dep}" }
configurations.api.allDependencies.each { dep -> println "Api: ${dep}" }
}
afterEvaluate {
publishing {
publications {
mavenAar(MavenPublication) {
groupId libraryGroupId
artifactId libraryArtefactId
version versionName
artifact sourceJar
artifact bundleReleaseAar
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.api.allDependencies
.findAll { dependency -> dependency.name != "unspecified" }
.each { dependency ->
addDependency(dependenciesNode.appendNode('dependency'), dependency, "compile")
}
configurations.implementation.allDependencies
.findAll { dependency -> !configurations.api.allDependencies.contains(dependency) }
.findAll { dependency -> dependency.name != "unspecified" }
.each { dependency ->
addDependency(dependenciesNode.appendNode('dependency'), dependency, "runtime")
}
}
}
}
repositories {
maven {
def snapshot = "http://repo.yourdomainname.tld/content/repositories/snapshots/"
def release = "http://repo.yourdomainname.tld/content/repositories/releases/"
url = versionName.endsWith("-SNAPSHOT") ? snapshot : release
credentials {
username nexusUsername
password nexusPassword
}
}
}
}
}
def addDependency(dependencyNode, dependency, scope) {
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
dependencyNode.appendNode('scope', scope)
}
您需要了解的关键部分:
implementation
依赖项也包含api
个依赖项,只需运行任务listDependencies()
来查看输出runtime
的API在应用程序/消费者中不可用,但是类路径的一部分。这样,使用者就无法直接访问那些依赖项,只能通过您自己的库提供的方法使那些依赖项“不可见”,但它们将成为类路径的一部分,因此当这些“不可见”依赖项的类被使用时,应用程序不会崩溃由类加载器加载。上面的脚本现在生成以下pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tld.yourdomain.project</groupId>
<artifactId>library-custom</artifactId>
<version>1.2.0-SNAPSHOT</version>
<packaging>aar</packaging>
<dependencies>
<dependency>
<groupId>tld.dependency</groupId>
<artifactId>android-sdk</artifactId>
<version>1.2.3</version>
<scope>compile</scope> <!-- From api -->
</dependency>
<dependency>
<groupId>tld.dependency.another</groupId>
<artifactId>another-artifact</artifactId>
<version>1.2.3</version>
<scope>runtime</scope> <!-- From implementation -->
</dependency>
<!-- and much more -->
</dependencies>
</project>
总结一下:
api
交付了类,也使依赖项也可供消费者使用implementation
也提供了这些类,但没有使消费者可以使用该依赖项,但是,在定义了runtime
范围的情况下,它仍将是类路径的一部分,从而使类加载器知道那些类是在运行时可用