I’m trying to call data class copy function using guidelines from this question, and it works fine in debug build, but as soon as I try to minify it using r8 (in standard android project) - it fails. Here’s my function:
fun <T : Any> callCopyUsingProperty(property: KProperty<*>, newValue: String, instance: T): T {
// find copy function - working fine with proper proguard rule
val copy = instance::class.memberFunctions.first { it.name == "copy" }
// THE ISSUE IS HERE
// get parameters. Works fine in debug or release, but as soon as I turn on r8 - the parameters name are different
val parameters = copy.parameters
// this in release returns "Parameters: [null, arg0, arg1]"
Log.d("TAG", "Parameters: ${parameters.map { it.name }}")
val instanceParameter = requireNotNull(copy.instanceParameter)
// i have to fine proper parameter to pass based on given [property]
// since the parameters are called arg0 and arg1 - we're crashing here on trying to fine proper name
val parameter = parameters.first { it.name == property.name }
// create a map that should be passed as copy arguments
val map = mapOf(
instanceParameter to instance,
parameter to newValue
)
// call copy and get the result
val result = copy.callBy(map)
// return result as casted T
@Suppress("UNCHECKED_CAST")
return result as T
}
I can call this function like that:
data class TestClass(
val field1: String,
val field2: String,
) {
val otherField = field1 + field2
}
try {
val test = TestClass("test1", "test2")
// let's call copy for r8 to leave the copy in binary
val dummy = test.copy(field1 = "another")
Log.d("DUM", dummy.toString())
// let's try updating field2 using this method
val result = callCopyUsingProperty(TestClass::field2, "updated", test)
if (result.field2 == "updated") {
// without r8 we're successfully here
}
} catch (ex: Throwable) {
Log.e("FAIL", "Unable to call copy via reflection", ex)
}
I tried to find some proguard rule that can keep the copy parameters name unchanged but failed to do that. So that’s my question, am I missing something obvious in proguard configuration?
UPDATE:
When i do this:
-keepnames class pl.test.repro.** {
*;
}
It works, so I have the partial solution, but I would like to be more specific. So I’d like to keep the names only for copy functions. I tried this:
-keepnames class pl.test.repro.** {
** copy(...);
}
// and this
-keepclasseswithmembernames class pl.test.repro.** {
** copy(...);
}
// and this
-keep class pl.test.repro.** {
** copy(...);
}
Which I think is a proper solution for me, but it doesn’t seem to work.
The exact thing I’m trying to achieve is to keep the names of all copy
functions in all of my classes (since there is no “data class” selector in proguard).