Solution 1 :
The Kotlin compiler uses Kotlin metadata in the class files to determine what is a Kotlin property. Therefore, if the Kotlin metadata is not maintained, the Kotlin compiler will not be able to tell that name
is a property and it will see it as Java code and will therefore insist that you call the name()
method.
R8 has added support for maintaining and rewriting Kotlin metadata in AGP 4.1 beta3. Therefore, if you update to that version and put the following in your library shrinker configuration file, hopefully, that should solve your issue.
# Keep kotlin.Metadata annotations to maintain metadata on kept items.
-keepattributes RuntimeVisibleAnnotations
-keep class kotlin.Metadata { *; }
Problem :
This is a pretty rare case and I have tried googled around but unfortunately nothing came out.
Basically I wanted to create a library module and build an aar binary from it to share by different client apps. But one strange thing happens when I created an enum class in the library module:
When R8 minifyEnabled is off the generated aar file can be imported to client app and compiles properly. But when minifyEnabled is on, it starts to throw this error for calling the enum “.name” property:
Function invocation 'name()' expected
More details below:
In library module
ScaleTyp.kt:
enum class ScaleType constructor(private val text: String) {
LARGE("large"),
SMALL("small");
override fun toString(): String {
return text
}
}
build.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'
}
}
}
...
In app module:
place generated aar in libs folder
MainActivity.kt, this is where it throws the error when .name is called, which should be completely legal in 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.gradle in app module
apply 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: [])
...
}
After digging into the AAR binary, I have observed that when minifyEnabled is off in lib module the ScaleType class is translated to
public final enum class ScaleType private constructor(text: kotlin.String) : kotlin.Enum<com.example.mylibrary.ScaleType> {
therefore in client app this is absolutely fine because this is just the kotlin way of calling name.
ScaleType.LARGE.name //compile pass
but when minifyEnabled is true, it got translated to
public final enum com/example/mylibrary/ScaleType extends java/lang/Enum
then in client app, because it sees ScaleType as a java enum, it will expect developers to call
ScaleType.LARGE.name()
instead of
ScaleType.LARGE.name // compile failed
I can also confirm that importing library module as source does not have this issue because the compiler has translated all kotlin classes uniformly to java class. They are consistent in this way so it doesn’t have this kotlin to java conflict.
This is causing big trouble now. For app that imports library module directly, it is fine to call “.name”. But for apps that use aar binary, they have to call “.name()”, and even more painful you still have to use “.name” when debugging the lib module.
Any help would be appreciated.
If you want to try it, you can find sample code here