google的gson三方包混淆问题,附上通用proguard-rules.pro

来源:互联网 发布:日程管理软件 知乎 编辑:程序博客网 时间:2024/06/14 18:56

碰到个头疼的问题,一个朋友项目混淆后打包编译出错,debug模式下正常。

断点模式下一步步检查发现:json解析以后数据放到javabean中去的,放进去的字符串是对的,解析出来的,但是javabean却是空,节操碎一地,多方查找原因后知道他项目json使用了google的gson三方包,于是猜想混淆的时候出了问题。

然后陪同一起查看混淆文本,一番下来基本的混淆文件都没问题,然后查找第三方包,
他说明明已经按照gson的官方文档,把混淆脚本加上去了,却还是出问题。

我后面又去查了次官方文档:google官方的proguard的文档如下,请大家一定要注意倒数第二行,class 后方到**签名的 这一段包名应该是你所有的java bean定义的目录,其实官方注释也写明了“Application classes that will be serialized/deserialized over Gson”(将通过Gson序列化/反序列化的应用程序类),通常我们cope后直接就用了没有去注意这个细节(lll¬ω¬),然后打包时Gson不能正常使用。ps:建议大家在写代码时把java bean 放在一个独立的包中,以便这行混淆文本简洁。

##---------------Begin: proguard configuration for Gson  ----------# Gson uses generic type information stored in a class file when working with fields. Proguard# removes such information by default, so configure it to keep all of it.-keepattributes Signature# For using GSON @Expose annotation-keepattributes *Annotation*# Gson specific classes-keep class sun.misc.Unsafe { *; }#-keep class com.google.gson.stream.** { *; }# Application classes that will be serialized/deserialized over Gson-keep class com.google.gson.examples.android.model.** { *; } ##这里包名需要改成自己的java bean包##---------------End: proguard configuration for Gson  ----------

以上就是Gson混淆解决方法,记录下以免自己也犯同样错误。


当然写篇文章不可能就这么短,那么接下来整理下混淆相关知识

混淆过程会有如下几个功能:

  1. 压缩。移除无效的类、类成员、方法、属性等;
  2. 优化。分析和优化方法的二进制代码;根据proguard-android-optimize.txt中的描述,优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
  3. 混淆。把类名、属性名、方法名替换为简短且无意义的名称;
  4. 预校验。添加预校验信息。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。

这四个流程默认开启。在 Android 项目中我们可以选择将“优化”和“预校验”关闭,对应命令是-dontoptimize、-dontpreverify(当然,默认的 proguard-android.txt 文件已包含这两条混淆命令,不需要开发者额外配置)。

科普下混淆基本指令区指令的含义,也是查资料得到的了(^_^)

  • 代码混淆的压缩比例,值在0-7之间
    -optimizationpasses 5
  • 混淆后类名都为小写
    -dontusemixedcaseclassnames
  • 指定不去忽略非公共的库的类
    -dontskipnonpubliclibraryclasses
  • 指定不去忽略非公共的库的类的成员
    -dontskipnonpubliclibraryclassmembers
  • 不做预校验的操作
    -dontpreverify
  • 生成原类名和混淆后的类名的映射文件
    -verbose
    -printmapping proguardMapping.txt
  • 指定混淆是采用的算法
    -optimizations !code/simplification/cast,!field/,!class/merging/
  • 不混淆Annotation
    -keepattributes Annotation,InnerClasses
  • 不混淆泛型
    -keepattributes Signature
  • 抛出异常时保留代码行号
    -keepattributes SourceFile,LineNumberTable

以上可以了解,有兴趣的可以去调试下((lll¬ω¬)—>自己很多都没用过)

接下来介绍下比较常用的:

  • -keep 防止类和成员被移除或者被重命名
    • -keep class XXXX 保留类名不变,也就是类名不混淆,而类中的成员名不保证
  • -keepnames 防止类和成员被重命名
  • -keepclassmembers 防止成员被移除或者被重命名
  • -keepnames 防止成员被重命名
  • -keepclasseswithmembers 防止拥有该成员的类和成员被移除或者被重命名
    • -keepclasseswithmembers class XXXX保留类名和成员名。当然也可以是类中特定方法
  • -keepclasseswithmembernames 防止拥有该成员的类和成员被重命名

想要继续了解的可以参考以下几篇文章:

Android安全攻防战,反编译与混淆技术完全解析(下)
Android混淆从入门到精通
Android代码混淆之ProGuard

最后附上稍作整理的 proguard-rules.pro 文档,各位可以在此基础上更改或添加以用于自己项目

#指定代码的压缩级别-optimizationpasses 5#包明不混合大小写-dontusemixedcaseclassnames#不去忽略非公共的库类-dontskipnonpubliclibraryclasses #优化  不优化输入的类文件-dontoptimize #预校验-dontpreverify #混淆时是否记录日志-verbose#保护注解-keepattributes *Annotation*# 保持哪些类不被混淆-keep public class * extends android.app.Fragment-keep public class * extends android.app.Activity-keep public class * extends android.app.Application-keep public class * extends android.app.Service-keep public class * extends android.content.BroadcastReceiver-keep public class * extends android.content.ContentProvider-keep public class * extends android.app.backup.BackupAgentHelper-keep public class * extends android.preference.Preference-keep public class com.android.vending.licensing.ILicensingService#如果有引用v4包可以添加下面这行-keep public class * extends android.support.v4.app.Fragment#忽略警告-ignorewarning##记录生成的日志数据,gradle build时在本项目根目录输出###apk 包内所有 class 的内部结构-dump proguard/class_files.txt#未混淆的类和成员-printseeds proguard/seeds.txt#列出从 apk 中删除的代码-printusage proguard/unused.txt#混淆前后的映射-printmapping proguard/mapping.txt########记录生成的日志数据,gradle build时 在本项目根目录输出-end#######如果引用了v4或者v7包-dontwarn android.support.**####混淆保护自己项目的部分代码以及引用的第三方jarlibrary-end#####保持 native 方法不被混淆-keepclasseswithmembernames class * {    native <methods>;}#保持自定义控件类不被混淆-keepclasseswithmembers class * {    public <init>(android.content.Context, android.util.AttributeSet);}#保持自定义控件类不被混淆-keepclassmembers class * extends android.app.Activity {   public void *(android.view.View);}-keep public class * extends android.view.View {    public <init>(android.content.Context);    public <init>(android.content.Context, android.util.AttributeSet);    public <init>(android.content.Context, android.util.AttributeSet, int);    public void set*(...);}#保持 Parcelable 不被混淆-keep class * implements android.os.Parcelable {  public static final android.os.Parcelable$Creator *;}#保持 Serializable 不被混淆-keepnames class * implements java.io.Serializable#保持 Serializable 不被混淆并且enum 类也不被混淆-keepclassmembers class * implements java.io.Serializable {    static final long serialVersionUID;    private static final java.io.ObjectStreamField[] serialPersistentFields;    !static !transient <fields>;    !private <fields>;    !private <methods>;    private void writeObject(java.io.ObjectOutputStream);    private void readObject(java.io.ObjectInputStream);    java.lang.Object writeReplace();    java.lang.Object readResolve();}#保持枚举 enum 类不被混淆-keepclassmembers enum * {  public static **[] values();  public static ** valueOf(java.lang.String);}-keepclassmembers class * {    public void *ButtonClicked(android.view.View);}#不混淆资源类,保持R文件不被混淆,否则,你的反射是获取不到资源id的  -keepclassmembers class **.R$* {    public static <fields>;}#避免混淆泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了,如果混淆报错建议关掉)#-keepattributes Signature#移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用,另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制,也可以自己写日志文件#-assumenosideeffects class android.util.Log {#    public static *** v(...);#    public static *** i(...);#    public static *** d(...);#    public static *** w(...);#    public static *** e(...);#}###############################  以上通用也可根据需求修改 ################################     ###################################################################################################################################################################################################  第三方包混淆选项,根据需求添加 ################################            #一般查看官方文档都有#####################################  第三方end ####################################################################################################################################### js互调的类,工程中没有直接跳过。##############一般你可以这样写-keep class 你的类所在的包.** { *; }#如果是内部类的话,你可以这样-keepclasseswithmembers class 你的类所在的包.父类$子类 { <methods>; }############# js互调的类end ############## 如果使用了Gson之类的工具要使被它解析的JavaBean类即实体类不被混淆。##---------------Begin: proguard configuration for Gson  ----------# Gson uses generic type information stored in a class file when working with fields. Proguard# removes such information by default, so configure it to keep all of it.-keepattributes Signature# For using GSON @Expose annotation-keepattributes *Annotation*# Gson specific classes-keep class sun.misc.Unsafe { *; }#-keep class com.google.gson.stream.** { *; }# Application classes that will be serialized/deserialized over Gson-keep class com.google.gson.examples.android.model.** { *; } ##这里包名需要改成自己的java bean包##---------------End: proguard configuration for Gson  ----------#如果在当前的application module或者依赖的library module中使用了第三方的库,并不需要显式添加规则#-libraryjars xxx#添加了反而有可能在打包的时候遭遇同一个jar多次被指定的错误,一般只需要添加忽略警告和保持某些class不被混淆的声明。#以libaray的形式引用了开源项目,如果不想混淆 keep 掉,在引入的module的build.gradle中设置

如有错误请指正,十分感谢!


为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。

原创粉丝点击