简介

Java代码是非常容易反编译的。为了很好的保护Java源代码,我们往往会对编译好的class文件进行混淆处理。

ProGuard是一个混淆代码的开源项目。它的主要作用就是混淆,当然它还能对字节码进行缩减体积、优化等,但那些对于我们来说都算是次要的功能。官网网址是:

www.2cto.com

详解

1、原理

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。

混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以 阅读 。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar 文件体积大约能减少25% ,这对当前费用较贵的无线网络传输是有一定意义的。

2、语法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-include {filename}              从给定的文件中读取配置参数 
-basedirectory {directoryname}    指定基础目录为以后相对的档案名称 
-injars {class_path}             指定要处理的应用程序jar,war,ear和目录 
-outjars {class_path}            指定处理完后要输出的jar,war,ear和目录的名称 
-libraryjars {classpath}          指定要处理的应用程序jar,war,ear和目录所需要的程序库文件 
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。 
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。
  
保留选项 
-keep {Modifier} {class_specification}               保护指定的类文件和类的成员 
-keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification}     保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。 
-keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除) 
-keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除) 
-keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后) 
-printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件 
  
压缩 
-dontshrink    不压缩输入的类文件 
-printusage {filename} 
-whyareyoukeeping {class_specification}     
  
优化 
-dontoptimize    不优化输入的类文件 
-assumenosideeffects {class_specification}    优化时假设指定的方法,没有任何副作用 
-allowaccessmodification    优化时允许访问并修改有修饰符的类和类的成员 
  
混淆 
-dontobfuscate    不混淆输入的类文件 
-printmapping {filename} 
-applymapping {filename}                重用映射增加混淆 
-obfuscationdictionary {filename}        使用给定文件中的关键字作为要混淆方法的名称 
-overloadaggressively                  混淆时应用侵入式重载 
-useuniqueclassmembernames              确定统一的混淆类的成员名称来增加混淆 
-flattenpackagehierarchy {package_name}  重新包装所有重命名的包并放在给定的单一包中 
-repackageclass {package_name}          重新包装所有重命名的类文件中放在给定的单一包中 
-dontusemixedcaseclassnames             混淆时不会产生形形色色的类名 
-keepattributes {attribute_name,...}     保护给定的可选属性,例如LineNumberTable, LocalVariableTable,
                                    SourceFile, Deprecated, Synthetic, Signature, and 
  
InnerClasses. 
-renamesourcefileattribute {string}    设置源文件中给定的字符串常量

demo 实例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
-ignorewarnings                      # 忽略警告,避免打包时某些警告出现
-optimizationpasses5               # 指定代码的压缩级别
-dontusemixedcaseclassnames           # 是否使用大小写混合
-dontskipnonpubliclibraryclasses      # 是否混淆第三方jar
-dontpreverify                     # 混淆时是否做预校验
-verbose                          # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
  
-libraryjars   libs/treecore.jar
  
-dontwarn android.support.v4.**     #缺省proguard 会检查每一个引用是否正确,
                                但是第三方库里面往往有些不会用到的类,
                                没有正确引用。如果不配置的话,系统就会报错。
-dontwarn android.os.**
-keep classandroid.support.v4.** { *; }        # 保持哪些类不被混淆
-keep classcom.baidu.** { *; }  
-keep classvi.com.gdi.bgl.android.**{*;}
-keep classandroid.os.**{*;}
  
-keep interfaceandroid.support.v4.app.** { *; }  
-keep publicclass * extendsandroid.support.v4.**  
-keep publicclass * extendsandroid.app.Fragment
  
-keep publicclass * extendsandroid.app.Activity
-keep publicclass * extendsandroid.app.Application
-keep publicclass * extendsandroid.app.Service
-keep publicclass * extendsandroid.content.BroadcastReceiver
-keep publicclass * extendsandroid.content.ContentProvider
-keep publicclass * extendsandroid.support.v4.widget
-keep publicclass * extendscom.sqlcrypt.database
-keep publicclass * extendscom.sqlcrypt.database.sqlite
-keep publicclass * extendscom.treecore.**
-keep publicclass * extendsde.greenrobot.dao.**
  
  
-keepclasseswithmembernamesclass * {       # 保持native 方法不被混淆
    native<METHODS>;
}
  
-keepclasseswithmembersclass * {            # 保持自定义控件类不被混淆
    public<INIT>(android.content.Context, android.util.AttributeSet);
}
  
-keepclasseswithmembersclass * {            # 保持自定义控件类不被混淆
    public<INIT>(android.content.Context, android.util.AttributeSet,int);
}
  
-keepclassmembersclass * extends android.app.Activity {//保持类成员
   publicvoid *(android.view.View);
}
  
-keepclassmembersenum * {                  # 保持枚举enum 类不被混淆
    publicstatic **[] values();
    publicstatic ** valueOf(java.lang.String);
}
  
-keep class* implements android.os.Parcelable {    # 保持 Parcelable 不被混淆
  publicstatic final android.os.Parcelable$Creator *;
}
  
-keep classMyClass;                              # 保持自己定义的类不被混淆</INIT></INIT></METHODS>

3、文件

在release模式下打包apk时会自动运行ProGuard,这里的release模式指的是通过ant release命令或eclipse project->android tools->export signed(unsigned)
application package生成apk。
在debug模式下为了更快调试并不会调用proguard。

如果是ant命令打包apk,proguard信息文件会保存于/bin/proguard文件夹内;
如果用eclipse export命令打包,会在/proguard文件夹内。其中包含以下文件:

mapping.txt
表示混淆前后代码的对照表,这个文件非常重要。如果你的代码混淆后会产生bug的话,log提示中是混淆后的代码,希望定位到源代码的话就可以根据mapping.txt反推。
每次发布都要保留它方便该版本出现问题时调出日志进行排查,它可以根据版本号或是发布时间命名来保存或是放进代码版本控制中。

dump.txt
描述apk内所有class文件的内部结构。

seeds.txt
列出了没有被混淆的类和成员。

usage.txt
列出了源代码中被删除在apk中不存在的代码。

4、不能混淆的代码

顾名思义,不能混淆代码,否则会出错。

1、放射的地方

2、系统接口

3、Jni接口

4、

android.app.backup.BackupAgentHelper
android.preference.Preference

com.android.vending.licensing.ILicensingService

……

5、bug(常见错误)
1、Proguard returned with error code 1. See console

1、更新proguard版本
2、android-support-v4 不进行混淆

3、添加缺少相应的库

2、使用gson包解析数据时,出现missing type parameter异常

1、在 proguard.cfg中添加

?
1
2
-dontobfuscate
-dontoptimize

2、在 proguard.cfg中添加

?
1
2
3
4
5
6
7
8
9
10
11
# removes such information bydefault, so configure it to keep all of it.
-keepattributes Signature
  
  
# Gson specific classes
-keep classsun.misc.Unsafe { *; }
#-keep classcom.google.gson.stream.** { *; }
  
  
# Application classes that will be serialized/deserialized over Gson
-keep classcom.google.gson.examples.android.model.** { *; }

3、类型转换错误

-keepattributes Signature

4、空指针异常

混淆过滤掉相关类与方法

5、安卓代码混淆与反射冲突,地图无法显示等问题解决及反编译方法,安卓反编译

此前的代码混淆,因为并没有用到反射,所以常规的代码混淆方式一遍就能通过,而此项目中某些类利用到了反射机制(本人的这个项目中有即时通讯功能,所以有表情类资源,因此需要通过反射由文件名找到表情资源id),当由文件名去寻找资源id时就报空指针异常了,期初我并不知道什么原因,通过反编译已经混淆的apk,一步一步寻找到出错的地方,才恍然大悟,正是反射那一步出现了问题:Field field = R.drawable.class.getDeclaredField(name);走到这一步就挂了,程序直接崩溃。

解决办法:
1.在proguard.cfg文件中,将反射用到的类中的变量不被混淆:
如:-keep public class com.byl.bean.Expressions { *; },表示Expressions 这个类及类中的所有变量及方法不被混淆,注意要写全路径;
2.过滤泛型:-keepattributes Signature
3.最重要的一点:保持R文件不被混淆,否则,你的反射是获取不到资源id的:-keep class **.R$* {*;}

补充一下:上个问题解决后,接下来又遇到了一个问题就是混淆后,地图无法正常使用了,博主使用的是百度地图,在proguard.cfg也已经写明了:
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}

6、android.provider.Settings$Global

# Project target.
target=android-19

7、java.lang.reflect.UndeclaredThrowableException

-keep interface com.dev.impl.**

8、内存溢出和无法写入堆栈

javaOptions in proguard := Seq(...)
or
javaOptions in (Proguard, proguard) := Seq(...)

9、Error: Unable to access jarfile ..libproguard.jar

路径问题

10、java.lang.NoSuchMethodError

没有相关方法,方法被混淆了,混淆过滤掉相关方法便可。

Android proguard 详解(一)相关推荐

  1. android+proguard目录,Android Proguard 详解

    一般的商业项目都需要对代码进行加密,Android提供了一种代码混淆方法,介绍如下: 一.简介 1.简介 混淆器通过删除从未用过的代码和使用晦涩名字重命名类.字段和方法,对代码进行压缩,优化和混淆.结 ...

  2. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  3. Android菜单详解——理解android中的Menu

    前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...

  4. Android LayoutInflater详解

    Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类 似于findViewById().不同点是LayoutInflater是用来 ...

  5. android Fragments详解

    android Fragments详解一:概述 android Fragments详解二:创建Fragment 转载于:https://my.oschina.net/liangzhenghui/blo ...

  6. android WebView详解,常见漏洞详解和安全源码(下)

    上篇博客主要分析了 WebView 的详细使用,这篇来分析 WebView 的常见漏洞和使用的坑.  上篇:android WebView详解,常见漏洞详解和安全源码(上)  转载请注明出处:http ...

  7. android WebView详解,常见漏洞详解和安全源码(上)

    这篇博客主要来介绍 WebView 的相关使用方法,常见的几个漏洞,开发中可能遇到的坑和最后解决相应漏洞的源码,以及针对该源码的解析.  由于博客内容长度,这次将分为上下两篇,上篇详解 WebView ...

  8. android子视图无菜单,Android 菜单详解

    Android中菜单分为三种,选项菜单(OptionMenu),上下文菜单(ContextMenu),子菜单(SubMenu) 选项菜单 可以通过两种办法增加选项菜单,一是在menu.xml中添加,该 ...

  9. Android StateFlow详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121913352 本文出自[赵彦军的博客] 文章目录 系列文章 一.冷流还是热流 S ...

  10. Android SharedFlow详解

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/121911675 本文出自[赵彦军的博客] 文章目录 系列文章 什么是SharedF ...

最新文章

  1. Visual studio 2017基本配置
  2. RESTful设计原则和样例(开发前后台接口)
  3. 【Qt】简单QT文本编辑器
  4. 汇编语言练习_1_数字分解_显示
  5. 粒子网格算法 pm_使粒子网格与Blynk一起使用的2种最佳方法
  6. 从RGB到Lab色彩空间的转换
  7. JSP根据状态动态改变数据表格按钮
  8. 1024程序员节:心疼被段子手黑得最惨的你们
  9. ELK学习总结(3-2)elk的过滤查询
  10. linux下的c语言编程实验4,实验四-Linux下的C语言编程
  11. python2.7打印中文乱码的问题解决
  12. loadrunner录制脚本为空的情况
  13. 使用Simple Allow Copy插件在网页内复制文字
  14. android studio连接木木模拟器
  15. 北漂四年,25K,程序员,我依然单身!
  16. psutil:系统、进程,信息都在我的掌握之中
  17. 谷歌浏览器怎么关闭硬件加速?
  18. C++PrimePlus第5章编程练习答案及运行结果
  19. 总体设计--《软件工程导论》
  20. ?? 关于zmq_proxy

热门文章

  1. 个人配置环境和跑代码的一些坑
  2. 在线教育凛冬将至!强敌环伺的尚德机构,能否突出重围?
  3. Windows关机或重启显示有程序正在阻止、程序失去响应
  4. 数组unshift方法及重构
  5. 5G核心网技术基础自学系列 | 与EPC互通
  6. IT部门绩效考核管理思考
  7. 利用H5SVG实现线性动画效果
  8. vuex 状态管理模式 + 库(大仓库与小仓库)
  9. STM32F103实现OV7725拍照存储为BMP位图
  10. DC升压直流高压电源模块12V24v转100V150V200V250V300V350v1000伏线性变化电压控制输出