使用混淆ProGuard壓縮代碼和資源/減少方法數量

来源:https://www.cnblogs.com/ganchuanpu/archive/2018/06/01/9123482.html
-Advertisement-
Play Games

ProGuard介紹 ProGuard是一個Java類文件壓縮器,優化器,混淆器和預先文件驗證器。 壓縮步驟檢測和刪除未使用的類,欄位,方法和屬性。 優化步驟分析和優化方法的位元組碼。 混淆步驟使用短無意義的名稱重命名剩餘的類,欄位和方法。 這些步驟使代碼更小,更高效,更難以進行逆向工程。 最終的預驗 ...


ProGuard介紹

ProGuard是一個Java類文件壓縮器,優化器,混淆器和預先文件驗證器。 壓縮步驟檢測和刪除未使用的類,欄位,方法和屬性。 優化步驟分析和優化方法的位元組碼。 混淆步驟使用短無意義的名稱重命名剩餘的類,欄位和方法。 這些步驟使代碼更小,更高效,更難以進行逆向工程。 最終的預驗證步驟將預驗證信息添加到類,這是Java Micro Edition和Java 6及更高版本所必需的。

所以我們可以通過開啟 ProGuard 來去除未使用的類、欄位、方法和屬性,包括自帶代碼庫中的未使用項,這樣就以變通方式解決了 64k 限制的問題。同時ProGuard 還可優化位元組碼,移除未使用的代碼指令,以及用短名稱混淆其餘的類、欄位和方法。這樣也在一定程度上減少了Apk的大小。

ShrinkResources資源壓縮通過 Android Plugin for Gradle 提供,該插件會移除應用中未使用的資源,包括庫中未使用的資源。同樣也可減少Apk的大小。

如何啟用壓縮和混淆?

先上代碼,在build.gradle中配置如下:

android {
    buildTypes {
        release {
            minifyEnabled true //啟用代碼壓縮
            shrinkResources true //啟用資源壓縮
            proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
                    'proguard-rules.pro'//混淆規則文件配置
        }
    }
}
  • getDefaultProguardFile(‘proguard-android.txt’) 
    這個配置的意思是從 Android SDK tools/proguard/ 文件夾獲取預設 ProGuard 設置。使用 proguard-android-optimize.txt 可以進一步的壓縮代碼還包括其他在位元組碼一級(方法內和方法間)執行分析的優化,可進一步減小 APK 大小和幫助提高其運行速度。
  • proguard-rules.pro 
    可以在這個文件中添加自定義的規則,該文件和build.gradle在同級目錄下。

ProGuard的輸出文件及用處: 
混淆過程完成後會生成如下幾個文件, 
dump.txt 
說明 APK 中所有類文件的內部結構。 
mapping.txt 
提供原始與混淆過的類、方法和欄位名稱之間的轉換。 
seeds.txt 
列出未進行混淆的類和成員。 
usage.txt 
列出從 APK 移除的代碼。 
這些文件保存在 /build/outputs/mapping/release/目錄下。

這裡需要特別註意:每次release新版編譯後,最好將這些文件加入git版本庫一起保存,因為每次Release編譯後這些文件都會被覆蓋。

ProGuard配置說明

保留配置(即對配置的內容不進行處理)

-keep [,modifier,…] class_specification 
指定要保留的類和類成員(欄位和方法)。

-keepclassmembers [,modifier,…] class_specification 
指定要保留的類成員,如果它們的類也被保留。 例如,你可能希望保留實現Serializable介面的所有序列化欄位和類的方法。

-keepclasseswithmembers [,modifier,…] class_specification 
指定要保留的類和類成員,條件是所有指定的類成員都存在。 例如,你可能希望保留所有具有main方法的應用程式,而無需顯式列出。

-keepnames class_specification 
-keep的縮寫,允許class_specification 
指定要保存的類和類成員的名稱(如果它們在壓縮階段不被刪除)。 例如,你可能希望保留實現Serializable介面的類的所有類名,以便處理的代碼與任何原始的序列化類保持相容。 根本不使用的類仍然可以刪除。 只適用於混淆。

-keepclassmembernames class_specification 
–keepclassmembers的縮寫,allowhrinking class_specification 
指定要保存其名稱的類成員,如果它們在壓縮階段未被刪除。 例如,當處理由JDK 1.2或更舊版本編譯的庫時,你可能希望保留內部類$ 方法的名稱,因此當處理使用已處理庫的應用程式時,混淆器可以再次檢測它(儘管ProGuard本身不需要 這個)。 只適用於混淆。

-keepclasseswithmembernames class_specification 
–keepclasseswithmembernames的縮寫,允許class_specification 
指定要保留其名稱的類和類成員,條件是所有指定的類成員在收縮階段之後都存在。 例如,你可能希望保留所有本機方法名稱和其類的名稱,以便處理後的代碼仍然可以鏈接到本機庫代碼。 根本不使用的本地方法仍然可以刪除。 如果使用一個類文件,但是它的本機方法都不是,它的名字仍然會被模糊。 只適用於混淆。

-printseeds [filename] 
指定徹底列出由各種保護選項匹配的類和類成員。 列表列印到標準輸出或給定文件。 該列表可用於驗證是否真正找到預期的類成員,特別是如果你使用通配符。 例如,你可能希望列出所有應用程式或所有保留的小程式。

壓縮

-dontshrink 
指定不壓縮的類文件。 
-printusage {filename} 
指定需要列出dead code的類文件。 可以列出應用程式的未使用的代碼。 只適用於壓縮。 
-whyareyoukeeping {class_specification} 
指定列印關於給定類和類成員在壓縮步驟中keep的原因的詳細信息。 只適用於壓縮。

優化

-dontoptimize 
指定不優化輸入類文件。 預設情況下,啟用優化; 所有方法都以位元組碼級別進行了優化。

-optimizations optimization_filter 
指定要在更細粒度的級別啟用和禁用的優化。 僅適用於優化。 這是一個專家選項。

-optimizationpasses n 
指定要執行的優化通過次數。 預設情況下,執行單程。 多次通過可能會導致進一步的改進。 如果在優化通過後沒有找到改進,則優化結束。 僅適用於優化。

-assumenosideeffects class_specification 
指定沒有任何副作用的方法(可能返回值除外)。 在優化步驟中,ProGuard會刪除對這些方法的調用,如果可以確定不使用返回值。例如,你可以指定方法System.out(),以便 用該選項來刪除日誌記錄代碼。 註意,該選項 僅適用於優化。 除非你很清楚這個方法的作用,否則請勿使用這個選項!

-allowaccessmodification 
指定在處理過程中可以擴展類和類成員的訪問修飾符。 這可以改善優化步驟的結果。

-mergeinterfacesaggressively 
指定介面可能被合併,即使它們的實現類不實現所有介面方法。 這可以通過減少類的總數來減少輸出的大小。

混淆

-dontobfuscate 不混淆輸入的類文件 
-obfuscationdictionary {filename} 使用給定文件中的關鍵字作為要混淆方法的名稱 
-overloadaggressively 混淆時應用侵入式重載 
-useuniqueclassmembernames 確定統一的混淆類的成員名稱來增加混淆 
-flattenpackagehierarchy {package_name} 重新包裝所有重命名的包並放在給定的單一包中 
-repackageclass {package_name} 重新包裝所有重命名的類文件中放在給定的單一包中 
-dontusemixedcaseclassnames 混淆時不會產生形形色色的類名 
-keepattributes {attribute_name,…} 保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses. 
-renamesourcefileattribute {string} 設置源文件中給定的字元串常量

在配置過程中可以使用通配符,關於通配符的說明如下,

通配符說明
? 匹配任何單字元。
* 匹配除了包分隔符或目錄分隔符之外的任何字元。
** 匹配任何字元的名稱

自定義要保留的代碼

通常來說,預設 ProGuard 配置文件 (proguard-android.txt) 足以滿足需要,ProGuard 會移除所有(並且只會移除)未使用的代碼。但是對許多情況進行正確分析時,可能會移除有用的代碼。 
以下幾種情況下它可能錯誤移除有用代碼:

  • 當應用引用的類只來自 AndroidManifest.xml 文件時
  • 當應用調用的方法來自 Java 原生介面 (JNI) 時
  • 當應用在運行時(例如使用反射或自檢)操作代碼時
  • 當使用Parcelable的子類和Creator靜態成員變數時
  • 當使用GSON、fastjson等框架時,所寫的JSON對象類如果進行混淆會造成無法將JSON解析成對應的對象
  • 當使用第三方開源庫或者引用其他第三方的SDK包時
  • 當有用到WEBView的JS調用時

在進行應用測試時應該能夠發現這些因不當移除而導致的錯誤,具體也可查看 usage.txt 的內容來檢查移除了哪些代碼。 
例如類似下麵這樣的錯誤,我們就需要配置keep這些類不被混淆

10:47:34.635 [ERROR] [system.err] Warning: com.kennyc.view.MultiStateView$1: can't find referenced method 'com.kennyc.view.MultiStateView$ViewState[] values()' in program class com.kennyc.view.MultiStateView$ViewState
10:47:34.636 [ERROR] [system.err] Warning: com.kennyc.view.MultiStateView$1: can't find referenced field 'com.kennyc.view.MultiStateView$ViewState LOADING' in program class com.kennyc.view.MultiStateView$ViewState

配置內容如下即可解決問題:

-keep class com.kennyc.**

在AndroidMainfest中的類不會混淆,四大組件和Application的子類和Framework層下所有的類預設不會進行混淆,android提供的預設配置中都有。以下就是Android SDK中預設的ProGuard配置,即proguard-android.txt的內容

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.

-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

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

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

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
-dontwarn android.support.**

# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep

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

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

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

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

列舉一些庫的混淆配置

##---------------Begin: proguard configuration for Twitter  ----------
-dontwarn com.squareup.okhttp.**
-dontwarn com.google.appengine.api.urlfetch.**
-dontwarn rx.**
-dontwarn retrofit.**
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-keep class retrofit.** { *; }
-keepclasseswithmembers class * {
    @retrofit.http.* <methods>;
}
##---------------End: proguard configuration for Twitter  ----------

  

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }

# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
##---------------End: proguard configuration for Gson  ----------

  

##---------------Begin: proguard configuration for Glide  ----------
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
##---------------End: proguard configuration for Glide  ----------

  

##---------------Begin: proguard configuration for EventBus  ----------
-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);
#}
##---------------End: proguard configuration for EventBus  ----------

  

##---------------Begin: proguard configuration for Paper  ----------
#1.Keep data classes:
-keep class com.bloomsky.android.model.** { *; }
#2.alternatively you can implement Serializable for all your data classes and keep all of them using:
#-keep class * implements java.io.Serializable { *; }
##---------------End: proguard configuration for Paper  ----------

  

##---------------Begin: proguard configuration for retrofit2  ----------
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
##---------------End: proguard configuration for retrofit2  ----------

移除調試log代碼的配置

移除Log類列印各個等級日誌的代碼,打正式包的時候可以做為禁log使用,這裡可以作為禁止log列印的功能使用,另外的一種實現方案是通過BuildConfig.DEBUG的變數來控制

-assumenosideeffects class android.util.Log {  
    public static *** v(...);  
    public static *** i(...);  
    public static *** d(...);  
    public static *** w(...);  
    public static *** e(...);  
} 

  

恢復混淆前的堆棧信息

當混淆後的代碼輸出一個堆棧信息時,方法名是不可識別的,這使得調試變得很困難,甚至是不可能的。幸運的是,當ProGuard運行時,它都會輸出一個/build/outputs/mapping/release/mapping.txt文件,而這個文件中包含了原始的類,方法和欄位名被映射成的混淆名字。 
retrace.bat腳本(Window)或retrace.sh腳本(Linux,Mac OS X)可以將一個被混淆過的堆棧跟蹤信息還原成一個可讀的信息。它位於/tools/proguard文件夾中。執行retrace工具的語法如下: 
retrace.bat|retrace.sh [-verbose] mapping.txt [] 
例如: 
./retrace.sh -verbose mapping.txt obfuscated_trace.txt 
如果你沒有指定,retrace工具會從標準輸入讀取。

原文地址:http://blog.csdn.net/ocean20/article/details/67634130 
更多關於ProGuard的信息可以訪問, 
https://www.guardsquare.com/en/proguard/manual/examples

  

 

  

  

  

  

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文轉自:https://stackoverflow.com/questions/48135889/writing-nvarchar-to-a-text-file According to the Scripting.FileSystemObject documentation, the Creat ...
  • 查找列名等於某一字元串: select * from table where column like '%string%' 查找列名不等於某一字元串 select * from table where column not like '%string%' ...
  • 1 select t1.empno, t1.ename, t1.deptno, t1.sal 2 from emp t1 3 inner join ( 4 select t2.deptno, max(sal) max_sal 5 from emp t2 6 group by t2.deptno ) ... ...
  • 本文來自 網易雲社區 。 Join操作是資料庫和大數據計算中的高級特性,大多數場景都需要進行複雜的Join操作,本文從原理層面介紹了SparkSQL支持的常見Join演算法及其適用場景。 Join背景介紹 Join是資料庫查詢永遠繞不開的話題,傳統查詢SQL技術總體可以分為簡單操作(過濾操作-wher ...
  • 本文來自 網易雲社區 。 Dolphin 是猛獁平臺里的一個機器學習功能模塊,提供給數據科學家進行機器學習的演算法開發、模型訓練和服務發佈,提供分散式全功能深度學習框架,易學易用,高效靈活,支持 Tensorflow、MXNet、Caffe、Spark 等多種機器或深度學習框架,最大可能的挖掘出數據的 ...
  • 今天查詢表的時候報無效的數字。查看表,都是varchar。 最後發現在進行關聯表操作的時候,其中一個id的類型是number。正常情況下,字元串和數字的比較是可以的。這裡只能給數字加上to_char解決問題。 出現這個問題,一定是存在number欄位,仔細查看 ...
  • 一. DML觸發器; 二. DDL觸發器; 三. LOGON 觸發器; ...
  • 一、資料庫簡介 資料庫概述 資料庫(database)是按照數據結構來組織,存儲和管理數據的倉庫,它產生與距今五十年前. 簡單來說是本身可視為電子化的文件櫃--存儲電子文件的處所,用戶可以對文件中的數據運行新增,截取,更新,刪除等操作。 常見的數據模型 1. 層次結構模型:層次結構模型實質上是一種有 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...