关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android Proguard 详解

    Android Proguard 详解

    2015-01-04 00:00:00 出处:zmit
    分享

    简介

    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 ..libproguard.jar

    路径问题

    10、java.lang.NoSuchMethodError

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

    11、专业网站bug解决方法

    http://proguard.sourceforge.net/index.html#manual/troubleshooting.html

    总结

    有了混淆技术,代码再也不用担心被偷了…

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    电脑屏幕不小心竖起来了?别慌,快捷键搞定

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    IT头条

    Synology 更新 ActiveProtect Manager 1.1 以增强企业网络弹性和合规性

    00:43

    新的 Rubrik Agent Cloud 加速了可信的企业 AI 代理部署

    00:34

    宇树科技 G1人形机器人,拉动一辆重达1.4吨的汽车

    00:21

    Cloudera 调查发现,96% 的企业已将 AI 集成到核心业务流程中,这表明 AI 已从竞争优势转变为强制性实践

    02:05

    投资者反对马斯克 1 万亿美元薪酬方案,要求重组特斯拉董事会

    01:18

    技术热点

    大型网站的 HTTPS 实践(三):基于协议和配置的优化

    ubuntu下右键菜单添加新建word、excel文档等快捷方式

    Sublime Text 简明教程

    用户定义SQL Server函数的描述

    怎么在windows 7开始菜单中添加下载选项?

    SQL Server 2016将有哪些功能改进?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。