最近编辑于2018年4月30日
一、
都知道在build.gradle中设置如下代码即可开启混淆。
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
其中minifyEnabled为true时即开启混淆,而proguardFiles则指定了混淆规则的文件们,也就是代码会根据proguard-android.text和proguard-rules.pro里所写的规则来进行混淆。你也可以像下面这样进行混淆(只要你在这个文件里设置了混淆规则):
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')//在proguard-android.txt文件
//设置了混淆规则
那么proguard-android.txt文件在哪?就在你的sdk路径下的\tools\proguard文件夹里。
可以发现这儿有三个可疑文件,proguard-android.txt就是默认混淆文件,proguard-android-optimize.txt就是比proguad-android.txt多指定了压缩级别,而proguard-project.txt给我们一条建议:应该保证类中所有js方法不被混淆,这里使用关键词keepclassmembers。
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
二、
新建一个工程,即使你不指定混淆规则文件也能成功打包,如下:
buildTypes {
release {
minifyEnabled true
}
}
那么我们什么时候不能成功打包?只要设置以下混淆规则就能成功打包。
-dontoptimize
-dontpreverify
-ignorewarnings
但是通常一打开应用就会崩。而且不推荐使用-ignorewarnings,推荐dontwarn。
三、
对于第三方包,首先肯定是按照其说明配置混淆规则,而如果你按照其说明仍然报错,首先可以放弃使用。其次,如果非要使用的话,报错信息与下面类似
Warning:retrofit2.Platform$Java8: can't find referenced class java.lang.invoke.MethodHandles$Lookup
Warning:retrofit2.Platform$Java8: can't find referenced class java.lang.invoke.MethodHandle
Warning:retrofit2.Platform$Java8: can't find referenced class java.lang.invoke.MethodHandles
Warning:retrofit2.Platform$Java8: can't find referenced class java.lang.invoke.MethodHandle
Warning:retrofit2.Platform$Java8: can't find referenced class java.lang.invoke.MethodHandles$Lookup
Warning:retrofit2.Platform$Java8: can't find referenced class org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
Warning:there were 8 unresolved references to classes or interfaces.
Warning:Exception while processing task java.io.IOException: Please correct the above warnings first.
Error:Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
> Job failed, see logs for details
出现Please correct the above warnings first,而上面warning是can't find referenced class xxxxxxxx,可以观察前面的retrofit2,即可设置-dontwarn retrofit2来避免报错不能打包。
四、
参考点击打开链接
移除是指在压缩(Shrinking)时是否会被删除。
保持元素不参与混淆的规则如下:
[保持命令] [类] {
[成员]
}
“类”代表类相关的限定条件,它将最终定位到某些符合该限定条件的类。它的内容可以使用:
- 具体的类
- 访问修饰符(
public
、protected
、private
) - 通配符
*
,匹配任意长度字符,但不含包名分隔符(.) - 通配符
**
,匹配任意长度字符,并且包含包名分隔符(.) extends
,即可以指定类的基类implement
,匹配实现了某接口的类- $,内部类
“成员”代表类成员相关的限定条件,它将最终定位到某些符合该限定条件的类成员。它的内容可以使用:
- <init> 匹配所有构造器
- <fields> 匹配所有域
- <methods> 匹配所有方法
- 通配符
*
,匹配任意长度字符,但不含包名分隔符(.) - 通配符
**
,匹配任意长度字符,并且包含包名分隔符(.) - 通配符
***
,匹配任意参数类型 …
,匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)
或者是void test(int a, String b)
这些方法。- 访问修饰符(
public
、protected
、private
)
我们再看看proguard-android.txt里写了啥
1、
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
native <methods>;
}
不混淆native的方法
2、
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
不混淆继承View的所有类的set和get方法
3、
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
不混淆继承Activity的所有类的中的参数类型为View的方法
4、
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
不混淆枚举类型的values和valueOf方法
5、
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
不混淆继承Parcelable的所有类的CREATOR
6、
-keepclassmembers class **.R$* {
public static <fields>;
}
不混淆R类中所有static字段
7、这是和build版本相关的内容
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontwarn android.support.**
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
五、
我们有那些东西不能被混淆呢?
1、实体类
2、与js互调的类
3、与反射相关的类
例如你需要通过反射获取TabLayout的一些信息,则应该
-keep class android.support.design.widget.TabLayout{*;}
4、如果需要使用类名调用,则不应被混淆
六、
使用注解来保持元素。
在SDK\tools\proguard下还有一个examples文件夹比较可疑。进去后除了一些混淆案例,在SDK\tools\proguard\examples\annotations\src\proguard\annotation文件夹下有一些java类。
如果想通过注解使set和get方法不被混淆
S1、在你的工程中参照KeepPublicGettersSetters.java新建一个类。
package proguard.annotation;//改为你的包名
import java.lang.annotation.*;//安卓中不需要导lang下的包
/**
* This annotation specifies to keep all public getters and setters of the
* annotated class from being shrunk, optimized, or obfuscated as entry points.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface KeepPublicGettersSetters {}
S2、参照SDK\tools\proguard\examples\annotations\lib文件,在proguard-android.pro文件中添加如下语句
-keepclassmembers @你的类名 class * {
void set*(***);
void set*(int, ***);
boolean is*();
boolean is*(int);
*** get*();
*** get*(int);
}
S3、参照SDK\tools\proguard\examples\annotations\examples文件,在你需要保持get和set方法不混淆的类的类名上添加@KeepPublicGettersSetters。
这样就通过注解完成keep了。