Kotlin 反射与 MetaData 的关系在混淆后浮出水面!

概要

本文主要为大家介绍 Kotlin 反射的一些原理,并提示大家如果需要在使用 Kotlin 反射的工程中进行混淆,千万注意,对所有反射涉及的类和接口的父类都需要 Keep。

问题的产生

话说我曾经遇到过一个问题,这个问题可以用下面的代码复现:

 
 
  1. open class SuperClass

  2. class SubClass: SuperClass(){

  3.    companion object {

  4.        fun seeErrorAfterProguard(){

  5.            try {

  6.                SubClass::class.supertypes.forEach {

  7.                    debug(it)

  8.                }

  9.            } catch (e: Exception) {

  10.                e.printStackTrace()

  11.            }

  12.        }

  13.    }

  14. }

如果混淆的时候没有 keep 这两个类,那么使用 Kotlin 反射时会抛一个无法找到 SuperClass 这个类的异常。

可能有些朋友可能还没有反应过来这是什么意思,如果我们使用 Java 反射的话,哪怕 SuperClass 这个类已经被混淆成了 a,那么使用 SubClass 获取它的父类也应该是去找 a 这个类,而不会仍然回去找什么 SuperClass,毕竟这个类信息已经在混淆的时候被改了呀,运行时的 Kotlin 反射又是怎么知道它的存在的呢?

Kotlin 反射的小伎俩

Kotlin 反射能够拿到 Java 反射拿不到的很多东西,这一点毋庸置疑,毕竟 Kotlin 的语法特性更复杂,需要的信息也更多。可是,既然最后大家都编译成了字节码,如果字节码里面原来就有这些信息,Java 反射无论如何也不应该金屋藏娇,捂着不给人看吧——Kotlin 反射一定是另辟蹊径的,不然它又怎么会突破字节码的限制呢?

那么它是怎么做到的呢?当然是这个:

 
 
  1. @Metadata(

  2.   mv = {1, 1, 9},

  3.   bv = {1, 0, 2},

  4.   k = 1,

  5.   d1 = {"..."},

  6.   d2 = {"Lcom/bennyhuo/kotlinspecifics/reflect/SubClass;", "Lcom/bennyhuo/kotlinspecifics/reflect/SuperClass;", "()V", "Companion", "production sources for module app"}

  7. )

  8. public final class SubClass extends SuperClass {

  9.    ...

  10. }

上面给出的是 SubClass 编译后的字节码反编译得到的 Java 代码,我们看到 Metadata 这个注解当中包含了很多信息,其中 d2 当中就包含了这个类所有的父类信息。

这时候想必各位同仁已然猜到了,其实 Kotlin 反射获取信息的过程就是一个注解读取的过程。

混淆有何罪过

既然知道了 Kotlin 反射的原理,那么我们来想想混淆,混淆对于类的处理,对于通过字面量反射操作类和对象来说是致命的,因为字面量不会作为混淆的对象。同样的,前面的注解的值也不会。也真是这个原因,混淆后 SuperClass 被混淆为了 aSubClass 的注解中存的仍然是 SuperClass

没错,混淆之后出现找不到类的问题是合乎情理的。只要是通过字面量反射操作类和对象,无论是直接还是间接,都需要注意混淆的问题。

如果大家不信,大家也可以试一下属性引用或者函数引用,看看他们在被混淆之后有什么情况发生。

那么这个应该是混淆的锅咯?当然不是,Kotlin 反射毕竟有点儿曲线救国的意思,混淆也只能长叹一口气,“你们这。。让我防不胜防啊”。

有解决方案吗?

有啊,凡涉及到使用 Kotlin 反射的类及其父类(接口)、属性、函数等,均要小心这个问题,如果出现无法找到类或者属性、函数的情形,记得 Keep 它们。

最后再说一句

解析注解这种操作。。。额,难怪它慢。。


欢迎关注微信公众号 Kotlin

640?wx_fmt=jpeg


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值