这是一个非常罕见的案例,我已经尝试过用谷歌搜索,但不幸的是没有任何结果。
基本上我想创建一个库模块并从中构建一个 aar 二进制文件以供不同的客户端应用程序共享。但是当我在库模块中创建一个枚举类时,发生了一件奇怪的事情:
当 R8 minifyEnabled 关闭时,生成的 aar 文件可以导入到客户端应用程序并正确编译。但是当 minifyEnabled 打开时,它开始抛出这个错误来调用枚举“.name”属性:
Function invocation 'name()' expected
更多详情如下:在库模块中
ScaleTyp.kt:
enum class ScaleType constructor(private val text: String) {
LARGE("large"),
SMALL("small");
override fun toString(): String {
return text
}
}
构建.gradle:apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
debug {
testCoverageEnabled = false
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
...
在应用模块中:place generated aar in libs folder
MainActivity.kt,这是它在调用 .name 时抛出错误的地方,这在 kotlin 中应该是完全合法的。import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.mylibrary.ScaleType
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ScaleType.LARGE.name //compile failed
}
}
应用程序模块中的 build.gradleapply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
testCoverageEnabled = false
minifyEnabled false
shrinkResources false
proguardFiles 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
...
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
...
}
在深入研究 AAR 二进制文件后,我观察到当 minifyEnabled 在 lib 模块中关闭时,ScaleType 类被转换为public final enum class ScaleType private constructor(text: kotlin.String) : kotlin.Enum<com.example.mylibrary.ScaleType> {
因此在客户端应用程序中这绝对没问题,因为这只是 kotlin 调用名称的方式。ScaleType.LARGE.name //compile pass
但是当 minifyEnabled 为真时,它被翻译为public final enum com/example/mylibrary/ScaleType extends java/lang/Enum
然后在客户端应用程序中,因为它将 ScaleType 视为 java 枚举,所以它会期望开发人员调用ScaleType.LARGE.name()
instead of
ScaleType.LARGE.name // compile failed
我还可以确认将库模块作为源导入没有这个问题,因为编译器已将所有 kotlin 类统一翻译为 java 类。它们以这种方式是一致的,所以它没有这个 kotlin 到 java 的冲突。这现在造成了很大的麻烦。对于直接导入库模块的应用,调用“.name”即可。但是对于使用 aar 二进制的应用程序,它们必须调用“.name()”,更痛苦的是,在调试 lib 模块时仍然必须使用“.name”。
任何帮助,将不胜感激。
如果你想尝试一下,你可以找到示例代码 here
最佳答案
Kotlin 编译器使用类文件中的 Kotlin 元数据来确定什么是 Kotlin 属性。因此,如果不维护 Kotlin 元数据,Kotlin 编译器将无法判断 name
是一个属性,它会将其视为 Java 代码,因此会坚持您调用 name()
方法。
R8 在 AGP 4.1 beta3 中增加了对维护和重写 Kotlin 元数据的支持。因此,如果您更新到该版本并将以下内容放入您的库压缩器配置文件中,希望这应该可以解决您的问题。
# Keep kotlin.Metadata annotations to maintain metadata on kept items.
-keepattributes RuntimeVisibleAnnotations
-keep class kotlin.Metadata { *; }
关于java - 安卓枚举 : generate AAR binary with R8 on and throws "Function invocation ' name( )'" exception in client app,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62859307/