Android中代码混淆

Android中代码混淆:ProGuard 的官网 https://www.guardsquare.com/en/products/proguard#manual/usage.html

参考自http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2018/0409/9568.html

https://zhuanlan.zhihu.com/p/92803018

https://www.jianshu.com/p/60e82aafcfd0/

Android studio中开启混淆  

 buildTypes {
        release {
            minifyEnabled true   //开启混淆
            zipAlignEnabled true  //压缩优化
            shrinkResources true  //移出无用资源
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //默认的混淆文件以及我们指定的混淆文件
        
        }

    }

 一、Android混淆的原则

  1、反射用到的类不混淆

  2、JNI方法不混淆

  3、AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类默认不会进行混淆

  4、Parcelable的子类和Creator静态成员变量不混淆,否则会产生android.os.BadParcelableException异常

  5、使用GSON、fastjson等框架时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象

  6、使用第三方开源库或者引用其他第三方的SDK包时,需要在混淆文件中加入对应的混淆规则

  7、有用到WEBView的JS调用也需要保证写的接口方法不混淆 

  8、自定义控件,枚举类,JavaBean 不用混淆

 

 2、google默认混淆文件位置:

         \sdk\tools\proguard\proguard-android.txt

         \sdk\tools\proguard\proguard-android-optimize.txt ;

    默认混淆文件说明:

   

  从上图比较来看,在 proguard-android-optimize.txt 设置了压缩级别和压缩算法。所以如果你需要优化就用 proguard-android-optimize.txt这个,不需要优化就用 proguard-android.txt这个。

 

 

3、Android多模块混淆的问题

Android在多模块或者组件化的时候,关于混淆的管理,一般常见的做法就是两条。

  • 把所有的混淆规则规则都放在app模块下面,由app统一管理。这样就会有一个问题,就是到会导致混淆规则的冗余。
  • module管理自己的混淆规则,这样的话需要你对自己的模块有一个很好的管理。

这里就是记录下,由module的处理混淆的方法,参看官方文档。管理子module的方法,本质上就是管理aar的方法,是通用的。在module中添加:

    release {
        consumerProguardFiles   'proguard-rules.pro'
    }

这样就可以了,需要注意的是,

  1. 多模块或者组件化混淆,只要app模块开了混淆,子模块无论是否打开混淆都是默认开启的。只是通过上面的方法,子模块可以自定义混淆的规则。
  2. 子模块的混淆规则是无法影响app模块的的。所以建议,在子模块里尽量只放和子模块相关的混淆规则,一些公有的混淆方式请放在app或者公有的模块中。

 

 

4、混淆常用操作说明

 

1、在proguard-android-optimize.txt已经有的属性:

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*    (混淆时所采用的算法)

-optimizationpasses 5 #指定代码压缩级别     (设置代码的压缩比率 0~7,Android一般设置为5)

-allowaccessmodification  #这项配置是设置是否允许改变作用域的。使用这项配置之后可以提高优化的效果。**但是,如果你的 代码是一个库的话,最好不要配置这个选项,因为它可能会导致一些private变量被改成public

-dontpreverify #不预校验

-dontskipnonpubliclibraryclasses  #指定读取引用库文件的时候不跳过非public类(与-skipnonpubliclibraryclasses相对应)

-verbose    #混淆时记录日志

-keepattributes *Annotation*  保持注解不混淆

-keep public class com.google.vending.licensing.ILicensingService  (保持类名不混淆)
-keep public class com.android.vending.licensing.ILicensingService   (保持类名不混淆)


# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;

 
#--保留自定义控件(继承自View)不被混淆-(保持该类下的特定方法不被混淆,其他方法和类名会被混淆)
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

#--原理同上 -keepclassmembers  保持继承自Activity的类的特定方法不被混淆

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


# 保持枚举 enum 类的特定方法不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

 保留 Parcelable  序列化类的特定方法不被混淆--
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

# 不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。
-keepclassmembers class **.R$* {
    public static <fields>;
}


#保持类名不混淆
-keep class android.support.annotation.Keep   


-keep @android.support.annotation.Keep class * {*;}

 

#-keepclasseswithmembers   不需要保持类名,只需要保持该类下的特定方法保持不被混淆

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

 

 

2、需要自定义的部分:

如果默认使用proguard-android-optimize.txt混淆文件的话,在自定义混淆文件proguard-rules.pro这个里面就不需要

添加上面的内容了,否则需要把上面的内容添加进来。

proguard-rules.pro文件内容:

  

#------------------------------基本不用动区域----------------------------------------------------------

-ignorewarnings#忽略警告(否则打包可能会不成功)
-dontusemixedcaseclassnames#指定在混淆时不生成混合大小写的类名
-keepattributes Signature#避免混淆泛型 如果混淆报错建议关掉 
-keepattributes EnclosingMethod#用到了反射需要加入-
-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.preference.Preference
-keep public class * extends android.view.View
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class com.android.vending.licensing.ILicensingService
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
-keep public class * extends android.app.Fragment
# 保持自定义控件类的特定方法不被混淆
-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);
}
#保持 Serializable 不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}
#对于带有回调函数的 onXXEvent 的不能被混淆------
-keepclassmembers class * {
void *(**On*Event);
}
#-WebView,没有使用 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);
}
# 保护注解
-keep class * extends java.lang.annotation.Annotation {*;}
# 不混淆内部类
-keepattributes InnerClasses



   #----------------------------变化区域--------------------------------------------------

 

#-----------处理反射类---------------

 

 

#-----------处理js交互---- -----------

#--保持该类下的特定方法不被混淆
-keepclassmembers class com.handscape.fun.SanitationJs{
  public *;
  }

 

 

#-----------处理实体类---------------
# 在开发的时候我们可以将所有的实体类放在一个包内,这样我们写一次混淆就行了。
-keep class com.handscape.bean.** { *; }

 

#-----------------第三方包的混淆-----

  #--第三方不混淆 通常采用 -dontwarn和-keep 祝贺使用

  例如:

#-------避免混淆Bugly--------------------
 #--不警告该包和该包和该包的子包下的类
-dontwarn com.tencent.bugly.**
 #-不混淆该包和该包的子包下的内容
-keep public class com.tencent.bugly.**{*;}

 

 

5、说明:

<init>; //匹配所有构造器

<fields>; //匹配所有域

<methods>; //匹配所有方法方法

# -keep关键字
# keep:包留类名和类中的方法,防止他们被混淆
# keepnames:保留类名和类中的方法防止被混淆,但方法如果没有被引用将被删除
# keepclassmembers :只保留类中的方法,防止被混淆和移除。
# keepclassmembernames:只保留类中的方法,但如果方法没有被引用将被删除。
# keepclasseswithmembers:如果当前类中包含指定的方法,则保留类和类方法,否则将被混淆。
# keepclasseswithmembernames:如果当前类中包含指定的方法,则保留类和类方法,如果类方法没有被引用,则会被移除。

 -keep  关键字

一颗星表示只是保持该包下的类名,而子包下的类名还是会被混淆
-
keep class com.thc.test.*

两颗星表示把本包和所含子包下的类名都保持;
-keep class com.thc.test.**

既可以保持该包下的类名,又可以保持类里面的内容不被混淆;
-keep class com.thc.test.*{*;}

既可以保持该包及子包下的类名,又可以保持类里面的内容不被混淆;
-keep class com.thc.test.**{*;}

-keepclassmembers 不混淆该类下的特定方法

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

#保持该类下的所有public 方法不被混淆

-keepclassmembers class com.handscape.fun.SanitationJs{

public *;

}

#--保持IndexEntity下的内部类MySetting里面的所有方法不混淆

-keepclassmembers class com.handscape.entity.IndexEntity$MySetting{
    *;  
}

-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

keepclassmembernames:只保留类中的方法,但如果方法没有被引用将被删除。

-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}

 

其他关键字的使用

-dontwarn 

 

 

-skipnonpubliclibraryclasses  #指定读取引用库文件的时候跳过非public类。这样做可以提高处理速度并节省内存。一般情况下非                                                public在应用内是引用不到的,跳过它们也没什么关系。但是,在一些java类库中中出现了public类                                                继承非public类的情况,这样就不能用这个选项了。这种情况下,会打印一个警告出来,提示找不到类。

 

# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

 

6、错误说明

  1、Proguard打包混淆报错:can't find superclass or interface

   找到报错误的类,发现如果是当前版本Android sdk没有,说明该第三方包在更高版的sdk下编译的,将所在项目的         compileSdkVersion 版本调高就行了。

  2、build Variants 里面切换为release ,然后rebild clean 后,百度地图会报找不到 okhttp和google gson 包

 

 3、导入第三方包

-libraryjars libs/android.support.v4.jar

***注意:在Android studio 中不需要导入第三方类库的代码,如上面的部分:-libraryjars libs/BaiduLBS_Android.jar等,按照网上说的,需要在混淆文件中导入第三方类库,防止混淆时读取包内容出错,但是如果那样做的话,会报如下错误: 

是的,他说这个包被指定了两次

原因是,在build.gradle文件中已经指定了第三方类库,这里再次指定,就会重复,所以,在此应该不需要导第三方包的代码

-libraryjars libs/android.support.v4.jar这个。

 

  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值