NoSuchMethodError after dexguard obfuscation when use safe call `?.`


#1

There two different ways(code1 and code2 ) to get drawable instance in imageview. In theory, they are the same, but code2 will crash after dexguard obfuscation.

// code1
if(imageView == null) return
val drawable = imageView.drawable ?: ColorDrawable(Color.LTGRAY)
// code2
val drawable = imageView?.drawable ?: ColorDrawable(Color.LTGRAY)

I have pushed an demo project which can reproduce this crash to github, the repository url is https://github.com/ohmerhe/kotlindexguard.


#2

This code is not identical at all. In particular (from your github demo), look at the next line:

val drawable = imageView?.drawable ?: ColorDrawable(Color.LTGRAY)
transitionDrawable = TransitionDrawable(arrayOf(drawable, ColorDrawable()))

You are creating a transitionDrawable with the result of the operation. If ImageView is null, this will mean that you create a TransitionDrawable with a null image, something that will break sooner or later as it defeats the idea of a transition drawable.

You can fix it as follows:

imageView?.drawable ?: ColorDrawable(Color.LTGRAY)?.let { drawable ->
    transitionDrawable = TransitionDrawable(arrayOf(drawable, ColorDrawable()))
    imageView?.setImageDrawable(transitionDrawable)
    transitionDrawable.setId(0, LAYER_FIRST)
    transitionDrawable.setId(1, LAYER_SECOND)
}

Or using a regular if statement of course.


#3

If imageview is null, i will get ColorDrawable(Color.LTGRAY) to drawable property, and than create a TransitionDrawable with drawable property and new ColorDrawable(). Why is null?


#4

You are right, I misread your elvis operator for?. Your code is different though as the second variant has code executed in case of a null image view. On the NoSuchMethodError, does the problem go away if you don’t use dexguard? In that case it’s probably a bug in dexguard.


#5

The crash would not happen without dexguard. There is a strong possibility that dexguard cause it, and i ask them for help too. I want to confirm if is there any unknown bug of my code.


#6

Most likely the issue is that the kotlin compiler creates code that is different from what the java compiler would/could create. As such it doesn’t have the testing and breaks the algorithms in dexguard that determine dead code. One thing you may notice if you look at bytecode is that javac doesn’t really use the dup bytecode much.