Android Studio实现代码混淆

时间:2023-03-08 17:43:57
 1,在build.grandle添加,其中规则写在proguard-rules.pro中,也可以自定义一个文件,将其代替,比如eclipse常用的 proguard-project.txt:
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true # 设置是否进行 shrink 等操作(即无用代码压缩),一般设置为 true,使混淆更有效
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
}
}

2,在proguard-rules.pro中加入以下代码,基本可以涵盖所有:

-optimizationpasses           # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-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 # 保持哪些类不被混淆 -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 *;
}

3,通过 Android Studio进行 混淆代码时,默认已经将 lib目录中的 jar 都已经添加到打包脚本中,所以不需要再次手动添加,否则会出现“ java.io.IOException: The same input jar is specified twice” 错误。

推荐将你所有引用的库(在 app/build.gradle 里)全部不混淆,里面的groupid就是package,将package加入就行了,这是我的示例:

-keep class org.greenrobot.greendao.** { *; }
-dontwarn org.greenrobot.greendao.**
-keep class com.jakewharton.** { *; }
-dontwarn com.jakewharton.**
-keep class io.reactivex.** { *; }
-dontwarn io.reactivex.**
-keep class org.jsoup.** { *; }
-dontwarn org.jsoup.**
-keep class com.squareup.retrofit2.** { *; }
-dontwarn com.squareup.retrofit2.**
-keep class com.scottyab.** { *; }
-dontwarn com.scottyab.**
-keep class com.pddstudio.preferences.encrypted.** { *; }
-dontwarn com.pddstudio.preferences.encrypted.**

忽略了所有库,如果还报警,可以把报警的也全部忽略。

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

ProGuard默认会对第三方库也进行混淆的,而第三方库有的已经混淆过了,有的使用了Java反射技术,所以我们在进行代码混淆的时候要排除这些第三方库。排除对第三方库的混淆需要在混淆规则文件(通常是:proguard-project.txt或proguard.cfg或proguard-rules.pro或proguard-rules.txt也可以是其它的文件名只要在配置文件中将含有混淆规则的文件名配置进去就行了)中添加如下规则:

1.如果使用了Gson之类的工具要使JavaBean类即实体类不被混淆。

2.如果使用了自定义控件那么要保证它们不参与混淆。

3.如果使用了枚举要保证枚举不被混淆。

4.对第三方库中的类不进行混淆

a.混淆时保护引用的第三方jar包

如:-libraryjars libs/baidumapapi_v3_2_0.jar  #保护引用的第三方jar包不被混淆

注意:在使用Eclipse+ADT时需要加入-libraryjars libs/...,如果你是使用Android Studio开发的项目则不需要加入libs包中的jar包,这是因为,通过Android Studio进行混淆代码时,默认已经将 lib目录中的 jar 都已经添加到打包脚本中,所以不需要再次手动添加,否则会出现“ java.io.IOException: The same input jar is specified twice” 错误。

b.混淆时保护第三方jar包中的类不被混淆

如:-keep class com.baidu.** { *; }         #保持com.baidu.**这个包里面的所有类和所有方法不被混淆。

-dontwarn com.baidu.**          #让ProGuard不要警告找不到com.baidu.**这个包里面的类的相关引用

附:下面是开发中用到的一些混淆规则,大家可以根据需要复制到自己的项目中的混淆规则的文件中:

################common###############
-keep class com.jph.android.entity.** { *; } #实体类不参与混淆
-keep class com.jph.android.view.** { *; } #自定义控件不参与混淆 ################baidu map###############
-libraryjars libs/baidumapapi_v3_2_0.jar
-libraryjars libs/locSDK_5..jar
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
-dontwarn com.baidu.** ################afinal##################
#-libraryjars libs/afinal_0.5_bin.jar
#-keep class net.tsz.afinal.** { *; }
#-keep public class * extends net.tsz.afinal.**
#-keep public interface net.tsz.afinal.** {*;}
#-dontwarn net.tsz.afinal.** ################xutils##################
-libraryjars libs/xUtils-2.6..jar
-keep class com.lidroid.xutils.** { *; }
-keep public class * extends com.lidroid.xutils.**
-keepattributes Signature
-keepattributes *Annotation*
-keep public interface com.lidroid.xutils.** {*;}
-dontwarn com.lidroid.xutils.**
-keepclasseswithmembers class com.jph.android.entity.** {
<fields>;
<methods>;
} ################支付宝##################
-libraryjars libs/alipaysecsdk.jar
-libraryjars libs/alipayutdid.jar
-libraryjars libs/alipaysdk.jar
-keep class com.alipay.android.app.IAliPay{*;}
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.lib.ResourceMap{*;} ################gson##################
-libraryjars libs/gson-2.2..jar
-keep class com.google.gson.** {*;}
#-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.** {
<fields>;
<methods>;
}
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private 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();
}
-dontwarn com.google.gson.** ################httpmime/httpcore##########
-libraryjars libs/httpcore-4.3..jar
-libraryjars libs/httpmime-4.3..jar
-keep class org.apache.http.** {*;}
-dontwarn org.apache.http.** ####################jpush##################
-libraryjars libs/jpush-sdk-release1.7.1.jar
-keep class cn.jpush.** { *; }
-keep public class com.umeng.fb.ui.ThreadView { } #双向反馈功能代码不混淆
-dontwarn cn.jpush.**
-keepclassmembers class * {
public <init>(org.json.JSONObject);
}
#不混淆R类
-keep public class com.jph.android.R$*{
public static final int *;
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
} ####################umeng##################
-libraryjars libs/umeng-analytics-v5.2.4.jar
-keep class com.umeng.analytics.** {*;}
-dontwarn com.umeng.analytics.** #-keep public class * extends com.umeng.**
#-keep public class * extends com.umeng.analytics.**
#-keep public class * extends com.umeng.common.**
#-keep public class * extends com.umeng.newxp.**
-keep class com.umeng.** { *; }
-keep class com.umeng.analytics.** { *; }
-keep class com.umeng.common.** { *; }
-keep class com.umeng.newxp.** { *; } -keepclassmembers class * {
public <init>(org.json.JSONObject);
}
-keep class com.umeng.** -keep public class com.idea.fifaalarmclock.app.R$*{
public static final int *;
} -keep public class com.umeng.fb.ui.ThreadView {
} -dontwarn com.umeng.** -dontwarn org.apache.commons.** -keep public class * extends com.umeng.** -keep class com.umeng.** {*; } ####################universal-image-loader########
-libraryjars libs/universal-image-loader-1.9..jar
-keep class com.nostra13.universalimageloader.** {*;}
-dontwarn com.nostra13.universalimageloader.** ####################zxing#####################
-libraryjars libs/zxing.jar
-libraryjars libs/zxing_apply.jar
-keep class com.google.zxing.** {*;}
-dontwarn com.google.zxing.** ####################BASE64Decoder##################
-libraryjars libs/sun.misc.BASE64Decoder.jar ####################support.v4#####################
-libraryjars libs/android-support-v4.jar
-keep class android.support.v4.** { *; }
-dontwarn android.support.v4.** ###################other####################
# slidingmenu 的混淆
-dontwarn com.jeremyfeinstein.slidingmenu.lib.**
-keep class com.jeremyfeinstein.slidingmenu.lib.** { *; }
# ActionBarSherlock混淆
-dontwarn com.actionbarsherlock.**
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keep class * extends java.lang.annotation.Annotation { *; }
-keepclasseswithmembernames class * {
native <methods>;
} -keep class com.jph.android.entity.** {
<fields>;
<methods>;
} -dontwarn android.support.**
-dontwarn com.slidingmenu.lib.app.SlidingMapActivity
-keep class android.support.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keep class com.slidingmenu.** { *; }
-keep interface com.slidingmenu.** { *; }

如果打包的时候出现警告:can't find referenced class  怎么办?解决方案如下:

1. 问题的产生原因

"类1 can't find referenced class 类2" 字面上的意思就是类1找不到类2的引用;接着再看下去"You may need to specify additional library jars (using '-libraryjars').";

噢,原来这么简单呀,他说我需要使用-libraryjars加上项目中使用到的第三方库就OK了。好!马上把"-libraryjars ./libs/xx.jar"这段代码加入到proguard.cfg配置文件里面去,
再export一次!一分钟过后,靠!同样的错误提示又来了:

  1. Warning: com.xxx.bbbb.F.H$3: can't find referenced class com.xxx.bbbb..F.H$com.xxx.bbbb.F.H$_B
  2. Warning: there were 1 unresolved references to classes or interfaces.
  3. You may need to specify additional library jars (using '-libraryjars').
  4. java.io.IOException: Please correct the above warnings first.
  5. at proguard.Initializer.execute(Initializer.java:321)
  6. at proguard.ProGuard.initialize(ProGuard.java:211)
  7. at proguard.ProGuard.execute(ProGuard.java:86)
  8. at proguard.ProGuard.main(ProGuard.java:492)

这不是坑爹吗?还报错!我以为是顺序不对,把-libraryjars ./libs/xx.jar这句话放到最开头,或者在keep...语句的开头,结果很悲催,也不行。马上看看官方文档的Troubleshooting,发现有说到这个问题后,大喜!我们一起去瞧瞧他怎么说的:

  1. Warning: can't find superclass or interface
  2. Warning: can't find referenced class
  3. If there are unresolved references to classes or interfaces, you most likely forgot to specify an essential library.
  4. For proper processing, all libraries that are referenced by your code must be specified, including the Java run-time library.
  5. For specifying libraries, use the -libraryjars option.
  6. For example, if ProGuard complains that it can't find a javax.crypto class, you probably still have to specify jce.jar, next to the more common rt.jar.
  7. If you're missing a library and you're absolutely sure it isn't used anyway, you can try your luck with the -ignorewarnings option, or even the -dontwarn option. Only use these options if you really know what you're doing though.
  8. For example, if you're developing for Android, and ProGuard complains that it can't find a java.awt class, then some library that you are using is referring to java.awt.
  9. This is a bit shady, since Android doesn't have this package at all, but if your application works anyway, you can let ProGuard accept it with "-dontwarn java.awt.**".

2.官方对于这个问题的解释:

如果存在未解决的类或者接口的引用的话,你很有可能忘记指定一些必要的库了。正确的处理方法是在你代码里引用到的所有库都必须要在配置文件中指定,包括Java运行库,使用-libraryjars选项来指定这些库。

看到这里,你明白了刚刚为什么提示You may need to specify additional library jars (using '-libraryjars').了吧,目的就是在配置文件里面加上项目中所使用到的第三方库。可是,你这是坑爹呀,我明明给所有库都加上-libraryjars参数指定了,结果还是报Warning: com.xxx.bbbb.F.H$3: can't find referenced class com.xxx.bbbb..F.H$com.xxx.bbbb.F.H$_B这个错啊,打包不了!

好,我们再看下去...

接着他给我们举个例子:如果ProGuard说它找不到javax.crypto class这个类,你可能还需要指定jce.jar包,紧接着还要指定更常用的rt.jar包。换句话说,javax.crypto class这个类里面所引用到的类不但在jce.jar包里面,还在rt.jar包里面。

可是我项目中用到的所有第三方包都使用-libraryjars指定了呀!这个方法解决不了我的问题,不知道解决得了你的问题不?

解决不了的话,再看下去...

如果你缺少了某个库,而且你绝对肯定自己没有用到这个库里面的类的话,你可以试试你的运气,使用-ignorewarnings或者-dontwarn选项!-dontwarn我试过了,加上
-dontwarn com.xxx.bbbb.**之后确实没有报错,可以打包出来了!呵呵,别高兴得太早,你拿你这样打包好了的包去运行一下试试看?如果运气好的话,程序没有执行到找不到的类那里就不会报错,如果运气不好的话执行到那里了就会抛ClassNotFoundException!哼哼,怕了没?

我们身为备受瞩目的程序猿,肯定要有职业道德的,总不能编译出来的程序要使用到用户的运气+人品才能保证不出错吧!!^_^

其实,我明白他说的意思的,就是说你要绝对确保这个类没有被你的程序中使用到才可以使用-ignorewarnings或者-dontwarn选项,接着,他又举了个例子了: 比如你开发的是Android项目,但是打包时ProGuard抱怨找不到java.awt里面的某些类,可能是因为你使用的某些库要用到java.awt包里面的类,众所周知,Android压根就没有java.awt这个包,它是J2SE里面的包,我们Android程序当然不需要这个包也能很好的运行了,此时,你可以用-dontwarn java.awt.**来屏蔽掉所有关于java.awt的警告他举这个例子是为了说明一个理论:当你绝对确定自己的代码没有用到报错的这个类后,可以使用-dontwarn com.xx.bbb**来屏蔽警告信息

3.总结出官方对于
Warning: can't find superclass or interface
Warning: can't find referenced class

这两个问题的解决方法:

1.要把你项目中所引入的第三方jar包使用"-libraryjars 包路径"指定好。
2.还是报错的话,确保报错的类没有在你的项目中使用到,使用"-dontwarn 类名正则表达式"屏蔽警告。
完了?可是我还想问:第一步做完后还是报错,而且这个类在我项目中真的有用到,不能使用"-dontwarn .."屏蔽警告啊??

4.说了这么久,终于开始说解决方案了:

其实找不到引用的这个类是第三方包里面的,而且很多时候我们只需要混淆自己写的代码就行了,第三方包的代码就是否要打乱就不要管了。嘻嘻,这叫做"只扫自己门前雪,甭管他人瓦上霜",

我们可以使用
-dontwarn com.xx.bbb.**
-keep class com.xx.bbb.** { *;}

参数来保持第三方库中的类而不乱,-dontwarn和-keep 结合使用,意思是保持com.xx.bbb.**这个包里面的所有类和所有方法而不混淆,接着还叫ProGuard不要警告找不到com.xx.bbb.**这个包里面的类的相关引用。
配置好后,重新打包,一切OK!而且程序能正确运行。示例:

----------------------------------------- question ------------------------------------------------

After some updates in Android SDK manager I try make signed apk and get this:

ProGuard: [] Warning: com.google.android.gms.auth.GoogleAuthUtil:
can't find referenced class com.welhzh.android.gms.R
ProGuard: [] Warning: com.google.android.gms.auth.GoogleAuthUtil:
can't find referenced class com.google.android.gms.R$string
...
etc.

If set -dontwarn com.welhzh.android.gms.** compiling is OK. But after run I get error many reports like this (from many devices):

Caused by: android.view.InflateException: Binary XML file line #32:
Error inflating class com.google.android.gms.common.SignInButton

On my devices all ok. Before update I have not ProGuard warnings and all work perfectly. How it fix?

----------------------------------------- answer ------------------------------------------------

Although adding this to proguard-project.txt file works, it keeps all classes.

-keep class com.welhzh.android.gms.** { *; }
-dontwarn com.welhzh.android.gms.**

I prefer this, which makes apk file size much smaller  (一般情况下别用这个) :

-keep public class com.welhzh.android.gms.* { public *; }
-dontwarn com.welhzh.android.gms.**

Also note up to date Google Play Proguard notification here:http://developer.android.com/google/play-services/setup.html#Proguard

-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
} -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
} -keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
} -keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}

如果上面的导致app运行时崩溃,可以来狠一点的,指定proguard只混淆某些package或类:

-keep class !com.foo.**,!com.bar.** { *; }
-dontwarn !com.foo.**,!com.bar.**     # 这句比较危险,不提示任何warning