Android代码混淆

为什么要代码混淆?

Java 是一种跨平台的、解释型语言,Java 源码编译成中间”字节码”存储于 class 文件里。因为跨平台的须要,Java 字节码中包括了非常多源码信息,如变量名、方法名,而且通过这些名称来訪问变量和方法,这些符号带有很多语义信息,非常easy被反编译成 Java 源码。

为了防止这样的现象,我们能够使用 Java 混淆器对 Java 字节码进行混淆。混淆就是对公布出去的程序进行又一次组织和处理,使得处理后的代码与处理前代码完毕同样的功能,而混淆后的代码非常难被反编译,即使反编译成功也非常难得出程序的真正语义。

ProGuard

ProGuard 是一个免费的 Java 类文件的压缩,优化,混肴器。它删除没有用的类,字段,方法与属性。使字节码最大程度地优化,使用简短且无意义的名字来重命名类、字段和方法 。

压缩:检测以及删除没有用到的类字段属性

优化:分析以及优化方法的字节码

混淆:使用无意义的短变量,对类、方法等进行重命名

Android SDK自带了混淆工具Proguard,SDK的 ‘\sdk\tools\proguard’ 文件夹下。

项目中如果含有多个module时,在主app中设置了混淆其他module都会混淆。
在App module build.gradle中:

android {
   
    ...     

    buildTypes {
        release {
          minifyEnabled true      // 开启代码混淆
          zipAlignEnabled true    // 开启Zip压缩优化
          shrinkResources true    // 移除未被使用的资源
           //混淆文件列表,混淆规则配置
          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    ...

}

取消混淆规则配置的三种类型

1 不能混淆的  2 第三方的jar包  3 混淆过程中肯定会有警告,有问题,根据提示解决问题,我遇到的问题就是有的jar包不能混淆,而我给混淆了,所以我加了第三部分的代码:

#压缩等级,一般选择中间级别5
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化  不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*

#保持下面的类不被混淆(没有用到的可以删除掉,比如没有用到service则可以把service行删除)
-keep public class * extends android.app.Fragment
-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.support.v4.app.FragmentActivity
-keep public class * extends android.support.** { *;}
#如果引用了v4或者v7包
-dontwarn android.support.*
#忽略警告(开始应该注释掉,让他报错误解决,最后再打开,警告要尽量少)
-ignorewarnings

#####################记录生成的日志数据,gradle build时在本项目根目录输出################
#混淆时是否记录日志
-verbose
#apk 包内所有class 的内部结构
-dump class_files.txt
#为混淆的类和成员
-printseeds seeds.txt
#列粗从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
#####################记录生成的日志数据,gradle build时在本项目根目录输出结束################

#本地的R类不要被混淆,不然就找不到相应的资源
-keep class **.R$*{ public static final int *; }

#保持内部类,异常类
-keepattributes Exceptions, InnerClasses
#保持泛型、注解、源代码之类的不被混淆
-keepattributes Signature, Deprecated, SourceFile
-keepattributes LineNumberTable, *Annotation*, EnclosingMethod

#保持自定义控件不被混淆(没有就不需要)
-keepclasseswithmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
-keepclasseswithmembers class * extends android.supprot.v4.app.Fragment{
    public void *(android.view.View);
}
#保持 Parcelable 不被混淆(没有就不需要)
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆(没有就不需要)
-keepnames class * implements java.io.Serializable

-keepclassmembers class * {
    public void *ButtonClicked(android.view.View);
}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# gson工具不需要混淆
-dontwarn com.google.gson**
-keep class com.google.gson.**{*;}


# volley
-dontwarn com.android.volley.jar.**
-keep class com.android.volley.**{*;}

#友盟混淆配置start
-keepclassmembers class * {
   public <init> (org.json.JSONObject);
}
-keep public class com.hawk.android.hicamera.R$*{
*;
}
#友盟混淆配置end


#极光推送混淆配置
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn com.tencent.**
-keep class com.tencent.**{*;}

# apache
-dontwarn org.apache.http.**
-keep class org.apache.http.** { *;}

Android Studio中自定义的混淆规则:

常见语法:

-include {filename}    从给定的文件里读取配置參数 
-basedirectory {directoryname}    指定基础文件夹为以后相对的档案名称 
-injars {class_path}    指定要处理的应用程序jar,war,ear和文件夹 
-outjars {class_path}    指定处理完后要输出的jar,war,ear和文件夹的名称 
-libraryjars {classpath}    指定要处理的应用程序jar,war,ear和文件夹所须要的程序库文件 
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。 
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。
 
保留选项 
-keep {Modifier} {class_specification}    保护指定的类文件和类的成员 
-keepclassmembers {modifier} {class_specification}    保护指定类的成员。假设此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是全部指定的类和类成员是要存在。 
-keepnames {class_specification}    保护指定的类和类的成员的名称(假设他们不会压缩步骤中删除) 
-keepclassmembernames {class_specification}    保护指定的类的成员的名称(假设他们不会压缩步骤中删除) 
-keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,假设全部指定的类成员出席(在压缩步骤之后) 
-printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件 
-keep public class * extends com.example.test.BaseActivity   保持继承了的BaseActivity 的public修饰类名不被混淆
 
压缩 
-dontshrink    不压缩输入的类文件 
-printusage {filename} 
-dontwarn   假设有警告也不终止
-whyareyoukeeping {class_specification}     
 
优化 
-dontoptimize    不优化输入的类文件 
-assumenosideeffects {class_specification}    优化时假设指定的方法。没有不论什么副作用 
-allowaccessmodification    优化时同意訪问并改动有修饰符的类和类的成员 
 
混淆 
-dontobfuscate    不混淆输入的类文件 
-printmapping {filename} 
-applymapping {filename}    重用映射添加混淆 
-obfuscationdictionary {filename}    使用给定文件里的keyword作为要混淆方法的名称 
-overloadaggressively    混淆时应用侵入式重载 
-useuniqueclassmembernames    确定统一的混淆类的成员名称来添加混淆 
-flattenpackagehierarchy {package_name}    又一次包装全部重命名的包并放在给定的单一包中 
-repackageclass {package_name}    又一次包装全部重命名的类文件里放在给定的单一包中 
-dontusemixedcaseclassnames    混淆时不会产生形形色色的类名 
-keepattributes {attribute_name,...}    保护给定的可选属性,比如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and 
 
InnerClasses. 
-renamesourcefileattribute {string}    设置源文件里给定的字符串常量

<init>   # 匹配所有构造函数
<fields>  # 匹配所有成员变量
<methods> # 匹配所有的方法

可以在它们前面添加 private ,public 进行进一步更精细的限制范围,比如保持 User 类中 所有 public 方法不被混淆:
-keep class com.xing.weijian.bean.User {
    public <methods>;
}
也可以在方法中加入参数进行限定:比如 保持 User 类的 public 修饰,参数是 String 类型的方法不被混淆:
-keep class com.xing.weijian.bean.User {
    public <methods>(String);
}
内部类使用 $ 号,保持 TabFragment 中 内部类 OnFragmentData的所有 public 修饰的都不被混淆掉
-keepclassmembers class com.xing.weijian.TabFragment$OnFragmentData{
    public *;
}
jni 方法不能混淆,因为这个方法需要和 native 方法保持一致
-keepclasseswithmembernames class * { # 保持native方法不被混淆    
    native <methods>;
}
不混淆某个类
-keep public class com.android.proguard.example.Test { *; }
不混淆某个包所有的类
-keep class com.android.proguard.example.** { *; }
不混淆某个类的子类
-keep public class * extends com.android.proguard.example.Test { *; }
不混淆所有类名中包含了“model”的类及其成员
-keep public class **.*model*.** {*;}
不混淆某个接口的实现
-keep class * implements com.android.proguard.example.TestInterface { *; }
不混淆某个类的构造方法
-keepclassmembers class com.android.proguard.example.Test {
    public <init>();
}
不混淆某个类的特定的方法
-keepclassmembers class com.android.proguard.example.Test {
    public void test(java.lang.String);
}
不混淆某个类的内部类
-keep class com.android.proguard.example.Test$* {
        *;
 }
keep 与 keepclassmembers , keepclasseswithmembers在这里插入图片描述
-ignorewarning                                      # 是否忽略警告
-optimizationpasses 5                               # 指定代码的压缩级别(在0~7之间,默认为5)
-dontusemixedcaseclassnames                         # 是否使用大小写混合(windows大小写不敏感,建议加入)
-dontskipnonpubliclibraryclasses                    # 是否混淆非公共的库的类
-dontskipnonpubliclibraryclassmembers               # 是否混淆非公共的库的类的成员
-dontpreverify                                      # 混淆时是否做预校验(Android不需要预校验,去掉可以加快混淆速度)
-verbose                                            # 混淆时是否记录日志(混淆后会生成映射文件)

#指定外部模糊字典
-obfuscationdictionary dictionary1.txt
#指定class模糊字典
-classobfuscationdictionary dictionary1.txt
#指定package模糊字典
-packageobfuscationdictionary dictionary2.txt

#混淆时所采用的算法(谷歌推荐算法)
-optimizations !code/simplification/arithmetic,!field,!class/merging,!code/allocation/variable

#添加支持的jar(引入libs下的所有jar包)
-libraryjars libs(*.jar;)

#将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile

#保持注解不被混淆
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation {*;}

#保持泛型不被混淆
-keepattributes Signature
#保持反射不被混淆
-keepattributes EnclosingMethod
#保持异常不被混淆
-keepattributes Exceptions
#保持内部类不被混淆
-keepattributes Exceptions,InnerClasses
#抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

#------------------------------------默认保留区--------------------------------------#
#保持基本组件不被混淆
-keep public class * extends android.app.Fragment
-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

#保持 Google 原生服务需要的类不被混淆
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

#Support包规则
-dontwarn android.support.**
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native &lt;methods&gt;;
}

#保留自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View {
    *** get*();
    void set*(***);
    public &lt;init&gt;(android.content.Context);
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet);
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet, int);
}

#保留指定格式的构造方法不被混淆
-keepclasseswithmembers class * {
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet);
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet, int);
}

#保留在Activity中的方法参数是view的方法(避免布局文件里面onClick被影响)
-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}

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

#保持R(资源)下的所有类及其方法不能被混淆
-keep class **.R$* { *; }

#保持 Parcelable 序列化的类不被混淆(注:aidl文件不能去混淆)
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepnames class * implements java.io.Serializable

#持 Serializable 序列化的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient &lt;fields&gt;;
    !private &lt;fields&gt;;
    !private &lt;methods&gt;;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#保持 BaseAdapter 类不被混淆
-keep public class * extends android.widget.BaseAdapter { *; }
#保持 CusorAdapter 类不被混淆
-keep public class * extends android.widget.CusorAdapter{ *; }

#-------------------------------------webView区---------------------------------------#
#WebView处理,项目中没有使用到webView忽略即可
#保持Android与JavaScript进行交互的类不被混淆
-keep class **.AndroidJavaScript { *; }
-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.WebChromeClient {
     public void *(android.webkit.WebView,java.lang.String);
}

#网络请求相关
-keep public class android.net.http.SslError

#-------------------------------------删除代码区--------------------------------------#
删除代码中Log相关的代码
-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int v(...);
    public static int i(...);
    public static int w(...);
    public static int d(...);
    public static int e(...);
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值