处理 R8 + JvmStatic Annotation + Lambda in public API for Android Library written in Kotlin

Dealing with R8 + JvmStatic Annotation + Lambda in public API for Android Library written in Kotlin

首先,请注意,我并不期待 why do you want to obfuscate library 评论。这是我要问的一个真正的问题。

我在使用 Kotlin 编写的 Android 库处理 R8/obfuscation 时遇到了问题。

我有一个 public API 方法,它用 @JvmStatic 注释并且该方法采用 Lambda 作为参数。

例如,看看下面的代码,

typealias MyLambdaCallback = (String, Map<String, Any>) -> Unit

@Keep
object MyApi {

    private var callback: MyLambdaCallback? = null

    @JvmStatic
    fun setCallback(callback: MyLambdaCallback) {
        this.callback = callback
    }
}

我添加了 @Jvmstatic 以便 Java 调用代码可以静态调用方法而不是 MyApi.INSTANCE.setCallback()

当我在没有 minification 的情况下发布库时,一切都很好,并且从 JavaKotlin 调用代码都按预期编写。

但是现在我想在开启的同时释放库minification

这会产生问题。

这里是错误

java.lang.IncompatibleClassChangeError: The method 'void setCallback(kotlin.jvm.functions.Function2)' was expected to be of type virtual but instead was found to be of type static (declaration of 'com.demo.basic.Application' appears in /data/app/com.demo.basic-_0uJXPbtfs3UZ2Rp2h-RdQ==/base.apk!classes2.dex)

我是不是在某处犯了错误,或者这应该是某种限制?

我尝试了什么?

  1. 删除 @Jvmstatic 解决了问题,但它创建了难看的 Java 调用代码

  2. 保留 @Jvmstatic 但删除 Lambda 将 Lambda 转换为 interface with one method,一切正常。不幸的是 SAM for Kotlin classes 还没有,所以调用 Kotlin 代码看起来很难看。

这在 R8 问题跟踪器 http://issuetracker.google.com/158393309 上进行了跟踪,其中包含更多详细信息。

简而言之,这已在 R8 版本 2.1.35 中修复,可以通过对顶层 build.gradle 文件进行以下更改来使用:

repositories {
    maven {
        url 'https://storage.googleapis.com/r8-releases/raw'
    }
}

dependencies {
    classpath 'com.android.tools:r8:2.1.35'          // Must be before the Gradle Plugin for Android.
    classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
 }

R8 团队在 R8 版本 2.1.42

中有 fixed this issue along with related issue b/158400283

修复程序应该已经在 Android Studio 4.1 beta 或更高版本中可用,但如果您使用的是稳定版 Android Studio 4.0,则将以下内容添加到您的顶级 build.gradle 文件中:

buildscript {

    repositories {
        maven {
            url 'https://storage.googleapis.com/r8-releases/raw'
        }
    }

    dependencies {
        classpath 'com.android.tools:r8:2.1.42'          // Must be before the Gradle Plugin for Android.
        classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
     }
}