3

我正在尝试使用以下 Gradle 配置重新定位带有Shadow的包(具体来说是 OkHttp 4):

apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'

shadowJar {
    archiveBaseName.set('my_archive')
    archiveClassifier.set(null)
    version = null

    relocate 'okhttp3', 'my.prefix.okhttp3'
    relocate 'okio', 'my.prefix.okio'
}

dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.2.1") {
        exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
    }
}

(我省略了buildscript部分,重要的是使用的 Shadow 版本是5.1.0. 包前缀等也已更改)

这在 OkHttp 3.12.0 及更早版本(纯 Java)之前有效。现在 OkHttp 4 是用 Kotlin 编写的,我在使用属性时遇到了麻烦,特别是在 Kotlin 代码中。当从 Java 中使用时,重新定位的 OkHttp 工作得很好。但是访问 Kotlin 中的属性,如下所示:

val cache = httpClient.cache

...导致异常:

java.lang.NoSuchMethodError: No virtual method getCache()Lmy/prefix/okhttp3/Cache; in class Lmy/prefix/okhttp3/OkHttpClient; or its super classes (declaration of 'my.prefix.okhttp3.OkHttpClient' appears in /data/app/redacted.redacted-0yalPGR5aw0RSY2Zdxnq7Q==/base.apk)

如您所见,该应用程序是一个 Android 应用程序,以防万一。

任何想法我的配置可能有什么问题?

4

2 回答 2

0

我们在非 android 项目中遇到了类似的情况。包级别的“事物”(在我们的例子中是扩展函数)实际上在编译器生成的类(在我们的例子中称为 ExtensionKt.class)上是静态的

我从 Java 或 Scala 代码访问该类没有问题。然而,在 Kotlin 代码中,编译器不允许我访问ExtensionKt类,并且由 shadow Jar 重新定位的包以某种方式破坏了原始语法,因此无法再通过包名称访问它。作为一种临时解决方法,我们从 Java 访问包范围内的东西:

所以取而代之的是这个 Kotlin 代码:

import my.package.name.niceExtensionFunction

...

val x = SomeClass()
val y = x.niceExtensionFunction()

我们在 Java 中这样做:

import my.package.name.ExtensionKt;

...

SomeClass x = new SomeClass;
Object y = ExtensionKt.niceExtensionFunction(x)

于 2019-12-16T15:26:17.233 回答
0

这不是一个完美的解决方案,但至少可以让事情在某种程度上发挥作用。与其完全排除嵌入式 Kotlin 标准库,不如顺其自然并重新定位它。将所有内容重新定位到相同的前缀是最简单的,方法是将其添加到build.gradle

task relocateShadowJar(type: ConfigureShadowRelocation) {
    target = tasks.shadowJar
    prefix = "my.prefix"

}

tasks.shadowJar.dependsOn tasks.relocateShadowJar

您可能还需要在任务中排除一些 KotlinMETA-INF位。shadowJar

这种方法的问题(至少对我而言)是,虽然一切都或多或少有效,但您现在可能在您的应用程序中拥有两次 Kotlin 标准库:您的前缀版本和您通常使用的版本。此外,属性语法不起作用。所以就像问题中的例子一样,

val cache = httpClient.cache

实际上变成

val cache = httpClient.cache()

......这不是很好。

我现在面临的另一个问题是,在 Android Studio 中,结果中的所有内容在jar代码编辑器中都显示为红色,即 Android Studio 看不到jar. 一切都编译得很好,只是编辑代码本身很痛苦,因为你没有得到任何代码完成,而且 Android Studio 有时会混淆你的导入。(因为它显然认为这些导入是无效的)

于 2020-12-23T13:13:03.680 回答