Fresco 源码解析 - 利用 @DoNotSkip 来防止混淆

我们都知道,如果打开了混淆开关,代码 release 阶段会根据 proguard 规则进行混淆,但是有些实体类(例如 json 字符串对应的 model)需要进行序列化、反序列化,而序列化工具(例如 Gson、fastjson)是利用反射来一一对应 json 串的 key 和实体类的成员变量。

例如,我们定义一个 POJO 类型的 User 实体类:

public class User {
  public String firstName;
  public String lastName;
  public int age;
}

那么对应的 json 串内容如下:

{
   "firstName":"fei",
   "lastName":"liangfei",
   "age":28
}

如果 User 类被混淆掉(成员变量的可能因为没有被用到而被删除或者名字改掉),那序列化工具就无能为力了,因为找不到 json key 与成员变量的对应关系(例如 User.firstName => “firstName”)。

一般的做法会在 proguard 文件中 keep 住 User 的成员变量:

 -keepclassmembernames User.**

但是当多团队合作,代码分散在不同 project 时,每次添加一个实体类还需要修改 proguard 文件,如果多个人同时修改,很可能产生冲突,所以我们必须要想一个一劳永逸的办法。

方法肯定有很多个,Fresco 利用 Annotation - @DoNotSkip 的做法还是比较巧妙的。

首先定义 @DoNotSkip(注释里详细说明了功能):

/**
 * Add this annotation to a class, method, or field to instruct Proguard to not strip it out.
 *
 * This is useful for methods called via reflection that could appear as unused to Proguard.
 */
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR })
@Retention(CLASS)
public @interface DoNotStrip {
}

然后在 proguard 文件中添加如下规则:

# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip

# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
    @com.facebook.common.internal.DoNotStrip *;
}

这样一来,我们只要给 User 加上 @DoNotSkip 就不会被混淆掉了。

@DoNotSkip
public class User { }

@DoNotSkip 的定义可以知道它的 target:

@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR })

所以,除了类(TYPE)我们还可以把 @DoNotSkip 用于 成员变量(FIELD)、方法(METHOD) 和构造方法(CONSTCTUCTOR)。

@Keep

其实,我们可以不用定义这个 annotation,因为 Android support-annotations 包提供了一个与 @DoNotSkip 类似的 annotation - @Keep, 但是现阶段我们仍然需要在 proguard 中一次性添加规则,将来可能就就不需要了。

We’ve also added @Keep to the support annotations. Note however that that annotation hasn’t been hooked up to the Gradle plugin yet (though it’s in progress.) When finished this will let you annotate methods and classes that should be retained when minimizing the app.

时间: 2024-12-28 15:00:30

Fresco 源码解析 - 利用 @DoNotSkip 来防止混淆的相关文章

Fresco源码解析 - 创建一个ImagePipeline(一)

在Fresco源码解析 - 初始化过程分析章节中,我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipelineFactory.initialize(context);会创建一个所有参数都使用默认值的ImagePipelineConfig来初始化ImagePipeline. ImagePipelineFactory.initialize(imagePipelineConfig)会首先用 imagePipelin

Fresco源码解析 - 初始化过程分析

使用Fresco之前,一定先要进行初始化,一般初始化的工作会在Application.onCreate()完成,当然也可以在使用Drawee之前完成. Fresco本身提供了两种初始化方式,一种是使用使用默认配置初始化,另一种是使用用户自定义配置. 如下代码是Fresco提供的两个初始化方法.第一个只需要提供一个Context参数,第二个还需要提供 ImagePipeline 的配置实例 - ImagePipelineConfig. /** Initializes Fresco with the

Fresco源码解析 - 本地编译

第一次写专栏,如有表述不好或者理解错误的地方,请各位读者不吝赐教,本人一定虚心接受并第一时间改正. 作为专题第一篇,先从最简单的开始,顺便找找感觉. Fresco 是 facebook 在今年的 F8 大会上宣布开源的一个用于加载图片的库,它不仅支持多种图片文件格式,而且由于使用了pinned purgeables 技术,使得大图加载过程中产生OOM的概率大大降低,对开发者来说绝对是一件喜大普奔的事情,对于像天猫HD这样需要加载大量图片的APP来说也绝对是个福音. 下载代码 首先把源码从 Git

Fresco源码解析 - DraweeView

DraweeView 是Fresco的三大组件(Hierarchy.Controller.View) 之一,作为MVC模式中的 View,主要负责显示由 Hierarchy 提供的数据(placeholder.actual image.progress drawable等),Controller 作为幕后,负责获取数据. 继承体系 DraweeView 并不是是一个简单的自定义View,它必须要提供与 Hierarchy 和 Controller 交互的接口,DraweeView 的继承关系如下

Fresco源码解析 - DataSource怎样存储数据

datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系比较简单,一张类图基本就可以描述清楚它们间的关系. DataSource 是一个 interface, 功能与JDK中的Future类似,但是相比于Future,它的先进之处则在于 不仅仅只生产一个单一的结果,而是能够提供系列结果. Unlike Futures, DataSource can issue a series of results, rathe

Fresco源码解析 - Hierarachy-View-Controller

Fresco是一个MVC模型,由三大组件构成,它们的对应关系如下所示: M -> DraweeHierarchy V -> DraweeView C -> DraweeController M 所对应的 DraweeHierarchy 是一个有层次结构的数据结构,DraweeView 用来显示位于 DraweeHierarchy 最顶层的图像(top level drawable),DraweeController 则用来控制 DraweeHierarchy 的顶层图像是哪一个. o F

Fresco 源码浅析

前言 fresco是facebook主导的一个开源图片缓存库,从它提供的示例程序comparison来看,fresco貌似比其他的几个目前android主流的图片缓存库(glide,picasso,uil等)更快更节省内存.接下来就看看它到底是如何做到的. 一.背景: 1:lru与SoftReference那些年的爱恨情仇:很久很久以前,android的内存缓存还用SoftReference, 在2.3以后,垃圾回收机制被修改,软引用已不推荐用作缓存技术了,lru等才是正义.既然软引用已经不再推

ChrisRenke/DrawerArrowDrawable源码解析

转载请注明出处http://blog.csdn.net/crazy__chen/article/details/46334843 源码下载地址http://download.csdn.net/detail/kangaroo835127729/8765757 这次解析的控件DrawerArrowDrawable是一款侧拉抽屉效果的控件,在很多应用上我们都可以看到(例如知乎),控件的github地址为https://github.com/ChrisRenke/DrawerArrowDrawable

socketserver源码解析和协程版socketserver

来,贴上一段代码让你仰慕一下欧socketserver的魅力,看欧怎么完美实现多并发的魅力 client import socket ip_port = ('127.0.0.1',8009) sk = socket.socket() sk.connect(ip_port) sk.settimeout(5) while True: data = sk.recv(1024) print('receive:',data.decode()) inp = input('please input:') sk