Android技术知识Android开发混淆

Android代码混淆使用手册

2019-11-05  本文已影响0人  Geekholt

如需转载请评论或简信,并注明出处,未经允许不得转载

目录

前言

一个发布后的apk可以通过反编译代码反编译资源重新打包后变成一个新的apk。使用代码混淆技术可以让反编译后的代码难以阅读(注意混淆不是让apk不能阅读,而是加大阅读的难度),还可以通过压缩优化代码,从而减小APK的体积,甚至在一定程度上还能减小应用运行时的内存

混淆原理

混淆包括四个功能,shrinker(压缩), optimizer(优化),obfuscator(混淆),preverifier(预校验)

哪些不应该混淆

混淆步骤

打开混淆

在build.gradle文件下,将minifyEnabled的值设为true代表开启混淆,proguardFiles代表混淆文件的地址

buildTypes {
     release {
     minifyEnabled true
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
   }
}

因为开启混淆会使编译时间变长,且不利于断点调试,所以debug模式下不开启

扩展:release下还有一些配置是可以加上的

zipAlignEnabled true  // Zipalign优化
shrinkResources false // 删除无用资源
debuggable false // 是否debug
signingConfig signingConfigs.relealse  // 签名

编写混淆文件

这里提供一个模板,基本指令区默认保留区WebView都是可以基本所有项目共用的,我们要做的事根据自己的实际项目区完善实体类第三方包与js互相调用的类反射相关的类和方法

#---------------------------------1.实体类---------------------------------



#-------------------------------------------------------------------------

#---------------------------------2.第三方包-------------------------------



#-------------------------------------------------------------------------

#---------------------------------3.与js互相调用的类------------------------



#-------------------------------------------------------------------------

#---------------------------------4.反射相关的类和方法-----------------------



#----------------------------------------------------------------------------

#---------------------------------基本指令区----------------------------------
-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.Appliction
-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 *(**On*Event);
}
#----------------------------------------------------------------------------

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

1.实体类

你可以针对单个实体类不进行混淆

-keep class 你的实体类所在的包.** { *; }

如果你的实体类都放在一个包下,如路径是com/geekholt/demo/bean,也可以用下面的方法对整个包下的类都不混淆

-keep class com.geekholt.demo.bean.** { *; }

2.第三方包

可以在build.gradle下查看项目引用到了哪些第三方包,一般可以到对应的官网查看混淆配置,这里列出了一些常用的第三方包的混淆配置

-dontwarn com.google.**
-keep class com.google.gson.** {*;}
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}
-keep public class * implements com.bumptech.glide.module.AppGlideModule
-keep public class * implements com.bumptech.glide.module.LibraryGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
-keepclassmembers class * {
    public <init> (org.json.JSONObject);
}
#友盟统计5.0.0以上SDK需要
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
#友盟统计R.java删除问题
-keep public class com.gdhbgh.activity.R$*{
    public static final int *;
}
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
   long producerIndex;
   long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{
    public *;
}
-keep class com.alipay.sdk.app.AuthTask{
    public *;
}
-dontwarn cn.jpush.**
-keep class cn.jpush.** {*;}

# protobuf(jpush依赖)
-dontwarn com.google.**
-keep class com.google.protobuf.** {*;}
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
 
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use Rx:
-dontwarn rx.**

3.与js互相调用的类

第三部分与js互调的类,工程中没有直接跳过

-keep class 你的类所在的包.** { *; }

如果是内部类的话,你可以这样

-keepclasseswithmembers class 你的类所在的包.父类$子类 { ; }
-keepclasseswithmembers class com.demo.login.bean.ui.MainActivity$JSInterface { 
      ; 
}

4.与反射有关的类

工程中没有直接跳过

-keep class 你的类所在的包.** { *; }

Keep配置

保留 防止被移除或者被重命名 防止被重命名
类和类成员 -keep -keepnames
仅类成员 -keepmembers -keepmembernames
如果拥有某成员,保留类和类成员 -keepclasseswithmembers -keepclasseswithmembernames

如果不确定自己该用哪个的话,就用-keep,它能保证匹配的类在压缩这一阶段不被移除,并且在混淆阶段不会被重新命名。

  • 如果只声明保护一个类,并没有指定受保护的成员。proguard只会保护它的类名和它的无参构造函数。其它成员依旧会被压缩、优化、混淆。
  • 如果声明保护一个方法,proguard会把它当作程序的入口点,方法名不会变,但它里面的代码依旧会被优化、混淆。

Proguard通配符

Proguard通配符 描述
<field> 匹配类中的所有字段
<method> 匹配类中所有的方法
<init> 匹配类中所有的构造函数
* 匹配任意长度字符,不包含包名分隔符(.)
** 匹配任意长度字符,包含包名分隔符(.)
*** 匹配任意参数类型
... ...

常用自定义混淆规则

-keep public class com.geekholt.example.Test { *; }
-keep class com.geekholt.test.** { *; }
}
-keep public class * extends com.geekholt.example.Test { *; }
-keep public class **.*model*.** { *; }
-keep class * implements com.geekholt.example.TestInterface { *; }
-keepclassmembers class com.geekholt.example.Test { 
    public <init>(); 
}
-keepclassmembers class com.geekholt.example.Test { 
    public void test(java.lang.String); 
}
}
-keep class com.geekholt.example.Test$* {
        *;
 }

注意事项

混淆过的包必须进行检查,避免因混淆引入的bug

  1. 需要从代码层面检查。混淆打包后在/build/outputs/mapping/release/目录下会输出mapping.txt文件,该文件提供混淆前后类、方法、类成员等的对照表,可以检查重点关注的类的混淆结果

  2. 需要从测试方面检查。将混淆过的包进行全方面测试,检查是否有 bug 产生

上一篇下一篇

猜你喜欢

热点阅读