某学姐

Android Female Developer, Technology Fan, Reader.

Android学习笔记——Android代码混淆

2018-09-15 | Comments

由于之前的工作,一直没有负责过代码混淆这一块,久而久之理解也不是很深刻,小小记录一下。

读懂 Android 中的代码混淆

Android ProGuard 代码混淆那些事儿

我觉得需要掌握的:
(1)ProGuard做了哪些事情?
(2)几个指令的含义:optimizationpasses, dontusemixedcaseclassnames, dontskipnonpubliclibraryclasses, verbose, dontwarn, dontnote, ignorewarnings, optimizations
(3)几个keep的区别:keep/keepclassmembers/keepclasseswithmembers、keepnames/keepclassmembernames/keepclasseswithmembernames
(4)哪些需要keep,为什么需要keep?
(5)mapping.txt符号映射表

下面简单的总结:
(1)ProGuard做了哪些事情?
首先看下ProGuard官网:https://www.guardsquare.com/en/proguard

ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier. The shrinking step detects and removes unused classes, fields, methods and attributes. The optimization step analyzes and optimizes the bytecode of the methods. The obfuscation step renames the remaining classes, fields, and methods using short meaningless names. These first steps make the code base smaller, more efficient, and harder to reverse-engineer. The final preverification step adds preverification information to the classes, which is required for Java Micro Edition and for Java 6 and higher.

包括4步:
shrinker, optimizer, obfuscator, and preverifier。

shrinker:压缩。检测并移除无用的类、字段、方法和属性。
optimizer:优化。分析并优化方法的字节码。
obfuscator:混淆。用无意义的短变量重命名其余的类、字段和方法。
preverifier:预校验。

(2)几个指令的含义?

这个参考上面的链接即可。

(3)几个keep的区别?

keep/keepclassmembers/keepclasseswithmembers、keepnames/keepclassmembernames/keepclasseswithmembernames

首先带name和不带name的区别:
不带name:不被压缩和混淆
带name:会被压缩,但不混淆

keep/keepclassmembers/keepclasseswithmembers区别:
keep保留类和类中的成员
keepclassmembers保留类中的成员
keepclasseswithmembers保留类和类中的成员

(4)哪些需要keep,为什么需要keep?
case:Application、四大组件、Fragment
AndroidManifest.xml文件会定义四大组件,外部也可能通过String引用四大组件,混淆后就找不到了。
Fragment我自己理解的是,Fragment创建的时候可能有反射调用,Fragment.instantiate(Context context, String fname)就是反射调用。

case:自定义View
layout文件引用到自定义View

case:R文件
防止痛过反射查找R资源时找不到,类似getResources().getIdentifier(“activity_main”, “layout”, getPackageName());

case:Java Bean
GSON的序列化和反序列化涉及到反射调用。一种方法是keep住JavaBean类,另一种方法是通过@SerializedName注解标识JavaBean里的属性。

因为加了-keepattributes Annotation,所以注解属性不会混淆,GSON反射调用的时候就能正确映射到。

关于@SerializedName,这里又有另一个知识点:学会使用 Gson @SerializedName

case:注解
有些情况注解被用作在运行时反射确定一些元素的特征。-keepattributes *Annotation*

case:枚举
涉及到反射调用

case:反射相关

case:jni接口和java的native方法
因为java的native方法需要和cpp层面的native方法保持一致。

case:Javascript调Java的方法
和java的native方法情况一样

case:Parcelable Parcelable的子类和Creator静态成员变量
否则会出现android.os.BadParcelableException异常

case:第三方库
一般按照第三方库提供的keep规则即可。

(5)mapping.txt符号映射表?
一般解决bugly里的问题时,需要上传mapping文件,这样才能将报错和混淆前对应的源代码对应上。

本文原文发自 某学姐, 转载请保留出处, 谢谢.

Comments