最近比较忙,博客和 codeKK 都两个月没怎么更新了。赶在月末分享个小技巧。
一、场景
两年前在 Proguard 语法及常用 proguard.cfg 代码 中介绍过一些 Proguard 的基础知识,其中提到一些类不能混淆,比如实现了 Serializable 接口的,否则反序列化时会出错。这种情况我们可以简单的通过在 proguard-rules.pro 配置文件中添加配置,对于较早 Android 项目默认配置文件可能为 proguard.cfg,如下:
1 2 3 4 5 6 7 8 9 10 |
-keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } |
表示所有实现了 Serializable 接口的类及其成员都不进行混淆。
但有时我们可能需要防止一些没有明显共同特征的类被混淆,比如个别控制层类需要反射、个别实体类需要 JSON 化存本地,这时我们怎么做呢,一个个添加到 proguard-rules.pro(或 proguard.cfg) 中吗?
这样会导致 proguard 配置文件变得杂乱无章,同时需要团队所有成员对其语法有所了解。
这里分享个小技巧,通过给这些类、属性、函数添加共同标识,然后统一过滤。
二、解决方法
1. 新建表示统一标识的注解 NotProguard
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package cn.trinea.android.common.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * NotProguard, Means not proguard something, like class, method, field<br/> * * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2015-08-07 */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) public @interface NotProguard { } |
NotProguard 是个编译时注解,不会对运行时性能有任何影响。可修饰类、方法、构造函数、属性。
关于注解更多的知识可见:Java Annotation 介绍及几个常用开源项目注解原理简析
2. 在 Proguard 配置文件中过滤被这个注解修饰的元素
1 2 3 4 5 6 |
# Keep annotated by NotProguard -keep @cn.trinea.android.lib.annotation.NotProguard class * {*;} -keep,allowobfuscation @interface cn.trinea.android.lib.annotation.NotProguard -keepclassmembers class * { @cn.trinea.android.lib.annotation.NotProguard *; } |
表示不混淆被 NotProguard 修饰的类、属性和方法。
3. 使用
(1) 整个类不混淆
1 2 |
@NotProguard public class User {} |
(2) 单个属性不混淆
1 2 |
@NotProguard public int id; |
(3) 单个方法不混淆
1 2 3 4 |
@NotProguard public boolean isValid() { … } |
这样我们便解决了每个类都需要在 proguard 配置文件中配置的问题。
三、关于混淆
混淆一般在 Release 模式生效,主要有三个作用:
(1) 压缩、优化、删除代码;
(2) 一定程度上提高反编译后被读懂的难度;
(3) 通过删除代码功能实现的特殊作用。
比如在 Proguard 语法及常用 proguard.cfg 代码 中介绍的利用 Progurad 使得线上版本不打印 Log.d 和 Log.v 的技巧,防止调试的敏感信息被泄露。
一些应用的代码可能从来都没混淆过,虽说这些代码实际价值可能不大,本身可能也是开源代码凑起来的,再者该破解的还是能破解,但本着做事要专业的态度,还是混淆吧。
关于 Proguard 基础可参考:
Proguard 语法及常用 proguard.cfg 代码
ProGuard 的作用、使用及 Bug 分析
四、杂谈
感谢不少朋友的关心,九月份博客会恢复正常更新。虽然很忙,还是抽空完善了 codeKK。
透露下下周 codeKK 会发布一个大功能模块,对,跟源码解析、职位内推并列的顶级模块,相信会对大家有用,希望大家到时多支持。
挺好的,不过更好的方式自带的@Keep注解就可解决,默认的proguard-android.txt文件里就添加了@keep注解不混淆,文件在:..\sdk\tools\proguard\proguard-android.txt。
默认是匿名
第一个才是正确。方向都对,但Android本身就有了的。@keep
这个是正解。top
你好,看了你的文章。我是定义了一个注解,去对接口用了保持不混淆;但混淆之后此接口出现// INTERNAL ERROR // 的结果。请问是什么原因呢?-keep @cn.trinea.android.common.annotation.NotProguard class * {*;} 这样写没有看太明白
-keep @cn.trinea.android.lib.annotation.NotProguard class * {*;}-keep,allowobfuscation @interface cn.trinea.android.lib.annotation.NotProguard-keepclassmembers class * { @cn.trinea.android.lib.annotation.NotProguard *;}这一段都要加上
Android混淆干货,mark。谢谢Trinea大神
非常优雅的方式….前天遇到某无良厂子更新sdk 问题,写了些依赖反射实现的方法,这个方式正好能优雅解决反射配置被混淆问题
好些次链接都到楼主这里。分享的都是干货,非常感谢~
楼主,我加入混淆,签名打包后百度地图上的覆盖物不见了,我都将覆盖物添加这部分的代码都keep了,怎么还是不显示,网上找了很多关于百度地图相关的混淆规则,还是不能解决,求楼主能帮我看看这个问题,感激不尽。急急急急急急急!!!
看看 mapping.txt 中百度覆盖物的类还在不在
我看到mapping.txt中有com.baidu.mapapi.map.Overlay a() -> a
求Trinea大神,快点看到我的信息吧。。。。
可以直接 keep 所有 com.baidu 开头的测试下
keep了,但还是不行。
这都不是事,目前接手一套代码,很多bean都没有序列化,最后我直接给忽略这个包了
嗯,同一个包下面都属于有明显共同特征
一直关注博主的文章。并且已经注册且投资挖财,给博主助阵
哈哈,顺便也替挖财感谢你,祝理财愉快
顶
确实比较忙啊
各种忙,不过马上会好些了