Proguard可以移除无用代码,或者使用语意模糊的名称来重命名类、变量和方法,以此达到压缩、优化和混淆代码的目的。这样,生成的APK体积更小,并且不容易被逆向工程。这些都比较常用,不作过多介绍,比较让我们头疼的是关于bean类的混淆,一般我们都是把所有的bean类放在同一个package下,或者继承同一个Base实体来控制不混淆,实现起来感觉不是很优雅,下面介绍一种比较优雅的注解混淆方案。
实现原理
- 自定义不混淆注解
- 在Proguard配置中指定被注解的类或者函数、成员不执行混淆
具体实现
一. 整个类不混淆
注解定义@IgnoreClassAll
/**
* 不需要混淆整个类,包括类名,成员变量和成员方法
*
* @author shamschu
* @Date 17/7/31 下午4:26
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
public @interface IgnoreClassAll {
}
使用示例:如数据库数据实体需要整个类不混淆
@Entity
@IgnoreClassAll
public class FaqQuestionInfo implements Serializable {
@Id
private String questionId;
private String title;
private String content;
private String searchContent;
private String sectionId;
private String sectionCode;
private String questionCode;
@Generated
public FaqQuestionInfo() {
}
public FaqQuestionInfo(String questionId) {
this.questionId = questionId;
}
@Generated
public FaqQuestionInfo(String questionId, String title, String content, String searchContent, String sectionId, String sectionCode, String questionCode) {
this.questionId = questionId;
this.title = title;
this.content = content;
this.searchContent = searchContent;
this.sectionId = sectionId;
this.sectionCode = sectionCode;
this.questionCode = questionCode;
}
public String getQuestionId() {
return questionId;
}
public void setQuestionId(String questionId) {
this.questionId = questionId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSearchContent() {
return searchContent;
}
}
二. 混淆类名,不混淆成员变量名(如Json数据解析实体)
注解定义:@IgnoreMembers
/**
* 不需要混淆类成员变量,混淆类名和成员方法名
*
* @author shamschu
* @Date 17/7/31 下午4:26
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
public @interface IgnoreMembers {
}
使用示例(服务端返回的Json数据不混淆字段):
@IgnoreMembers
public static class Settings {
/***
* msgCountPollInterval:未读消息数量轮询间隔,单位秒, appDownloadUrl:社区app下载地址
*
*/
private long msgCountPollInterval;
private String appDownloadUrl;
private String postUrlReg;
}
三. 不混淆指定的成员变量或者方法
注解定义:@IgnoreProperty
/**
* 不需要混淆指定成员变量或方法
*
* @author shamschu
* @Date 17/7/31 下午4:26
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
public @interface IgnoreProperty {
}
使用示例:
public class DisplayInfo implements Comparable {
@IgnoreProperty // 不混淆id字段
private String id;
private String name;
private int displayOrder;
@IgnoreProperty // 不混淆getId()方法
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
在Proguard中配置
#不混淆实体类
-keep,allowobfuscation @interface com.zsh.test.proguard.IgnoreClassAll
-keep @com.zsh.test.proguard.IgnoreClassAll class * {*;}
-keep,allowobfuscation @interface com.zsh.test.proguard.IgnoreMembers
-keepclassmembers @com.zsh.test.proguard.IgnoreMembers class * {*;}
-keep,allowobfuscation @interface com.zsh.test.proguard.IgnoreProperty
-keepclassmembers class * {
@com.zsh.test.proguard.IgnoreProperty *;
}
三. 注意点
- 创建一个数据实体时,要清楚的判断是否可以混淆实体类的类名或者只有部分变量或者方法不混淆,再判断应该用@IgnoreMembers或者@IgnoreClassAll或者IgnoreProperty
- 内部类如果不需要混淆也需要加上指定的注解
- 新增一个库时,一般该库都会提供混淆配置,采用它们提供的混淆配置而不是整个库直接不混淆,因为有的库代码是可混淆的,可以有效缩小apk体积
网友评论