前言
自己用了段时间,由于个人能力有限,因此,我这里就不说原理了,我就说说我个人用的时候的感受吧;作用
个人感受吧:①在未使用proguard的时候,APK文件能达到很大,使用之后APK文件会变得很小;
②有些类,你必须在proguard进行配置,否则的话,该类对应的class文件除了构造方法,别的方法都没了;
③你在类里面定义的内部类会给你提取出来形成一个单独的类;
混淆的原则
我曾经对外提供过jar文件来供对方调用我提供的服务,在该jar文件混淆的时候,除了对外暴露的类、方法、回调的接口,别的类全部混淆了,另外还有一些固定类名的String变量,这些变量记录着某些类的路径,这些变量通常用于反射,个人总结如下,以便参考吧:
①你需要熟悉你所有的code,系统的架构以及系统和你code的集成的接口并细心分析,这是基础,我在混淆jar的时候一次完成,因为这个jar从设计到实现都是我一个人完成的;
②用到反射的地方;
③Android API的接口、方法、类,最常见的就是不能混淆四大组件及其回调方法;
④混淆错误,用到第三方库的时候,必须告诉proguard不要检查,否则proguard会报错;
⑤调试苦难,哎,这就不多说了,蛋疼;
常用配置
Android系统组件及其固定的方法,这里一般用-keep;被Android Resource文件引用到的,名字已经固定,也不能混淆,比如自定义的View;
Android Parcelable不能混淆;
其他Anroid官方建议不混淆的,如
android.app.backup.BackupAgentHelper
android.preference.Preference
com.android.vending.licensing.ILicensingService
Java序列化方法,系统序列化需要固定的方法。
枚举 ,系统需要处理枚举的固定方法。
本地方法,不能修改本地方法名
annotations 注释
数据库驱动
有些resource 文件
用到反射的地方
配置选项
这里也是我从网上搜的一些语法,大家就参考看看吧-keep {Modifier} {class_specification} 指定的类及其类成员被保留,这里直接把类、成员变量、成员方法等全部被保留
-keepclassmembers {modifier} {class_specification} 对指定的类的特定成员被保留,这里强调的是成员变量、成员方法
-keepclasseswithmembers {class_specification} 对指定的类、类成员被保留
-dontwarn proguard默认会检查每一个引用是否正确,这样太严格了,例如:第三方库里面往往有些不会用到的类没有正确引用。如果不配置的话,系统就会报错
-include {filename} 从给定的文件中读取配置参数
-basedirectory {directoryname} 指定基础目录为以后相对的档案名称
-injars {class_path} 将要被混淆的文件的绝对路径,如果你想混淆jar文件的话,会用到这个属性,APK混淆一般用不到
-outjars {class_path} 混淆后的文件生成的绝对路径,与injars对应 ,如果你想混淆jar文件的话,会用到这个属性,APK混淆一般用不到
-libraryjars {classpath} 指定要处理的应用程序、jar、目录等所需要的程序库文件,如果你引用的第三方类库没有在这里配置,那么,你通过extends第三方类的子类只剩下构造方法,别的方法都会略去;
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。
-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} 设置源文件中给定的字符串常量
-dontshrink 关闭压缩
默认开启,用以减小应用体积,移除未被使用的类和成员,
并且会在优化动作执行之后再次执行(因为优化后可能会再次暴露一些未被使用的类和成员)
-dontoptimize 关闭优化
-optimizationpasses n 表示proguard对代码进行迭代优化的次数,Android一般为5
默认开启,在字节码级别执行优化,让应用运行的更快
-dontobfuscate 关闭混淆
默认开启,增大反编译难度,类和类成员会被随机命名,除非用keep保护。
-keep class com.XXX.activity.**
-keep class com.XXX.activity.*
一颗星表示只是保持该包下的类名,而子包下的类名还是会被混淆;两颗星表示把本包和所含子包下的类名都保持;
用以上方法保持类后,你会发现类名虽然未混淆,但里面的具体方法和变量命名还是变了,
这时如果既想保持类名,又想保持里面的内容不被混淆,我们就需要以下方法了
-keep class com.XXX.activity.* {*;}
如果我们要保留一个类中的内部类不被混淆则需要用$符号
-keepclassmembers class com.XXX.activity.MainFragment$ClickInterface {
public *;
}
含义就是:MainFragment内部接口ClickInterface里面的所有public修饰的内容不会混淆
再者,如果一个类中你不希望保持全部内容不被混淆,而只是希望保护类下的特定内容,就可以使用
<init>; //匹配所有构造器
<fields>; //匹配所有域
<methods>; //匹配所有方法方法
你还可以在<fields>或<methods>前面加上private 、public、native等来进一步指定不被混淆的内容,如
-keep class cn.hadcn.test.One {
public <methods>;
}
配置实例
-injars androidtest.jar【jar包所在地址】-outjars out【输出地址】
-libraryjars 'D:\android-sdk-windows\platforms\android-9\android.jar' 【引用的库的jar,用于解析injars所指定的jar类】
-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 * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keep public abstract interface com.asqw.android.Listener{
public protected <methods>; 【所有方法不进行混淆】
}
-keep public class com.asqw.android{
public void Start(java.lang.String); 【对该方法不进行混淆】
}
-keepclasseswithmembernames class * { 【保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)】
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 * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {【保护指定的类文件和类的成员】
public static final android.os.Parcelable$Creator *;
}
//不混淆指定包下的类
-keep class com.aspire.**