Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 混淆語法

android 混淆語法

編輯:關於Android編程

初步了解手動混淆配置的規則

手動添加的配置,一般以”-keep”開頭,常用的配置命令分別示例如下:
假設android工程中有一個接口和一個類:

package com.ticktick.example;

public interface TestInterface {
    public void test();
}

public class Test {

    private String mTestString;
    private final int mMinValue;
    private final int mMaxValue;

    public Test( int min, int max){
        mMinValue = min;
        mMaxValue = max;
    }

    public int getMinValue() {
        return mMinValue;
    }

    public int getMaxValue() {
        return mMaxValue;
    }

    public void setTestString(String testStr ) {
        mTestString = testStr;
    }
}

1.不混淆某個類的構造函數

例如不混淆Test類的構造函數

-keepcalssmembers clsss com.ticktick.example.Text{
    public (int,int)
}

2.不混淆某個包下所有的類或者指定的類

例如不混淆package com.ticktick.example下的所有的類/接口

#不混淆這個包下的所有的類
-keep class com.ticktick.example.**{*;}

例如不混淆com.ticktick.example.Text類

-keep class com.ticktick.example.Text{*;}

如果希望不混淆某個接口,則把上述命令的class替換為interface即可.

3.不混淆某個類的特定的函數

例如不混淆com.ticktick.example.Test類中的setTestString函數

-keepclassmembers class com.ticktick.example.Test{
    public void setTestString(java.lang.String);
}

4.不混淆某個類的子類,某個接口的實現

例如不混淆com.ticktick.example.Test的子類

-keep public class * extend com.ticktick.example.Test

例如不混淆com.ticktick.example.TestInterface的實現

-keep class * implements com.ticktick.example.TestInterface{
    public static final com.ticktick.example.TestInterface$Creator *;
}

5.注意第三方依賴包

例如添加android-support-v4.jar依賴包

-libraryjars libs/android-support-v4.jar

-dontwarn android.support.v4.**{*;}
-keep class android.support.v4.**{*;}
-keep interface android.support.v4.**{*;}

注意添加dontwarn,因為默認情況下proguard會檢查每一個引用是否正確,但是第三方庫裡往往有些不會用到的類,沒有正確引用,所有如果不配置的話,系統會報錯.

ProGuard常用語法

枯澀的語法總是避免不了的.上面的小例子對簡單的配置進行了一下描述,下面是詳細的語法.

保留 keep的配置

-keep {Modifier(修飾符)}{class_specification(類規范)} 保護指定的類和類的成員
#例如對一個可執行jar包來說,需要保護main的入口類,對一個類庫來說需要保護它的所有public元素
-keep public class MyMain{
    public static void main(java.lang.String[]);
}
-keepclassmembers {Modifier}{class_specification}
保護指定類的成員,如果此類也受到保護他們會保護的更好
#例如指定繼承了Serizalizable的類的如下成員不被混淆,成員屬性和方法,非私有的屬性非私有的方法.
-keepclassmembers class * implements java.io.Serializable{
    static final long seriaVersionUID;
    !private ;
    !private ;
    private void writeObject(java.io.ObjectOuputStream);
}
-keepclasseswithmembers{Modifier}{class_specification}保護指定成員的類,根據成員確定一些將要被保護的類

就是說如果一個類含有以下的成員,那麼這個類會被保護

#保護含有main方法的類以及這個類的main方法
-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}
-keepnames {Modifier}{class_specification} 這個是-keep,allowshrinking {Modifier}{class_specification}的簡寫.意思是說允許壓縮操作,如果在壓縮過程中沒有被刪除,那麼類名和該類中的成員的名字會被保護 -keepclassmembernames {Modifier}{class_specification}如果在壓縮過程中沒有被刪除在保護這個類中的成員

-keepclasseswithmembers {Modifier}{class_specification}如果在壓縮過程中該類沒有被刪除,同樣如果該類中有某個成員字段或者方法,那麼保護這個類和這個方法.

-printseeds{filename}將keep的成員輸出到文件或者打印到標准輸出流.

代碼壓縮配置 shrinker配置

-dontshrink 聲明不壓縮文件.默認情況下,除了-keep相關指定的類,其它所有的沒有被引用到的類都會被刪除,每次優化(optimizate)操作之後也會執行一次壓縮操作,因為每次優化操作可能刪除一部分不在需要的類. -printusage{filename} 將被刪除的元素輸出到文件,或者打印到保准輸出流 whyareyoukeeping {class_specification} 打印為什麼嗎一個類或類的成員被保護,這對檢查一個輸出文件中的類的結果有幫助.

代碼優化配置 optimizate配置

-dontoptimize 聲明不優化的文件.默認情況下,優化選項是開啟的,並且所有的優化都是在字節碼層進行的. -optimizations 更加細粒度的聲明優化開啟或者關閉. -optimizationpasses n 指定執行幾次優化,默認情況只執行一次優化,執行多次優化可以提高優化的效果.但是如果執行一次優化之後沒有效果,就會停止優化,剩下的設置次數不在執行.

混淆配置 obfuscate配置

-dontobfuscate 聲明不混淆 默認情況下,混淆是開啟的.除了keep配置中的類其它的類或者類的成員混淆後會改成隨機簡短的名字 printmapping{filename} 指定輸出新舊元素名的對照表的文件,可以通過在build.gradle中的配置,進行自動保存.這個在異常追蹤的時候非常有用可以參考這個粗暴接觸混淆 -applymapping {filename}指定重用一個已經寫好的map文件作為新舊元素名的映射.元素名已經存在的就按照該文件中的配置進行,對於沒存在的就重新賦一個新的名字 obfuscationdictionary {filename}指定一個文本文件用來生成混淆後的名字.默認情況下混淆後的名字一般為a,b,c.通過這個選項配置的字典文件,可以使用一些非英文字符做為類名,成員名,方法名.需要注意的是添加了字典並不會顯著提高混淆的效果,只不過是更不利與人類的閱讀。正常的編譯器會自動處理他們,並且輸出出來的jar包也可以輕易的換個字典再重新混淆一次。最有用的做法一般是選擇已經在類文件中存在的字符串做字典,這樣可以稍微壓縮包的體積。
#查找字典文件的格式:一行一個單詞,空行忽略,重復忽略
# 這裡巧妙地使用java中的關鍵字作字典,混淆之後的代碼更加不利於閱讀
#
# This obfuscation dictionary contains reserved Java keywords. They can't
# be used in Java source files, but they can be used in compiled class files.
# Note that this hardly improves the obfuscation. Decent decompilers can
# automatically replace reserved keywords, and the effect can fairly simply be
# undone by obfuscating again with simpler names.
# Usage:
#     java -jar proguard.jar ..... -obfuscationdictionary keywords.txt
#
do
if
for
int
new
try
byte
case
char
else
goto
long
this
void
break
catch
class
const
final
float
short
super
throw
while
double
import
native
public
return
static
switch
throws
boolean
default
extends
finally
package
private
abstract
continue
strictfp
volatile
interface
protected
transient
implements
instanceof
synchronized
-classobfuscationdictionary {filename}指定一個混淆類名的字典,字典格式與-obfuscationdictionary相同 -packageobfuscationdictionary {filename}指定一個混淆包名的字段 -oberloadaggressively 混淆的時候大量使用重載,多個方法名使用同一個混淆名,但是它們的方法簽名不同,這可以使包的體積減小一部分也可以加大理解難度.

不過這個配置有一定的限制

Sun的JDK1.2上會報異常
Sun JRE 1.4上重載一些方法之後會導致序列化失敗
Sun JRE 1.5上pack200 tool重載一些類之後會報錯
java.lang.reflect.Proxy類不能處理重載的方法
-useuniqueclassmembernames 指定相同的混淆名對應相同的方法名,不同的混淆名對應不同的方法名.如果不設置這個選項,同一個類中將會有很多方法映射到相同的方法名.這項配置會稍微增加輸出文件中的代碼,但是它能夠保證 保存下來的mapping文件能夠在隨後的增量混淆中繼續被遵守,避免重新命名.比如說兩個接口擁有同名的方法和相同的簽名,如果沒有這個配置,在第一次打包混淆之後它們兩個方法可能會被賦予不同的混淆名.如果下一次添加代碼有一個類同時實現了這兩個接口,那麼混淆的時候必然會將兩個混淆後的方法名統一起來.這樣就必須要改混淆文件其中一處的配置,也就不能保證前後兩次混淆的mapping文件一致了(如果想用一份mappping文件迭代更新的話,這項配置比較有用). -dontusemixedcaseclassnames 指定在混淆的時候不使用大小寫混用的類名.默認情況下混淆後的類名可能同時包含大寫字母和小寫字母.這樣的jar並沒有什麼問題,只有在大小寫不敏感的window系統上解壓時,才會涉及問題.因為大小寫不區分,可能會導致部分文件在解壓的時候相互覆蓋. -keeppackagenames{package_filter} 聲明不混淆指定的包名,配置的過濾器是逗號隔開的一組包名.包名可以包含? *通配符,並且可以在前面加!否定符 -flatternpackagenames{packagename} 所有重命名的包都重新打包,並把所有的類移動到packagename包下面.如果沒有指定packagename或者packagename為”“,那麼所有的類都會被移動到根目錄下. -repackageclasses{package_name} 所有重新命名類都重新打包,並把它們移動到指定的packagename目錄下.這項配置會覆蓋-flatternpackagehierarchy的配置.他可以使代碼體積更小,並且更加難以理解.

需要注意的是如果需要從目錄中讀取資源文件,移動包的位置可能會導致異常.如果出現這個問題,就不要用這個配置了.

-keepattributes{attribute_filter} 指定受保護的屬性.可以有一個或者多個該配置項,每個配置後面跟隨的是java虛擬機和proguard支持的attribute(具體支持的屬性先看這裡),兩個屬性之間用逗號分隔.屬性名可以使用通配符,或者! 將某個屬性排除在外.當混淆一個類庫的時候至少要保持InnerClasses,Exceptions,Signature屬性.為了跟蹤異常信息,需要把SourceFile,LineNumberTable兩個屬性保留.如果代碼中有用到注解,需要Annotion屬性.
#可以分開寫
-keepattributes SourceFile, LineNumberTable
-keepattributes *Annotation*
-keepattributes EnclosingMethod
# 可以直接寫在一行
-keepattributes Exceptions, InnerClasses, Signature, Deprecated,
                SourceFile, LineNumberTable, *Annotation*, EnclosingMethod
-keepparameternames 指定被保護的方法的參數類型和參數名不被混淆.這項配置在混淆一些類庫的時候特別有用,因為根據IDE提示的參數名和參數類型,開發者可以根據語意獲得一些信息. -adaptclassstrings{classfilter}指定字符串常量如果與類名相同,也需要被混淆.如果沒有加classfilter,所有的符合要求的字符串常量都會被混淆;如果帶classfilter,只有在匹配的類中的字符串常量才會受此影響.例如在你的代碼中有大量的類名對應的字符串的hard-code,並且不想保留它們的本名,那就可以利用哦這項配置來完成. -adaptresourcefileanmes{file_filter} 如果資源文件與某類同名,那麼混淆後資源文件被命名為與之對應的類的混淆名.不加file_filter的情況下,所有資源文件都受此影響,加了file_filter的情況只有匹配的類才受此類的影響. -adaptresourcefilecontents{file_filter}指定資源文件的中的類名隨混淆後的名字更新.根據被混淆的名字的前後映射關系,更新文件中對應的包名和類名.

普通配置

-berbose 聲明在處理過程中輸出更多信息,添加這項配置之後,如果處理過程中出現異常,會輸出整個StackTrace而不是一條簡單的異常說明. -dontwarn {class_filter}聲明不輸出那些未找到的引用和一些錯誤,繼續混淆.配置中的class_filter是一串正則表達式.

通配符匹配規則

?      匹配單個字符
*      匹配類名中的任何部分,但不包含額外的包名
**    匹配類名中的任何部分,並且可以包含額外的包名
%    匹配任何基礎類型的類型名
...    匹配認識數量 任意類型的參數
   匹配任何構造器
  匹配任何字段名
*(當用在類內部時)   匹配任何字段和方法
$     指內部類 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved