title: 关于android打包混淆你必须知道的事
date: 2016-08-24 15:48:08
tags:

混淆是我们的应用上线前的一个重要环节,android中使用proguard,可以起到压缩,混淆,预检,优化的作用

  • 先说压缩(shrink):移除代码中无用的类,字段,方法和特性。

  • 混淆:使用a,b,c,d这样简短而无意义的名称对类,字段,方法重新命名。

  • 预检:在java平台对处理后的代码进行预检。

  • 优化:对字节码进行优化,移除无用的指令。

在as的gradle文件中:

1
2
3
4
5
6
7
8
9
buildTypes {
release {
minifyEnabled true
proguardFiles
getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}

找到项目根目录下的proguard-ruls.pro文件

基本上我们混淆主要分两大部分

  • 定制化的部分

  • 基本设置部分,这一部分是android每个apk打包混淆相同的部分

    先来说说基本设置部分,主要包括一些基本的指令:

——————————-基本指令区———————————

-optimizationpasses 5

-dontusemixedcaseclassnames

-dontskipnonpubliclibraryclasses

-dontskipnonpubliclibraryclassmembers

-dontpreverify

-verbose

-printmapping proguardMapping.txt

-optimizations !code/simplification/cast,!field/,!class/merging/

-keepattributes Annotation,InnerClasses

-keepattributes Signature

-keepattributes SourceFile,LineNumberTable

——————————默认保留区———————————

-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 * extends android.view.View

-keep public class com.android.vending.licensing.ILicensingService

-keep class android.support.* {;}

-keepclasseswithmembernames class * {
native ;
}

-keepclassmembers class extends android.app.Activity{
public void
(android.view.View);
}

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

-keep public class extends android.view.View{
**
get();
void set
(*);
public (android.content.Context);
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}

-keepclasseswithmembers class * {
public (android.content.Context, android.util.AttributeSet);
public (android.content.Context, android.util.AttributeSet, int);
}

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

-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();
}

-keep class *.R$ {
*;
}

-keepclassmembers class {
void
(*OnEvent);
}

————————-webview—————————————

-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}

-keepclassmembers class extends android.webkit.webViewClient {
public void
(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}

-keepclassmembers class extends android.webkit.webViewClient {
public void
(android.webkit.webView, jav.lang.String);

————————–end——————————————–

以上命令就是在各个不同apk打包混淆相同的命令,下面就相关命令做相关探讨:

-optimizationpasses 5

代码压缩比例0-7之间

-dontusemixedcaseclassnames

混淆之后类名都为小写

-dontskipnonpubliclibraryclasses

指定不去忽略非公共的库的类

-dontskipnonpubliclibraryclassmembers

指定不去忽略非公共的库的类的成员

-dontpreverify

不做预校验的操作,android 不需要做预校验,这样可以提高混淆的速度

-verbose

-printmapping proguardMapping.txt

生成原类名和混淆后的类名的映射文件

-optimizations !code/simplification/cast,!field/,!class/merging/

指定混淆所采用的算法,后面的参数是一个过滤器,这个过滤器是谷歌推荐的算法一般不改变

-keepattributes Annotation,InnerClasses

不混淆Anotation

-keepattributes Signature

不混淆泛型,这个主要是在JSON实体映射时非常重要,比如fastJson

-keepattributes SourceFile,LineNumberTable

抛出异常时显示代码的行号

-keep class XXXX

保持类名不混淆

-keepclasseswithmembers class XXXX

保持类名和其中的成员名不混淆

####By the way 需要保留的东西:

  • 保留所有本地的native方法不被混淆
1
2
3
print -keepclasseswithmembernames class * {
native <methods>;
}
  • 保留Activity中的方法参数是view的方法,
    从而我们在layout里面编写onClick就不会影响
1
2
3
print -keepclassmembers class * extends android.app.Activity {
public void * (android.view.View);
}
  • 枚举类不能被混淆
1
2
3
4
print -keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
  • 保留自定义控件(继承自View)不能被混淆
1
2
3
4
5
6
7
print -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*(***);
*** get* ();
}
  • 保留Parcelable序列化的类不能被混淆
1
2
3
-keep class * implements android.os.Parcelable{
public static final android.os.Parcelable$Creator *;
}
  • 保留Serializable 序列化的类不被混淆
1
2
3
4
5
6
7
8
9
-keepclassmembers class * implements java.io.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();
}
  • 对R文件下的所有类及其方法,都不能被混淆
1
2
3
-keepclassmembers class **.R$* {
*;
}
  • 对于带有回调函数onXXEvent的,不能混淆
1
2
3
-keepclassmembers class * {
void *(**On*Event);
}
  • 保留所有的实体类不被混淆最好放在一个包下面
1
2
3
4
-keep class com.null.test.entities.** {
//全部忽略
*;
}
  • 内嵌类容易被混淆,如果在一个类里面用了,eg:在MainActivity
1
2
3
4
5
keep class com.null.test.MainActivity$* {
*;
}
$这个符号就是用来分割内嵌类与其母体的标志
  • 对WebView的处理
1
2
3
4
5
6
7
8
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String);
}
  • 对javaScript的处理
1
2
3
-keepclassmembers class com.null.test.MainActivity$JSInterfacel {
<methods>;
}

#Last But most Important:很多第三方包都已混淆过使用的时候会有混淆说明,请添加到混淆文件中