android打包混淆-proguard配置详解

ProGuard是一个免费的java类文件压缩,优化,混淆器.它探测并删除没有使用的类,字段,方法和属性.它删除没有用的说明并使用字节码得到最大优化.它使用无意义的名字来重命名类,字段和方法.

 

ProGuard的作用: 
 
1.创建紧凑的代码文档是为了更快的网络传输,快速装载和更小的内存占用. 
2.创建的程序和程序库很难使用反向工程. 
3.所以它能删除来自源文件中的没有调用的代码 
4.充分利用java6的快速加载的优点来提前检测和返回java6中存在的类文件. 
 
参数: 
 
-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}    设置源文件中给定的字符串常量


Ant Example:

< !-- This Ant build file illustrates how to process applications,
     by including ProGuard-style configuration options.
     Usage: ant -f applications2.xml -->

< project name="Applications" default="obfuscate" basedir="../..">

< target name="obfuscate">
  <taskdef resource="proguard/ant/task.properties"
           classpath="lib/proguard.jar" />

  <proguard>

    <!-- Specify the input jars, output jars, and library jars. -->

    -injars  in.jar
    -outjars out.jar

    -libraryjars ${java.home}/lib/rt.jar
    <!-- -libraryjars junit.jar    -->
    <!-- -libraryjars servlet.jar  -->
    <!-- -libraryjars jai_core.jar -->
    <!-- ...                       -->

    <!-- Save the obfuscation mapping to a file, and preserve line numbers. -->

    -printmapping out.map
    -renamesourcefileattribute SourceFile
    -keepattributes SourceFile,LineNumberTable

    <!-- Preserve all annotations. -->

    -keepattributes *Annotation*

    <!-- Preserve all public applications. -->

    -keepclasseswithmembers public class * {
        public static void main(java.lang.String[]);
    }

    <!-- Preserve all native method names and the names of their classes. -->

    -keepclasseswithmembernames class * {
        native &lt;methods&gt;;
    }

    <!-- Preserve the methods that are required in all enumeration classes. -->

    -keepclassmembers class * extends java.lang.Enum {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }

    <!-- Explicitly preserve all serialization members. The Serializable
         interface is only a marker interface, so it wouldn't save them.
         You can comment this out if your library doesn't use serialization.
         If your code contains serializable classes that have to be backward
         compatible, please refer to the manual. -->

    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        static final java.io.ObjectStreamField[] serialPersistentFields;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }

    <!-- Your application may contain more items that need to be preserved;
         typically classes that are dynamically created using Class.forName -->

  </proguard>
< /target>

< /project>


下面几种情况是不能改变java 元素的名称,代码混淆的时候要注意保留,否则就会这样就会导致程序出错。

所以使用proguard时,我们需要有个配置文件告诉proguard哪些java 元素是不能被混淆的。

1。我们代码依赖于系统的接口,比如被系统代码调用的回调方法,这种情况最复杂。
2。我们的java 元素名称是在配置文件中配置好的。

常见的不能混淆的androidCode:

Android系统组件,系统组件有固定的方法被系统调用。
被Android Resource 文件引用到的。名字已经固定,也不能混淆,比如自定义的View 。
Android Parcelable ,需要使用android 序列化的。
其他Anroid 官方建议 不混淆的,如
android.app.backup.BackupAgentHelper
android.preference.Preference
com.android.vending.licensing.ILicensingService
Java序列化方法,系统序列化需要固定的方法。
枚举 ,系统需要处理枚举的固定方法。
本地方法,不能修改本地方法名
annotations 注释
数据库驱动
有些resource 文件
用到反射的地方

-optimizationpasses 5 
-dontusemixedcaseclassnames 
-dontskipnonpubliclibraryclasses 
-dontpreverify 
-verbose 
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 
-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 com.android.vending.licensing.ILicensingService 
-keepclasseswithmembernames class * { 
    native <methods>; 

-keepclasseswithmembernames class * { 
    public <init>(android.content.Context, android.util.AttributeSet); 

-keepclasseswithmembernames class * { 
    public <init>(android.content.Context, android.util.AttributeSet, int); 

-keepclassmembers enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 

-keep class * implements android.os.Parcelable { 
  public static final android.os.Parcelable$Creator *; 


proguard 问题和风险
代码混淆后虽然有混淆优化的好处,但是它往往也会带来如下的几点问题
1,混淆错误,用到第三方库的时候,必须告诉 proguard 不要检查,否则proguard 会报错。
2,运行错误,当code 不能混淆的时候,我们必须要正确配置,否则程序会运行出错,这种情况问题最多。
3,调试苦难,出错了,错误堆栈是混淆后的代码 ,自己也看不懂。


为了防止混淆出问题,你需要熟悉你所有的code ,系统的架构 ,以及系统和你code的集成的接口,并细心分析。 同时你必须需要一轮全面的测试。 所以混淆也还是有一定风险的。 为了避免风险,你可以只是混淆部分关键的代码,但是这样你的混淆的效果也会有所降低。


常见问题汇总:

1。Warning 类1 can't find referenced class 类2

需要使用-libraryjars标签指定引用库,然后对库中的类或者接口做keep、dontwarn处理。

很多时候我们只需要打乱自己的代码就行了,第三方包的代码就是否要打乱就不要管了。

例如:

有引用android-support-v4.jar的工程,混淆配置:

-libraryjars /android-support-v4.jar 
-dontwarn android.support.v4.** 
-keep class android.support.v4.** { *; } 
-keep public class * extends android.support.v4.** 
-keep public class * extends android.app.Fragment 

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

2。can't find superclass or interface android.os.Parcelable$ClassLoaderCreator,碰到这样的情况,可以使用-dontwarn com.xx.yy.**,不对错误提出警告。
注意:使用这个方式的话,要确保自己没有用到这个库里面的类!否则就会抛ClassNotFoundException!

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

-dontwarn com.xx.bbb.**

-keep class com.xx.bbb.** { *;}

-libraryjars ./libs/ormlite-core-4.48.jar

#指定不显示警告的包名

#缺省proguard 会检查每一个引用是否正确,但是第三方库里面往往有些不会用到的类。如果不配置的话,系统就会报错。

-dontwarn com.j256.ormlite.**

-dontwarn android.support.v4.**

#指定不混淆的类

-keep class com.j256.ormlite.**{*;}

-keep class android.support.v4.**{*;}

-keep class com.j256.**

-keepclassmembers class com.j256.** {*;}

#指定不混淆的枚举

-keep enum com.j256.**

#指定不混淆的接口

-keep interface com.j256.**

更多案例请参考:

Android中proguard混淆第三方jar包及内部类

http://blog.youkuaiyun.com/lichuanzhi7909/article/details/9834727

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值