Can't figure out how to correctly setup R8 obfuscation rule to keep my interface working.
I am releasing a library. It has obfuscated code everywhere, except it's public API.
There is a basic interface BaseFoo
that has a type parameters in signature:
interface BaseFoo<D, E> {
fun handle(result: SomeOtherClass<D, E>): Boolean
}
Then there is a class Bar
with derived interface DerivedFoo
declared inside:
class Bar {
interface DerivedFoo : BaseFoo<Alice, Bob>
}
After publishing this code with obfuscation using R8, attempt to use this library's interface DerivedFoo
fails:
val myDerivedFoo = object : Bar.DerivedFoo {
override fun handle(result: SomeOtherClass<Alice, Bob>): Boolean {
return false
}
}
object
here shows error:
Object is not abstract and does not implement abstract member public abstract fun handle(result: SomeOtherClass<Alice, Bob>): Boolean defined in com.example.Bar.DerivedFoo
Respectively the handle
method gives the
'handle' overrides nothing
error. If you make an overriding function using autocomplete here, you'll get:
override fun handle(result: SomeOtherClass<D, E>): Boolean {
}
That is - exactly with <D, E>
generic arguments (instead of <Alice, Bob>
), despite the fact that compiler does not know, what are those D
and E
.
The obfuscation config so far has these rules set up:
-keeppackagenames com.example.**
-keep public class com.example.Bar { *; }
-keep public interface com.example.Bar$DerivedFoo { *; }
# Common rules:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-dontshrink
-verbose
-ignorewarnings
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,InnerClasses,EnclosingMethod,MethodParameters,Exceptions
-keepparameternames
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable
Can anyone shed some light on how to treat this missing derived interface signature?
UPDATE: sample with reproducing issue can be found here
It appears that config is correct and everything should work. But it does not due to some Kotlin-interoperability issues, I guess.
Good news is that alongside with other Kotlin-related issues this was fixed in 2.1.42 version.
So the solution for given problem is to force usage of corresponding R8 version:
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.
}
}
Credits go to this answer