在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda

Posted

技术标签:

【中文标题】在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda【英文标题】:Dealing with R8 + JvmStatic Annotation + Lambda in public API for Android Library written in Kotlin 【发布时间】:2020-09-26 16:30:01 【问题描述】:

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

我在使用 Kotlin 编写的 android 库处理 R8/混淆时遇到问题。

我有一个用 @JvmStatic 注释的公共 API 方法,该方法采用 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:方法 'void setCallback(kotlin.jvm.functions.Function2)' 应该是 virtual 类型,但被发现是 static 类型('com.demo.basic.应用程序'出现在 /data/app/com.demo.basic-_0uJXPbtfs3UZ2Rp2h-RdQ==/base.apk!classes2.dex)

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

我做了什么?

    删除 @Jvmstatic 解决了这个问题,但它创建了丑陋的 Java 调用代码

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

【问题讨论】:

你使用的是什么版本的 Kotlin 编译器? @RyanM 1.3.72 @RyanM 我发现问题出在@Jvmstatic 附近。我更新了Q的内容。看看你是否可以帮忙。 这是一个包含很多细节的好问题。对我来说,这确实看起来像是某处工具中的错误(即,不是您的错误)-我目前没有时间深入研究它,但是如果可以的话,我会看一下找点时间。 好的。没问题。谢谢@RyanM 【参考方案1】:

这在 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.
 

【讨论】:

【参考方案2】:

R8 团队在 R8 版本中有 fixed 这个问题以及相关问题 b/158400283 2.1.42

修复应该已经在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.
     

【讨论】:

以上是关于在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda的主要内容,如果未能解决你的问题,请参考以下文章

用 Kotlin 编写的 Android 库,提供对 Java 应用程序的支持

如何在用 Kotlin 编写的 JUnit 5 测试类中注入 Spring bean?

将 Kotlin 运行时库添加到 android 中的 aar

在 Kotlin 中编写具有特征的 Android 测试时出现 java.lang.VerifyError

关于在用java编写的android应用程序中使用异步共享内存(ASHMEM)

Java vs Kotlin 应该使用Kotlin进行Android开发吗