简介

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

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

官网地址:http://proguard.sourceforge.net/

原理

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

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

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

语法


-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}
-dontwarn   如果有警告也不终止
-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}    设置源文件中给定的字符串常量

Android Eclipse开发环境与ProGuard

在Android 2.3以前,混淆Android代码只能手动添加proguard来实现代码混淆,非常不方便。而2.3以后,Google已经将这个工具加入到了SDK的工具集里。具体路径:SDK\tools\proguard。当创建一个新的Android工程时,在工程目录的根路径下,会出现一个proguard的配置文件proguard.cfg。也就是说,我们可以通过简单的配置,在我们的elipse工程中直接使用ProGuard混淆Android工程。

具体混淆的步骤非常简单。首先,我们需要在工程描述文件project.properties中,添加一句话,启用ProGuard。如下所示:


# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt# Project target.
target=android-19

这样,Proguard就可以使用了。当我们正常通过Android Tools导出Application Package时(或者使用ant执行release打包),Proguard就会自动启用,优化混淆你的代码。

导出成功后,你可以反编译看看混淆的效果。一些类名、方法名和变量名等,都变成了一些无意义的字母或者数字。证明混淆成功!

实例(proguard 文件代码解读)

-optimizationpasses 7  #指定代码的压缩级别 0 - 7
-dontusemixedcaseclassnames  #是否使用大小写混合
-dontskipnonpubliclibraryclasses  #如果应用程序引入的有jar包,并且想混淆jar包里面的class
-dontpreverify  #混淆时是否做预校验(可去掉加快混淆速度)
-verbose #混淆时是否记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  #淆采用的算法
-keep public class * extends android.app.Activity  #所有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 #指定具体类不要去混淆
-keepclasseswithmembernames class * {native <methods>;  #保持 native 的方法不去混淆
}-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); #保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)
}-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*(...);
}-keepclassmembers enum * {  #保持枚举 enum 不被混淆public static **[] values();public static ** valueOf(java.lang.String);
}-keep class * implements android.os.Parcelable {  #保持 Parcelable 不被混淆(aidl文件不能去混淆)public static final android.os.Parcelable$Creator *;
}-keepnames class * implements java.io.Serializable #需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepclassmembers class * implements java.io.Serializable { #保护实现接口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();
}-keepattributes Signature  #过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了)-keepattributes *Annotation*  #假如项目中有用到注解,应加入这行配置-keep class **.R$* { *; }  #保持R文件不被混淆,否则,你的反射是获取不到资源id的-keep class **.Webview2JsInterface { *; }  #保护WebView对HTML页面的API不被混淆
-keepclassmembers class * extends android.webkit.WebViewClient {  #如果你的项目中用到了webview的复杂操作 ,最好加入public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);public boolean *(android.webkit.WebView,java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebChromeClient {  #如果你的项目中用到了webview的复杂操作 ,最好加入public void *(android.webkit.WebView,java.lang.String);
}
#对WebView的简单说明下:经过实战检验,做腾讯QQ登录,如果引用他们提供的jar,若不加防止WebChromeClient混淆的代码,oauth认证无法回调,反编译基代码后可看到他们有用到WebChromeClient,加入此代码即可。-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; }  #转换JSON的JavaBean,类成员名称保护,使其不被混淆##################################################################
# 下面都是项目中引入的第三方 jar 包。第三方 jar 包中的代码不是我们的目标和关心的对象,故而对此我们全部忽略不进行混淆。
##################################################################
-libraryjars  libs/android-support-v4.jar
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.app.Fragment
-libraryjars libs/gson-2.3.1-sources.jar
-libraryjars libs/gson-2.3.1.jar
-dontwarn com.google.gson.**
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.** { *; }-libraryjars libs/alipaySDK-20150602.jar
-dontwarn com.alipay.**
-dontwarn com.ta.utdid2.**
-dontwarn com.ut.device.**
-keep class com.alipay.** { *; }
-keep class com.ta.utdid2.** { *; }
-keep class com.ut.device.** { *; }-libraryjars libs/android-async-http-1.4.6.jar
-dontwarn com.loopj.android.http.**
-keep class com.loopj.android.http.** { *; }-libraryjars libs/baidumapapi_v2_4_1.jar
-dontwarn com.baidu.**
-keep class com.baidu.** {*; }
-keep class assets.** {*; }
-keep class vi.com.gdi.bgl.** {*; }-libraryjars libs/libammsdk.jar
-dontwarn com.tencent.**
-keep class com.tencent.** { *; }-libraryjars libs/locSDK_4.1.jar
-dontwarn com.baidu.location.**
-keep class com.baidu.location.** { *; }-libraryjars libs/mframework.jar
-dontwarn m.framework.**
-keep class m.framework.** { *; }-libraryjars libs/mta-sdk-1.6.2.jar
-dontwarn com.tencent.stat.**
-keep class com.tencent.stat.** { *; }-libraryjars libs/nineoldandroids-library-2.4.0.jar
-dontwarn com.nineoldandroids.**
-keep class com.nineoldandroids.** { *; }-libraryjars libs/open_sdk_r4889.jar
-dontwarn com.tencent.**
-keep class com.tencent.** { *; } -libraryjars libs/ShareSDK-Core-2.5.9.jar
-dontwarn cn.sharesdk.framework.**
-keep class cn.sharesdk.framework.** { *; } -libraryjars libs/ShareSDK-ShortMessage-2.5.9.jar
-dontwarn cn.sharesdk.system.text.**
-keep class cn.sharesdk.system.text.** { *; } -libraryjars libs/ShareSDK-SinaWeibo-2.5.9.jar
-dontwarn cn.sharesdk.sina.weibo.**
-keep class cn.sharesdk.sina.weibo.** { *; } -libraryjars libs/ShareSDK-Wechat-2.5.9.jar
-dontwarn cn.sharesdk.wechat.friends.**
-keep class cn.sharesdk.wechat.friends.** { *; } -libraryjars libs/ShareSDK-Wechat-Core-2.5.9.jar
-dontwarn cn.sharesdk.wechat.utils.**
-keep class cn.sharesdk.wechat.utils.** { *; } -libraryjars libs/ShareSDK-Wechat-Favorite-2.5.9.jar
-dontwarn cn.sharesdk.wechat.favorite.**
-keep class cn.sharesdk.wechat.favorite.** { *; } -libraryjars libs/ShareSDK-Wechat-Moments-2.5.9.jar
-dontwarn cn.sharesdk.wechat.moments.**
-keep class cn.sharesdk.wechat.moments.** { *; } -libraryjars libs/universal-image-loader-1.9.2-SNAPSHOT-with-sources.jar
-dontwarn com.nostra13.universalimageloader.**
-keep class com.nostra13.universalimageloader.** { *; } -libraryjars libs/weibosdkcore.jar
-dontwarn com.sina.weibo.sdk.**
-keep class com.sina.weibo.sdk.** { *; }

关于如何配置忽略第三方jar,附上一个图进行说明。

说明一下,第三方jar包中如果有.so文件,不用去理会,引入的第三方jar文件不要混淆,否则可能会报异常。

文件

在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中不存在的代码。

不能混淆的代码

顾名思义,不能混淆代码如果被混淆了,就会出现错误。

1、需要反射的代码

2、系统接口

3、Jni接口

4、需要序列号和反序列化的代码(即实现Serializable接口的JavaBean)

5、与服务端进行元数据交互的JavaBean(JSON、XML中对应的类)

……

常见错误

1) Proguard returned with error code 1. See console

> 更新proguard版本
  > android-support-v4 不进行混淆
  > 添加缺少相应的库

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

> 在 proguard-project.txt 中添加
    -dontobfuscate
    -dontoptimize
  > 在 proguard-project.txt 中添加
    # 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) 类型转换错误

> 在 proguard-project.txt 中添加
    -keepattributes Signature

4) 空指针异常

> 混淆过滤掉相关类与方法

5) java.lang.reflect.UndeclaredThrowableException

> -keep interface com.dev.impl.**

6) Error: Unable to access jarfile ..libproguard.jar

> 路径问题

7) java.lang.NoSuchMethodError

> 这也是最常见的问题,因为找不到相关方法,方法被混淆了,混淆过滤掉相关方法便可。

----------------------

(完)

---------------------

原文:https://yq.aliyun.com/articles/1328

版权声明:本文为作者原创文章,转载请附上博文链接!

[转]Android 项目的代码混淆,Android proguard 使用说明相关推荐

  1. java war包混淆,spring项目的代码混淆(proguard)

    前不久被要求对java web的war包做代码混淆,我使用proguard6.0.3完成的.后面也许还会用到,因此记录下过程和配置方法,demo代码按照图1结构进行组织.仅对混淆功能进行说明,其他功能 ...

  2. android 常用混淆,Android常用的代码混淆整理【原创】

    android里的代码混淆是比不可少的东西,下面就贴一些常用的代码混淆. #指定代码的压缩级别 -optimizationpasses 5 #包明不混合大小写 -dontusemixedcasecla ...

  3. android方法不混淆,android app进行代码混淆实例详解

    接到一个新的任务,对现有项目进行代码混淆.之前对混淆有过一些了解,但是不够详细和完整,知道有些东西混淆起来还是比较棘手的.不过幸好目前的项目不是太复杂(针对混淆这块来说),提前完成--现总结之. 第一 ...

  4. Java代码混淆工具ProGuard

    目录 Java代码混淆工具ProGuard 简介 描述 作用的环境 功能 工作原理 下载 使用时注意事项 版本问题 JDK位数问题 Java的字节码验证问题 关于使用类似于Hibernate的对象关系 ...

  5. 视频教程-Android 项目实战-影讯-Android

    Android 项目实战-影讯 1999年开始从事开发工作,具备十余年的开发.管理和培训经验. 在无线通信.Android.iOS.HTML5.游戏开发.JavaME.JavaEE.Linux等领域都 ...

  6. Android代码混淆工具Proguard学习

    概述 Proguard代码混淆工具:可以对代码进行去冗余压缩,代码优化,代码混淆等.在Android中的主要应用就是对代码混淆:就是将类名,方法名,Field名变成如a,b,c或者1,2,3等难以阅读 ...

  7. android代码混淆作用,Android分享:代码混淆那些事

    1) 前言 ProGuard是一个开源的Java代码混淆器.它可以混淆Android项目里面的java代码,对的,你没看错,仅仅是java代码.它是无法混淆Native代码,资源文件drawable. ...

  8. android默认代码混淆,Android SDK默认混淆配置文件

    一.介绍 通常情况下编译后的字节码包含了大量调试信息(如源类名/行号等) 混淆代码就能删除这些调试信息,并用无意义字符替换所有名字,增加反编译难度! ProGuard是一个混淆代码的开源项目,主要作用 ...

  9. 读懂Android中的代码混淆

    本文为本人的一些实践总结,介绍一些混淆的知识和注意事项.希望可以帮助大家更好的学习和使用代码混淆. 什么是混淆 关于混淆维基百科上该词条的解释为 代码混淆(Obfuscated code)亦称花指令, ...

最新文章

  1. 寻找两个正序数组的中位数——冒泡排序(归并排序)
  2. IE下ajax响应慢,IE9上的Jquery Ajax调用非常慢,但在IE9中非常快
  3. 树莓派 Ubuntu mate 18.04 修改为清华源
  4. Linux系统下ifconfig命令使用及结果分析
  5. 刚刚,Redis公布了5.0版本12项新特性
  6. 基于C#net4.5websocket客户端与服务端
  7. 免费文字识别软件有哪些?分享三款不错的软件
  8. matlab脉冲压缩,雷达线性调频脉冲压缩的原理及其matlab仿真
  9. Go适合做什么?为何这么多人偏爱Go语言?
  10. 照相机和眼睛成像的基本原理
  11. 网页游戏是如何快速推广,寻找真实玩家。提高充值消费的。这里都有教程
  12. gram矩阵的性质_矩阵分析(九)Gram矩阵
  13. android 百度地图获取两个坐标的实际路线距离
  14. Android中的适配
  15. php artisan命令表,php artisan 命令列表
  16. Spring IoC容器:BeanFactory和ApplicationContext
  17. MySQL 启停过程了解一二
  18. proteus实现电子钟计时
  19. C4D模型工具—细分
  20. 自动驾驶 l5 ai_强AI和弱AI的真实故事以及适用于自动驾驶汽车的信息

热门文章

  1. 纯JDBC系统的开发随想
  2. 介绍这个库:C# Blazor中显示Markdown文件
  3. NET框架下如何使用PaddleOCRSharp
  4. Hello Blazor:(9)Source Generators生成导航菜单
  5. Source Generators实现简版AutoMapper
  6. Dotnet Core应用跨框架版本运行
  7. 微软发布 Windows 10 预览版 Build 21343:此电脑和回收站等启用全新图标
  8. 跟我一起学Redis之加个哨兵让主从复制更加高可用
  9. Dapr微服务应用开发系列2:Hello World与SDK初接触
  10. 如何使用 C# 中的 HashSet