Search code examples
kotlinproguardandroid-r8

Issue with Kotlin generic's type argument in interface after R8 obfuscation


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


Solution

  • 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