Proguard混淆入門手冊

代碼混淆

代碼混淆(Obfuscated code)亦稱花指令,是將計算機程序的代碼,轉換成一種功能上等價,但是難於閱讀和理解的形式的行爲。代碼混淆可以用於程序源代碼,也可以用於程序編譯而成的中間代碼。執行代碼混淆的程序被稱作代碼混淆器。已經存在許多種功能各異的代碼混淆器。

將代碼中的各種元素,如變量,函數,類的名字改寫成無意義的名字。比如改寫成單個字母,或是簡短的無意義字母組合,甚至改寫成“__”這樣的符號,或者中文使得閱讀的人無法根據名字猜測其用途。重寫代碼中的部分邏輯,將其變成功能上等價,但是更難理解的形式。比如將for循環改寫成while循環,將循環改寫成遞歸,精簡中間變量,等等。打亂代碼的格式。比如刪除空格,將多行代碼擠到一行中,或者將一行代碼斷成多行等等。

代碼混淆器也會帶來一些問題。主要的問題包括:

被混淆的代碼難於理解,因此調試以及除錯也變得困難起來。開發人員通常需要保留原始的未混淆的代碼用於調試。對於支持反射的語言,代碼混淆有可能與反射發生衝突。代碼混淆並不能真正阻止反向工程,只能增大其難度。因此,對於對安全性要求很高的場合,僅僅使用代碼混淆並不能保證源代碼的安全。

Java是一種跨平臺的、解釋型語言,Java源代碼編譯成中間“字節碼”存儲於class文件中。由於跨平臺的需要,Java字節碼中包括了很多源代碼信息,如變量名、方法名,並且通過這些名稱來訪問變量和方法,這些符號帶有許多語義信息,很容易被反編譯成Java源代碼。爲了防止這種現象,我們可以使用Java混淆器對Java字節碼進行混淆。

混淆就是對發佈出去的程序進行重新組織和處理,使得處理後的代碼與處理前代碼完成相同的功能,而混淆後的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義。被混淆過的程序代碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將代碼中的所有變量、函數、類的名稱變爲簡短的英文字母代號,在缺乏相應的函數名和程序註釋的情況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。

混淆器的作用不僅僅是保護代碼,它也有精簡編譯後程序大小的作用。由於以上介紹的縮短變量和函數名以及丟失部分信息的原因, 編譯後jar文件體積大約能減少25% ,這對當前費用較貴的無線網絡傳輸是有一定意義的。

此處轉載於:https://baike.baidu.com/item/%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7%86/1892288?fr=aladdin

ProGuard https://www.guardsquare.com/en/products/proguard/manual

proguard是最流行的java字節碼優化器。 它使您的java和Android應用程序文件小到90%,執行速度提升20%。 proguard還通過混淆類、字段和方法的名稱來增加逆向工程的難度。

ProGuard是Java class文件壓縮器、優化器、混淆器和預校驗器。壓縮步驟檢測並刪除未使用的類、字段、方法和屬性。優化步驟對方法的字節碼進行了分析和優化。混淆步驟使用無意義的短名稱重命名保留的類、字段和方法。這些步驟使代碼文件更小,更高效,更難逆向。

最後的預校驗步驟將預校驗信息添加到classes中,這是Java Micro Edition和Java 6及更高版本所必需的,編譯時可以把預校驗信息添加到類文件中(StackMap 和 StackMapTable屬性),從而加快類加載效率。
Android會把class編譯成dex,並對dex文件進行校驗,對class進行預校驗是多餘的。

這些步驟中的每一個都是可選的。例如,ProGuard還可以用於僅列出應用程序中的無作用代碼,或者用於預校驗class文件,以便在Java 6中有效使用。

ProGuard是一個壓縮、優化和混淆Java字節碼文件的免費的工具,它可以刪除無用的類、字段、方法和屬性。可以刪除沒用的註釋,最大限度地優化字節碼文件。它還可以使用簡短的無意義的名稱來重命名已經存在的類、字段、方法和屬性。常常用於Android開發用於混淆最終的項目,增加項目被反編譯的難度。

ProGuard執行流程

在這裏插入圖片描述
ProGuard首先讀取輸入的jar包(或aar、war、ear、zip、apk或目錄),然後壓縮、優化、混淆和預校驗,您可以隨意選擇讓ProGuard執行哪些優化步驟。ProGuard將處理的結果寫入一個或多個jar(或aar、war、ear、zip、apk或目錄)。輸入可以包含資源文件,其名稱和內容可以隨意地更新以映射混淆後的class名稱。

爲了確定哪些代碼必須保留,哪些代碼可以丟棄或混淆,您必須指定一個或多個代碼入口點。這些入口點通常是帶有main方法、applet等的類。

壓縮

默認開啓

在壓縮步驟,ProGuard遞歸地確定代碼使用了哪些類和類成員,其他類和類成員都會被刪除。

JAVA源代碼(.java文件)通常被編譯爲字節碼(.class文件)。而完整的程序或程序庫通常被壓縮和發佈成Java文檔(.jar文件)。字節碼比 Java源文件更簡潔,但是它仍然包含大量的無用代碼,尤其它是一個程序庫的時候。ProGuard的壓縮程序操作能分析字節碼,並刪除無用的類、字段和方法。程序只保留功能上的等價,包括異常堆棧描述所需要的信息。

優化

默認開啓

在優化步驟,ProGuard進一步優化代碼。在其他優化中,可以將非入口點的類和方法變爲私有、靜態或final的,可以刪除未使用的參數,並且可以內聯某些方法,目的是爲了提升代碼執行效率。

ProGuard支持以下種類的優化:

除了在壓縮操作刪除的無用類,字段和方法外,ProGuard也能在字節碼級提供性能優化,內部方法有:
常量表達式求值
刪除不必要的字段存取
刪除不必要的方法調用
刪除不必要的分支
刪除不必要的比較和instanceof驗證
刪除未使用的代碼
刪除只寫字段
刪除未使用的方法參數
像push/pop簡化一樣的各種各樣的peephole優化
在可能的情況下爲類添加static和final修飾符
在可能的情況下爲方法添加private, static和final修飾符
在可能的情況下使get/set方法成爲內聯的
當接口只有一個實現類的時候,就取代它
選擇性的刪除日誌代碼

此處轉載於:https://baike.baidu.com/item/ProGuard/5627019?fr=aladdin

混淆

默認開啓

在混淆步驟,使用簡短的無意義的名稱來重命名已經存在的類、字段、方法和屬性,ProGuard重命名不是入口點的類和類成員。在整個過程中,保留入口點確保它們仍然可以被原始名稱訪問。

預校驗

這個預校驗步驟是唯一不需要知道入口點的步驟。

最後的預校驗步驟將預校驗信息添加到classes中,這是Java Micro Edition和Java 6及更高版本所必需的,編譯時可以把預校驗信息添加到類文件中(StackMapStackMapTable屬性),從而加快類加載效率。

Android會把class編譯成dex,並對dex文件進行校驗,對class進行預校驗是多餘的。

反射

反射給混消時代碼的自動處理帶來了特殊的問題。在ProGuard中,代碼中動態創建或調用的類或類成員(即名稱)也必須指定爲入口點。例如,Class.forName()可以在運行時引用任何類。通常不可能知道哪些類必須保留,因爲類名可能是從配置文件中讀取的。因此,您必須在ProGuard配置中用-keep保留它們。

所幸,ProGuard已經爲您檢測並處理了以下情況:

Class.forName("SomeClass")
SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod", null)
SomeClass.class.getMethod("someMethod", new Class[] { A.class,... })
SomeClass.class.getDeclaredMethod("someMethod", null)
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class,... })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")

當你在java代碼中調用以上反射代碼時,混淆器會自動將你的類、方法、屬性混淆,不會出現問題

在Android Studio中測試,建類如下:
在這裏插入圖片描述

package com.cy.utils;

public class MyClass {
    private String s;
    private void add(MyClass myClass){}
    private void add(){}
}

package com.cy.utils;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
public class Test {
    public static void getM() throws Exception {
       Class clazz= Class.forName("com.cy.utils.MyClass");
        Class clazz1 = MyClass.class;
        MyClass.class.getField("s");
        MyClass.class.getDeclaredField("s");
        MyClass.class.getMethod("add", null);
        MyClass.class.getMethod("add", new Class[]{MyClass.class });
        MyClass.class.getDeclaredMethod("add", null);
        MyClass.class.getDeclaredMethod("add", new Class[]{MyClass.class });
        AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "s");
        AtomicLongFieldUpdater.newUpdater(MyClass.class, "s");
        AtomicReferenceFieldUpdater.newUpdater(MyClass.class, MyClass.class, "s");
    }
}

添加混淆配置:
在這裏插入圖片描述
配置:

-dontshrink

小編是在子模塊裏release的,所以要配置不壓縮,不然release出來的jar裏什麼都沒有,會被移除。

混淆結果如下:

package a.a.a;
public class b {
  public String a;
  private void a(b paramb) {}
  private void a() {}
}
package a.a.a;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
public class c {
  public static void a() {
    Class.forName("a.a.a.b");
    b.class.getField("a");
    b.class.getDeclaredField("a");
    b.class.getMethod("a", null);
    Class[] arrayOfClass;
    (arrayOfClass = new Class[1])[0] = b.class;
    b.class.getMethod("a", arrayOfClass);
    b.class.getDeclaredMethod("a", null);
    (arrayOfClass = new Class[1])[0] = b.class;
    b.class.getDeclaredMethod("a", arrayOfClass);
    AtomicIntegerFieldUpdater.newUpdater(b.class, "a");
    AtomicLongFieldUpdater.newUpdater(b.class, "a");
    AtomicReferenceFieldUpdater.newUpdater(b.class, b.class, "s");
  }
}

可以看到混淆結果相當滿意,運行並不會出現毛病。

注意: 如果你做的是SDK,你的代碼裏用了反射,如果你要混淆,你需要保證別人使用你的SDK的時候,沒有反射你SDK裏的某些類,否則GG,當然一般不會出現這樣的情況。

Android Studio混淆

Android Studio開啓混淆賊容易,在對應模塊的build.gradle下添加如下代碼:

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

release 表示只有在release APK或者release 模塊的時候,會執行混淆

minifyEnabled true表示開啓混淆,false表示不混淆

proguard-rules.pro 是混淆文件

如圖:
在這裏插入圖片描述
release APK的時候,並且全局啓動了混淆,子模塊libs下的aar裏的class不會被混淆,子模塊libs下的jar裏的class會被混淆
release 模塊的時候,無論是否開啓混淆,該模塊libs下的aar均不會被保留,開啓混淆並且keep住libs下jar的的class,keep的class會被保留。
子模塊需要配置consumerProguardFiles,才能控制對自身模塊的混淆,否則會使用全局的混淆

如果在多個子模塊的consumerProguardFiles中設置了相同語句,比如:-repackageclasses,會被最內層的子模塊覆蓋,例如app引用A模塊,A模塊引用B模塊,將會使用B模塊的配置。

用compileOnly添加的jar包,即使在混消時keep了,依然無法保留。

子模塊依賴了其他子模塊,release出來的aar/jar裏沒有其他子模塊的class,並且自身引用其他子模塊的class無論如何也不會被混淆。
如引用:

import com.utils.BitmapUtils ;
public class Test{
  private BitmapUtils bitmapUtils;
  private ImageLoader imageLoader;
}

BitmapUtils 來自其他子模塊,那麼混淆後結果:

import com.utils.BitmapUtils ;
public class Test{
  private BitmapUtils e;
  private a v;
}

com.utils.BitmapUtils無論如何也不會被混淆

子模塊依賴了aar,用compileOnly依賴時,release該模塊,aar裏的內容不會添加進去(api、implementation依賴時,會被添加進去),並且無論如何都不會被混淆

子模塊依賴了jar,用compileOnly依賴時,release該模塊,jar裏的內容不會添加進去(api、implementation依賴時,會被添加進去),會被混淆

多模塊APP混淆

app模塊用 proguardFiles

buildTypes {
        release {
            minifyEnabled rootProject.ext.minifyEnabled
            zipAlignEnabled rootProject.ext.zipAlignEnabled
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    '../zzz_proguard/base-proguard-rules.pro',
                    "../zzz_proguard/app-proguard-rules.pro"
            signingConfig signingConfigs.release
        }
    }

子模塊用consumerProguardFiles

  buildTypes {
        release {
            minifyEnabled rootProject.ext.minifyEnabled
            zipAlignEnabled rootProject.ext.zipAlignEnabled
            consumerProguardFiles '../zzz_proguard/base-proguard-rules.pro',
                    "../zzz_proguard/http-proguard-rules.pro"

        }
    }

只混淆自身模塊

proguardFiles

 buildTypes {
        release {
            minifyEnabled rootProject.ext.minifyEnabled
            zipAlignEnabled rootProject.ext.zipAlignEnabled
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    '../zzz_proguard/base-proguard-rules.pro',
                    "../zzz_proguard/utils-proguard-rules.pro"
        }
    }

Github源碼:
https://github.com/AnJiaoDe/MakeJar

混淆Jar包,首先得有一個普通的Jar包
死丟丟如何將多module生成一個Jar包?
在這裏插入圖片描述
目前小編掌握的比較簡單方便的方法是:需要在所有module的build目錄找到對應的class文件,然後合併
如各位有更好的方法,歡迎屏幕下方留言討論,喜歡的朋友可以點擊關注,瞭解更多
比如開發一個SDK,但是有多module依賴關係如下:
在這裏插入圖片描述
在這裏插入圖片描述
生成Jar包方式如下:
在app module下的build.gradle加入如下配置

def SDK_DEBUG_BASENAME = "makeJar-debug-" + new Date().format("yyyy-MM-dd");//未混淆的jar名字
def SDK_RELEASE_BASENAME = "makeJar-release-" + new Date().format("yyyy-MM-dd");//混淆後的jar名字
def SDK_OUTPATH = "libs/";//生成Jar的目錄
//生成未混淆的Jar
task makeJar(type: Jar) {
    delete SDK_OUTPATH+SDK_DEBUG_BASENAME+'.jar'//刪除原來的jar
    //包括子module額class文件
    from('../utils/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
    from('../http/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
    from('../router/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
    from('../amodule/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
    from('../manager/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes')
    from(project.zipTree('..\\router\\libs\\protobuf-lite-3.0.0.jar'))//合併其他Jar
//    //去掉不需要打包的目錄和文件
    exclude('BuildConfig.class', 'R.class')
////    //去掉R$開頭的文件
    exclude { it.name.startsWith('R$'); }
    baseName = SDK_DEBUG_BASENAME
    destinationDir = file(SDK_OUTPATH)
}

操作方式如下:
在這裏插入圖片描述
混淆Jar包方式如下:
在app module下的build.gradle加入如下配置

//混淆Jar
task proguard(type: proguard.gradle.ProGuardTask) {
    delete SDK_OUTPATH+SDK_RELEASE_BASENAME+'.jar'//刪除原來的jar
    configuration "${rootProject.rootDir}/proguard-rules.pro"//配置混淆文件
    injars SDK_OUTPATH+SDK_DEBUG_BASENAME+'.jar'//未混淆的Jar
    outjars SDK_OUTPATH+SDK_RELEASE_BASENAME+'.jar'//混淆後的Jar
}
proguard.dependsOn(makeJar)//必須添加此行,不然混淆失敗

操作方式如下:
在這裏插入圖片描述
混淆文件的配置
在這裏插入圖片描述

混淆文件內容如下:
關鍵在底部
#必須添加如下2行,否則GG, rt.jar android.jar

-libraryjars "D:\java\jre\lib\rt.jar"
-libraryjars "D:\AndroidSDK\platforms\android-28\android.jar"
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

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

#
#-------------------------------------------基本不用動區域----------------------------------------------
#
#
# -----------------------------基本 -----------------------------
#

# 指定代碼的壓縮級別 0 - 7(指定代碼進行迭代優化的次數,在Android裏面默認是5,這條指令也只有在可以優化時起作用。)
-optimizationpasses 5
# 混淆時不會產生形形色色的類名(混淆時不使用大小寫混合類名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的庫類(不跳過library中的非public的類)
-dontskipnonpubliclibraryclasses
# 指定不去忽略包可見的庫類的成員
-dontskipnonpubliclibraryclassmembers
#不進行優化,建議使用此選項,
-dontoptimize
 # 不進行預校驗,Android不需要,可加快混淆速度。
-dontpreverify
# 屏蔽警告
-ignorewarnings
# 指定混淆是採用的算法,後面的參數是一個過濾器
# 這個過濾器是谷歌推薦的算法,一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保護代碼中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 這在JSON實體映射時非常重要
-keepattributes Signature
# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable
 #優化時允許訪問並修改有修飾符的類和類的成員,這可以提高優化步驟的結果。
# 比如,當內聯一個公共的getter方法時,這也可能需要外地公共訪問。
# 雖然java二進制規範不需要這個,要不然有的虛擬機處理這些代碼會有問題。當有優化和使用-repackageclasses時才適用。
#指示語:不能用這個指令處理庫中的代碼,因爲有的類和類成員沒有設計成public ,而在api中可能變成public
-allowaccessmodification
#當有優化和使用-repackageclasses時才適用。
-repackageclasses ''
 # 混淆時記錄日誌(打印混淆的詳細信息)
 # 這句話能夠使我們的項目混淆後產生映射文件
 # 包含有類名->混淆後類名的映射關係
-verbose
#
##
## ----------------------------- 默認保留 -----------------------------
##
##----------------------------------------------------
## 保持哪些類不被混淆
#繼承activity,application,service,broadcastReceiver,contentprovider....不進行混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-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 class android.support.** {*;}## 保留support下的所有類及其內部類

-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#表示不混淆上面聲明的類,最後這兩個類我們基本也用不上,是接入Google原生的一些服務時使用的。
#----------------------------------------------------

# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**


#表示不混淆任何包含native方法的類的類名以及native方法名,這個和我們剛纔驗證的結果是一致
-keepclasseswithmembernames class * {
    native <methods>;
}


#這個主要是在layout 中寫的onclick方法android:onclick="onClick",不進行混淆
#表示不混淆Activity中參數是View的方法,因爲有這樣一種用法,在XML中配置android:onClick=”buttonClick”屬性,
#當用戶點擊該按鈕時就會調用Activity中的buttonClick(View view)方法,如果這個方法被混淆的話就找不到了
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}

#表示不混淆枚舉中的values()和valueOf()方法,枚舉我用的非常少,這個就不評論了
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

#表示不混淆任何一個View中的setXxx()和getXxx()方法,
#因爲屬性動畫需要有相應的setter和getter的方法實現,混淆了就無法工作了。
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

#表示不混淆Parcelable實現類中的CREATOR字段,
#毫無疑問,CREATOR字段是絕對不能改變的,包括大小寫都不能變,不然整個Parcelable工作機制都會失敗。
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
# 這指定了繼承Serizalizable的類的如下成員不被移除混淆
-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();
}
# 保留R下面的資源
#-keep class **.R$* {
# *;
#}
#不混淆資源類下static的
-keepclassmembers class **.R$* {
    public static <fields>;
}

# 對於帶有回調函數的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}
#保持內部類能正常引用
-keepattributes Exceptions,InnerClasses

# 保留我們自定義控件(繼承自View)不被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

#
#----------------------------- 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);
}
#在app中與HTML5的JavaScript的交互進行特殊處理
#我們需要確保這些js要調用的原生方法不能夠被混淆,於是我們需要做如下處理:
-keepclassmembers class com.ljd.example.JSInterface {
    <methods>;
}

#
#---------------------------------實體類---------------------------------
#--------(實體Model不能混淆,否則找不到對應的屬性獲取不到值)-----
#
-dontwarn com.suchengkeji.android.confusiondemo.md.**
#對含有反射類的處理
-keep class com.suchengkeji.android.confusiondemo.md.** { *; }
#
# ----------------------------- 其他的 -----------------------------
#
# 刪除代碼中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(...);
}

# 保持測試相關的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**


#
# ----------------------------- 第三方 -----------------------------
#
-dontwarn com.orhanobut.logger.**
-keep class com.orhanobut.logger.**{*;}
-keep interface com.orhanobut.logger.**{*;}

-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;}
-keep interface com.google.gson.**{*;}

#   -------------------------------multidata sdk------------------------------------------------------
#不移除資源,必須寫這行,不寫,module的所有沒有用到的類都會被移除
-dontshrink

#utils
-keepnames class com.cy.utils.**{
  protected <methods>;
  public <methods>;
}
#http
-keepnames class com.cy.http.StringCallbackImpl{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.ProtobufCallbackImpl{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.Imageloader{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.HttpUtils{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.FileCallbackImpl{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.Callback{
  protected <methods>;
  public <methods>;
}
-keepnames class com.cy.http.BitmapCallbackImpl{
  protected <methods>;
  public <methods>;
}
#router
-keepnames class com.cy.router.VideoListener{
    protected <methods>;
     public <methods>;
}
-keepnames class com.cy.router.RequestListener{
    protected <methods>;
     public <methods>;
}
-keepnames class com.cy.router.LoadListener{
    protected <methods>;
     public <methods>;
}
-keepnames class com.cy.router.ContainerManager{
    protected <methods>;
     public <methods>;
}
-keepnames class com.cy.router.Container{
    protected <methods>;
     public <methods>;
}
-keepnames class com.cy.router.RouterFileProvider{
}
#protobuf
-keepnames class com.google.protobuf.**{
   *;
}
#amodule
-keepnames class com.cy.amodule.ARouterBuilderImpl{
}

#manager
-keepnames class com.cy.manager.Manager{
  protected <methods>;
  public <methods>;
}
-repackageclasses 'comcymakejar'#將混淆打亂的類放置於此包名下
#必須添加如下2行,否則GG,  rt.jar android.jar
-libraryjars "D:\java\jre\lib\rt.jar"
-libraryjars "D:\AndroidSDK\platforms\android-28\android.jar"

未混淆的Jar是這樣的
在這裏插入圖片描述

混淆後的Jar是這樣的:
在這裏插入圖片描述

這時,想到如果多module生成一個aar,咋整?死丟丟可不好整,貌似小編能想到的就是自己用代碼或者groovy寫插件,自己合併再混淆。

文章前面已提供源碼

各位老鐵有問題歡迎及時聯繫、指正、批評、撕逼

Github:
https://github.com/AnJiaoDe
簡書:
https://www.jianshu.com/u/b8159d455c69

微信公衆號
這裏寫圖片描述

QQ羣
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章