Android proguard 详解
本文转载于:http://blog.csdn.net/banketree/article/details/41928175
简介
Java代码是非常容易反编译的。为了很好的保护Java源代码,我们往往会对编译好的class文件进行混淆处理。
ProGuard是一个混淆代码的开源项目。它的主要作用就是混淆,当然它还能对字节码进行缩减体积、优化等,但那些对于我们来说都算是次要的功能。官网网址是:
http://proguard.sourceforge.net/。
详解
1、原理
Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。
混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。
混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar 文件体积大约能减少25% ,这对当前费用较贵的无线网络传输是有一定意义的。
2、语法
- -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 实例
- -ignorewarnings # 忽略警告,避免打包时某些警告出现
- -optimizationpasses 5 # 指定代码的压缩级别
- -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 class android.support.v4.** { *; } # 保持哪些类不被混淆
- -keep class com.baidu.** { *; }
- -keep class vi.com.gdi.bgl.android.**{*;}
- -keep class android.os.**{*;}
- -keep interface android.support.v4.app.** { *; }
- -keep public class * extends android.support.v4.**
- -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.support.v4.widget
- -keep public class * extends com.sqlcrypt.database
- -keep public class * extends com.sqlcrypt.database.sqlite
- -keep public class * extends com.treecore.**
- -keep public class * extends de.greenrobot.dao.**
- -keepclasseswithmembernames class * { # 保持 native 方法不被混淆
- native <methods>;
- }
- -keepclasseswithmembers class * { # 保持自定义控件类不被混淆
- public <init>(android.content.Context, android.util.AttributeSet);
- }
- -keepclasseswithmembers class * { # 保持自定义控件类不被混淆
- public <init>(android.content.Context, android.util.AttributeSet, int);
- }
- -keepclassmembers class * extends android.app.Activity { //保持类成员
- public void *(android.view.View);
- }
- -keepclassmembers enum * { # 保持枚举 enum 类不被混淆
- public static **[] values();
- public static ** valueOf(java.lang.String);
- }
- -keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
- public static final android.os.Parcelable$Creator *;
- }
- -keep class MyClass; # 保持自己定义的类不被混淆
3、文件
在release模式下打包apk时会自动运行ProGuard,这里的release模式指的是通过ant release命令或eclipse project->android tools->export signed(unsigned)
application package生成apk。
在debug模式下为了更快调试并不会调用proguard。
如果是ant命令打包apk,proguard信息文件会保存于<project_root>/bin/proguard文件夹内;
如果用eclipse export命令打包,会在<project_root>/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中添加
- -dontobfuscate
- -dontoptimize
2、在 proguard.cfg中添加
- # removes such information by default, so configure it to keep all of it.
- -keepattributes Signature
- # 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.** { *; }
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 ..\lib\proguard.jar
路径问题
10、java.lang.NoSuchMethodError
没有相关方法,方法被混淆了,混淆过滤掉相关方法便可。
11、专业网站bug解决方法
http://proguard.sourceforge.net/index.html#manual/troubleshooting.html
总结
有了混淆技术,代码再也不用担心被偷了…
Android proguard 详解的更多相关文章
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Android ActionBar详解
Android ActionBar详解 分类: Android2014-04-30 15:23 1094人阅读 评论(0) 收藏 举报 androidActionBar 目录(?)[+] 第4 ...
- Android 签名详解
Android 签名详解 AndroidOPhoneAnt设计模式Eclipse 在Android 系统中,所有安装 到 系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程 ...
- Android编译系统详解(一)
++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/art ...
- Android布局详解之一:FrameLayout
原创文章,如有转载,请注明出处:http://blog.csdn.net/yihui823/article/details/6702273 FrameLayout是最简单的布局了.所有放在布局里的 ...
- 【整理修订】Android.mk详解
Android.mk详解 1. Android.mk 的应用范围 Android.mk文件是GNU Makefile的一小部分,它用来对Android程序进行编译. 一个Android.mk文件可以编 ...
- Android菜单详解(四)——使用上下文菜单ContextMenu
之前在<Android菜单详解(二)——创建并响应选项菜单>和<Android菜单详解(三)——SubMenu和IconMenu>中详细讲解了选项菜单,子菜单和图标菜单.今天接 ...
- Android签名详解(debug和release)
Android签名详解(debug和release) 1. 为什么要签名 1) 发送者的身份认证 由于开发商可能通过使用相同的Package Name来混淆替换已经安装的程序,以此保证签名不同的包 ...
随机推荐
- dos2unix
dos2unix 实际上就是把文本文件里面的^M删除,我一般懒得用这个命令,vi里面用一个命令(:%s/^m//g)删除即可. 用法举例: dos2unix a.txt b.txt 要把一批文件都do ...
- css3--布局正六边形
怎样布局正六边形?-->如果不能直接布局,就只能采用图形的组合.-->既然是正六边形,则: -->AB=2分之根号3乘2倍的边长,也就是对于矩形ABCD来说,AB是BD的根号3倍(也 ...
- cocos2d-x 常用UI
CCSprite* sprite = CCSprite::create("CloseNormal.png"); sprite->setPosition(ccp(50, 50) ...
- Math.abs(~2018),掌握规律即可!
Math.abs(~2018) 某前端群的入门问题长姿势了,一个简单的入门问题却引发了我的思考,深深的体会到自己在学习前端技术的同时忽略遗忘了一些计算机的基础知识. 对于 JS Math对象没什么可说 ...
- 3dsMax用到的网格优化
3dsMax软件主要是用于建模的,里面有一个网格优化的功能,它的网格优化的过程是基于那个网格简化算法,经过使用个人认为是基于几何删除的折叠方式来进行的,可能是边折叠或者三角折叠的方式,还望大神多多指教 ...
- Java集合与算法
梗概: 集合接口 集合实现(链表.数组列表.散列集.树集.队列与双端队列.映射表) 集合与数组之间的转换 算法(排序.二分查找). 文章链接: http://mp.weixin.qq.com/s?__ ...
- C语言状态机
转载声明 如果转载本博客内容,请联系869119842@qq.com,获得作者书面授权 前言 状态机的好处不用多说,自己百度去,但传统的编程模式,无论是C语言,或是硬件FPGA的Verilog都是采用 ...
- Ubuntu 手工挂载硬盘
首先我们得到到/dev/sda3这个分区的UUID,使用以下命令: sudo blkid /dev/sda3 结果如下: 然后,我们按照/etc/fstab文件中的格式添加一行如下内容: UUID=9 ...
- javascript之小积累-匿名函数表达式的最佳实践
在写js的时候,还是经常会用的匿名函数表达式,比如 setTimeout(function() { console.log(110); }, 1000); 上面那个function()就是匿名函数表达 ...
- re.S
在Python的正则表达式中,有一个参数为re.S.它表示多行匹配