Android代碼混淆

Android知識總結(jié)

一、配置( 項目的app/build.gradle)

    buildTypes {
        release {
            /*打開混淆*/
            minifyEnabled true
            /*打開資源壓縮*/
            shrinkResources true
            zipAlignEnabled true // Zipalign優(yōu)化 
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

proguard-android.txt 是官方提供的通用混淆配置,文件路徑在 \sdk\tools\proguard\proguard-android.txt
proguard-rules.pro 即自定義配置文件

            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    file('proguard-rules.pro'),
                    project.ext.LiteDir + 'buildOperation/proguard.cfg',
                    file('../PluginSDK/proguard-rules.pro'),
                    file('../LibThemeEngine/proguard-rules.pro'),

二、混淆為什么要保留類名或方法名?

  • 1、讓C/C++程序可以通過jni使用對應(yīng)的java方法
  • 2、四大組件由于在AndroidManifest.xml里面注冊了,所以需要保留。
  • 3、R文件混淆會導(dǎo)致引用錯誤。
  • 4、第三方架包有的已經(jīng)經(jīng)過混淆了,再次混淆會導(dǎo)致找不到類名或者方法名

三、什么時候不被混淆?

一般以下情況都會不混淆:

  • 1、使用了自定義控件那么要保證它們不參與混淆
  • 2、使用了枚舉要保證枚舉不被混淆
  • 3、對第三方庫中的類不進行混淆
  • 4、運用了反射的類也不進行混淆
  • 5、使用了 Gson 之類的工具要使 JavaBean 類即實體類不被混淆
  • 6、靜態(tài)成員JNI中調(diào)用的類
  • 7、有用到 WebViewJS 調(diào)用也需要保證寫的接口方法不混淆,原因和第一條一樣
  • 8、Serializable,Parcelable的子類和 Creator 靜態(tài)成員變量不混淆,否則會產(chǎn)生 Android.os.BadParcelableException 異常
  • 9、四大組件 ,自定義的Application

四、混淆語法

  • 2.1 基本規(guī)則
    兩個常用的混淆命令,注意一顆星表示只是保持該包下的類名,而子包下的類名還是會被混淆;而兩顆星表示把本包和所包含的子包下的類名都保留。
-keep class cn.hadcn.test.**
-keep class cn.hadcn.test.*

如果既想保持類名,又想保持里面的內(nèi)容不被混淆,就執(zhí)行以下方法

 -keep class com.example.bean.** { *; }

在此基礎(chǔ)上,我們也可以使用Java的基本規(guī)則來保護特定類不被混淆,比如我們可以用extend,implement等這些Java規(guī)則。如下例子就避免所有繼承Activity的類被混淆

保留我們使用的四大組件,自定義的Application等等這些類不被混淆
因為這些子類都有可能被外部調(diào)用

-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
  • 2.2、基本混淆模板
    對于一些基本指令的添加
#############################################
#
# 對于一些基本指令的添加
#
#############################################
#保證使用同一套 mapping 文件,從而保證前后打包一直。
#mapping文件時混淆前后文件的映射關(guān)系
-applymapping mapping.txt
# 代碼混淆壓縮比,在0~7之間,默認為5,一般不做修改
-optimizationpasses 5
# 混合時不使用大小寫混合,混合后的類名為小寫
-dontusemixedcaseclassnames
# 指定不去忽略非公共庫的類
-dontskipnonpubliclibraryclasses
# 這句話能夠使我們的項目混淆后產(chǎn)生映射文件# 包含有類名->混淆后類名的映射關(guān)系
-verbose
# 指定不去忽略非公共庫的類成員
-dontskipnonpubliclibraryclassmembers
# 不做預(yù)校驗,preverify是proguard的四個步驟之一,Android不需要preverify,去掉這一步能夠加快混淆速度。
-dontpreverify
# 保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature
#將文件來源重命名為“SourceFile”字符串
-renamesourcefileattribute SourceFile
# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable
# 避免混淆Annotation、內(nèi)部類、泛型、匿名類
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod
# 指定混淆是采用的算法,后面的參數(shù)是一個過濾器# 這個過濾器是谷歌推薦的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#把混淆類中的方法名也混淆了
-useuniqueclassmembernames
#優(yōu)化時允許訪問并修改有修飾符的類和類的成員
-allowaccessmodification

Android開發(fā)中一些需要保留的公共部分

#############################################
#
# Android開發(fā)中一些需要保留的公共部分
#
#############################################
# 保留我們使用的四大組件,自定義的Application等等這些類不被混淆# 因為這些子類都有可能被外部調(diào)用
-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

# 保留support下的所有類及其內(nèi)部類
-keep class android.support.** {*;}
# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留R下面的資源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
# 保留在Activity中的方法參數(shù)是view的方法,
# 這樣以來我們在layout中寫的onClick就不會被影響
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
# 保留枚舉類不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# 保留我們自定義控件(繼承自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);
}
# 保留Parcelable序列化類不被混淆
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的類不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
# 對于帶有回調(diào)函數(shù)的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}
# 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);
}

# assume no side effects:刪除android.util.Log輸出的日志
-assumenosideeffects class android.util.Log {
    public static *** v(...);
    public static *** d(...);
    public static *** i(...);
    public static *** w(...);
    public static *** e(...);
}

#保留Keep注解的類名和方法
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
    @android.support.annotation.Keep *;
}

#fastjson混淆
-keepattributes Signature
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.**{*;}
-keep class com.alibaba.fastjson.**{*; }
-keep public class com.ninstarscf.ld.model.entity.**{*;}

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

# webview
-keep class android.webkit.JavascriptInterface {*;}
#自定義webview接口實現(xiàn)類
-keep public class com.gjmetal.app.ui.ball.**{*;}

# 微信支付
-dontwarn com.tencent.mm.**
-dontwarn com.tencent.wxop.stat.**
-keep class com.tencent.mm.** {*;}
-keep class com.tencent.wxop.stat.**{*;}

# 支付寶錢包
-dontwarn com.alipay.**
-dontwarn HttpUtils.HttpFetcher
-dontwarn com.ta.utdid2.**
-dontwarn com.ut.device.**
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-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 *;}
-keep class com.alipay.mobilesecuritysdk.*
-keep class com.ut.*

五、其他混淆

然后需要在項目生成的混淆腳本中添加過濾混淆的條件

# Glide
-dontwarn com.bumptech.glide.**
-keep class com.bumptech.glide.**{*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

# Gson
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
# OkHttp3
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
# Okio
-dontwarn com.squareup.**
-dontwarn okio.**
-keep public class org.codehaus.* { *; }
-keep public class java.nio.* { *; }
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
# RxJava RxAndroid
-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;
}
#數(shù)據(jù)模型(實體類)
-keep class com.seekfangle.pad.bean.* {*;}
#第三方架包
-keep class  cn.com.** { *;}
-keep class  android_serialport_api.** { *;}

#butterknife
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepnames class * { @butterknife.InjectView *;}

#EventBus3.0
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

#友盟
-keep class com.umeng.** {*;}
-keepclassmembers class * {
   public <init> (org.json.JSONObject);
}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep public class com.gjmetal.app.R$*{
public static final int *;
}

#個推
-dontwarn com.igexin.**
-keep class com.igexin.** { *; }
-keep class org.json.** { *; }
-keep class android.support.v4.app.NotificationCompat { *; }
-keep class android.support.v4.app.NotificationCompat$Builder { *; }

#routes
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}


#ShareSdk
-keep class cn.sharesdk.**{*;}
-keep class com.sina.**{*;}
-keep class **.R$* {*;}
-keep class **.R{*;}
-keep class com.mob.**{*;}
-keep class m.framework.**{*;}
-dontwarn cn.sharesdk.**
-dontwarn com.sina.**
-dontwarn com.mob.**
-dontwarn **.R$*

#Picasso
-keep class com.parse.*{ *; }
-dontwarn com.parse.**
-dontwarn com.squareup.picasso.**
-keepclasseswithmembernames class * {
    native <methods>;
}

#GreenDao
-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.**

#百度定位混淆配置
-keep class vi.com.gdi.** { *; }
-keep public class com.baidu.** {*;}
-keep public class com.mobclick.** {*;}
-dontwarn com.baidu.mapapi.utils.*
-dontwarn com.baidu.platform.comapi.b.*
-dontwarn com.baidu.platform.comapi.map.*
#百度地圖混淆配置
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
-keep class mapsdkvi.com.** {*;}

#QQ分享
-dontwarn com.tencent.**
-keep class com.tencent.** {*; }

#微信分享
-keep class com.tencent.mm.opensdk.** {*;}
-keep class com.tencent.wxop.** {*;}
-keep class com.tencent.mm.sdk.** { *;}

六、檢查混淆結(jié)果

混淆過的包必須進行檢查,避免因混淆引入的bug。
一方面,需要從代碼層面檢查。使用上文的配置進行混淆打包后在<module-name>/build/outputs/mapping/release/目錄下會輸出以下文件:
dump.txt
描述APK文件中所有類的內(nèi)部結(jié)構(gòu)
mapping.txt
提供混淆前后類、方法、類成員等的對照表
seeds.txt
列出沒有被混淆的類和成員
usage.txt
列出被移除的代碼
我們可以根據(jù) seeds.txt 文件檢查未被混淆的類和成員中是否已包含所有期望保留的,再根據(jù) usage.txt文件查看是否有被誤移除的代碼。
另一方面,需要從測試方面檢查。將混淆過的包進行全方面測試,檢查是否有 bug 產(chǎn)生。

七、解出混淆棧

混淆后的類、方法名等等難以閱讀,這固然會增加逆向工程的難度,但對追蹤線上 crash 也造成了阻礙。我們拿到 crash 的堆棧信息后會發(fā)現(xiàn)很難定位,這時需要將混淆反解。
<sdk-root>/tools/proguard/路徑下有附帶的的反解工具(Window 系統(tǒng)為proguardgui.bat,Mac 或 Linux 系統(tǒng)為proguardgui.sh)。
這里以 Window 平臺為例。雙擊運行 proguardgui.bat 后,可以看到左側(cè)的一行菜單。點擊 ReTrace,選擇該混淆包對應(yīng)的 mapping 文件(混淆后在 <module-name>/build/outputs/mapping/release/路徑下會生成 mapping.txt 文件,它的作用是提供混淆前后類、方法、類成員等的對照表),再將 crash 的 stack trace 黏貼進輸入框中,點擊右下角的 ReTrace ,混淆后的堆棧信息就顯示出來了。
以上使用 GUI 程序進行操作,另一種方式是利用該路徑下的 retrace 工具通過命令行進行反解,命令是
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
例如:

retrace.bat -verbose mapping.txt obfuscated_trace.txt
注意事項:
所有在 AndroidManifest.xml涉及到的類已經(jīng)自動被保持,因此不用特意去添加這塊混淆規(guī)則。(很多老的混淆文件里會加,現(xiàn)在已經(jīng)沒必要)
proguard-android.txt已經(jīng)存在一些默認混淆規(guī)則,沒必要在proguard-rules.pro 重復(fù)添加

混淆的文件對照表

mapping.txt中的混淆前后的類對照如下:

//混淆前的文件 -> 混淆后的文件
org.aspectj.runtime.reflect.SourceLocationImpl -> c.a.b.b.g:
    java.lang.String fileName -> a
    int line -> b
    24:28:void <init>(java.lang.Class,java.lang.String,int) -> <init>
    31:31:java.lang.String getFileName() -> a
    32:32:int getLine() -> b
    36:36:java.lang.String toString() -> toString
org.aspectj.runtime.reflect.StringMaker -> c.a.b.b.h:
    org.aspectj.runtime.reflect.StringMaker middleStringMaker -> g
    org.aspectj.runtime.reflect.StringMaker longStringMaker -> h
    org.aspectj.runtime.reflect.StringMaker shortStringMaker -> f
    int cacheOffset -> e
    boolean shortTypeNames -> a
    boolean includeArgs -> b
    boolean includeModifiers -> c
    boolean shortPrimaryTypeNames -> d
    33:69:void <clinit>() -> <clinit>
    19:28:void <init>() -> <init>

八、自定義混淆規(guī)則

在上文“混淆配置”中有這樣一行代碼

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

這行代碼定義了混淆規(guī)則由兩部分構(gòu)成:位于 SDK 的tools/proguard/ 文件夾中的 proguard-android.txt的內(nèi)容以及默認放置于模塊根目錄的proguard-rules.pro 的內(nèi)容。前者是 SDK 提供的默認混淆文件,后者是開發(fā)者自定義混淆規(guī)則的地方。

九、常見的混淆指令

  • 1、 optimizationpasses代碼混淆壓縮比,在0~7之間,默認為5,一般不做修改
  • 2、 dontoptimize 不進行優(yōu)化
  • 3、 dontusemixedcaseclassnames 混合時不使用大小寫混合,混合后的類名為小寫
  • 4、 dontskipnonpubliclibraryclasses 指定不去忽略非公共庫的類
  • 5、 dontpreverify 不做預(yù)校驗
  • 6、 dontwarn 不提示警告,和keep可以說是形影不離,尤其是處理引入的library時.
  • 7、 verbose 混淆時是否記錄日志
  • 8、 optimizations 指定混淆是采用的算法,后面的參數(shù)是一個過濾器
  • 9、 keep 保留類和類中的成員,防止被混淆或移除
  • 10、keepnames 保留類和類中的成員,防止被混淆,成員沒有被引用會被移除
  • 11、 keepclassmembers 只保留類中的成員,防止被混淆或移除
  • 12、keepclassmembernames 只保留類中的成員,防止被混淆,成員沒有引用會被移除
  • 13、 keepclasseswithmembers 保留類和類中的成員,防止被混淆或移除,保留指明的成員
  • 14、 keepclasseswithmembernames 保留類和類中的成員,防止被混淆,保留指明的成員,成員沒有引用會被移除
  • 15、dontshrink 不壓縮類文件。默認情況下會壓縮所有的類文件,除了那些用keep聲明和被這些類依賴的class
    更多詳細的請到官網(wǎng)

十、規(guī)則

  [保持命令] [類] {
    [成員] 
}

“類”代表類相關(guān)的限定條件,它將最終定位到某些符合該限定條件的類。它的內(nèi)容可以使用:

  • 具體的類
  • 訪問修飾符public、protected、private
  • 通配符*,匹配任意長度字符,但不含包名分隔符(.)
  • 通配符**,匹配任意長度字符,并且包含包名分隔符(.)
  • extends,即可以指定類的基類
    *implement,匹配實現(xiàn)了某接口的類
  • $,內(nèi)部類

成員代表類成員相關(guān)的限定條件,它將最終定位到某些符合該限定條件的類成員。它的內(nèi)容可以使用:

  • <init>匹配所有構(gòu)造器
  • <fields> 匹配類中的所有字段
  • <methods> 匹配所有方法
  • 通配符*,匹配任意長度字符,但不含包名分隔符(.)
  • 通配符**,匹配任意長度字符,并且包含包名分隔符(.)
  • 通配符***,匹配任意參數(shù)類型
  • ,匹配任意長度的任意類型參數(shù)。比如void test(…)就能匹配任意void test(String a)或者是 void test(int a, String b)這些方法。
  • 訪問修飾符public、protected、private
指定成員
\ 代表任意構(gòu)造方法.
\ 代表任意域.
\ 代表任意方法.
* 代表任意成員(包括成員變量和方法).

類型描述通配符
% 表示任意基本類型(int,char等,但是不包括void).
? 表示類名中的任意單個字符.
* 表示類名中的任意多個字符,不包括分隔符(.).
** 表示類名中的任意多個字符,包括分隔符(.).
*** 表示任意類型.
... 表示任意多個任意類型的參數(shù).

舉個例子,假如需要將com.biaobiao.test包下所有繼承Activity的public類及其構(gòu)造函數(shù)都保持住,可以這樣寫:

 -keep public class com.biaobiao.test.** extends Android.app.Activity {
    <init>
}

十一、常用自定義混淆規(guī)則

1、不混淆某個類

-keep public class com.biaobiao.example.Test { *; }

2、不混淆某個包所有的類

-keep class com.biaobiao.test.** { *; }

3、不混淆某個類的子類

-keep public class * extends com.biaobiao.example.Test { *; }

4、不混淆某個接口的實現(xiàn)

-keep class * implements com.biaobiao.example.TestInterface { *; }

5、不混淆某個類的構(gòu)造方法

-keepclassmembers class com.biaobiao.example.Test { 
    public <init>(); 
}
//保持指定類的所有字段
-keep class com.xy.myapp.MyClass { public <fields>; }

6、不混淆某個類的特定的方法

-keepclassmembers class com.biaobiao.example.Test { 
    public void test(java.lang.String); 
}
//保持指定類的所有方法
-keep class com.xy.myapp.MyClass { public <methods>; }
//保持用指定參數(shù)作為形參的方法
-keep class com.xy.myapp.MyClass { public <methods>(java.lang.String); }

7、不混淆某個類的內(nèi)部類

//所有內(nèi)部類
-keep class com.biaobiao.example.Test$* { *; }
//內(nèi)部類 Builder
-keep class com.biaobiao.example.Test$Builder { *; }
//保持MyClass內(nèi)部類JavaScriptInterface中的所有public內(nèi)容。
-keepclassmembers class com.xy.myapp.MyClass$JavaScriptInterface { 
    #保持該類下所有的共有內(nèi)容不被混淆
    public *;
    #保持該類下所有的私有方法不被混淆
    private * ;
 }

8、混淆引入的 library

//使指定的類不輸出警告信息
-dontwarn purang.purang_shop.**
-keep class purang.purang_shop.**{*;}

十二、組件模塊定義混淆規(guī)則

子模塊混淆文件的指定是通過consumerProguardFiles這個屬性來指定的,并不是proguardFiles屬性,而且我們無需配置其他的選項,只需要配置consumerProguardFiles屬性就可以。該屬性表示在打包的時候會自動尋找該module下我們指定的混淆文件對代碼進行混淆。可以把一些公共的混淆定義在子模塊中。

   release {
            consumerProguardFiles   'proguard-rules.pro'
        }

consumerProguardFiles作用:

  • proguard.txt會被打包進aar中
  • 此配置只對aar進行混淆。
  • 此配置只對庫文件有效,對應(yīng)用程序無效。

當app模塊將全部代碼匯總混淆時,Library 模塊會被打包為release aar,然后被引用匯總,通過proguard-rule.pro規(guī)則各自混淆,保證只混淆一次。

組件化工程中具體混淆用法:
我們可以將固定的第三方混淆放到base模塊的proguard-rule.pro文件中,每個模塊獨有的第三方引用庫混淆放到各自的proguard-rule.pro文件中,在app模塊的proguard-rule.pro文件中放入Android基礎(chǔ)屬性的混淆聲明,如四大組件和全局的混淆等配置。這樣可以最大限度的完成混淆解耦操作。

十三、自定義要保持的資源

資源壓縮包含了“合并資源”和“移除資源”兩個流程?!昂喜①Y源”流程中,名稱相同的資源被視為重復(fù)資源會被合并。需要注意的是,這一流程不受shrinkResources屬性控制,也無法被禁止, gradle 必然會做這項工作。
當我們開啟了資源壓縮之后,系統(tǒng)會默認替我們移除所有未使用的資源,假如我們需要保留某些特定的資源,可以在我們項目中創(chuàng)建一個被 <resources> 標記的 XML 文件(如 res/raw/keep.xml),并在tools:keep屬性中指定每個要保留的資源,在tools:discard屬性中指定每個要舍棄的資源。這兩個屬性都接受逗號分隔的資源名稱列表。同樣,我們可以使用字符 * 作為通配符。

<?xml version="1.0" encoding="utf-8"?><resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/activity_video*,@layout/dialog_update_v2"
    tools:discard="@layout/unused_layout,@drawable/unused_selector" />

十四、移除替代資源

一些替代資源,例如多語言支持的 strings.xml,多分辨率支持的 layout.xml 等,在我們不需要使用又不想刪除掉時,可以使用資源壓縮將它們移除。我們使用 resConfig 屬性來指定需要支持的屬性,例如

  android {
      defaultConfig {
          ...
          resConfigs "en", "fr"
      }
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇文章:自己在混淆的時候整理出比較全面的混淆方法,比較實用,自己走過的坑,淌出來的路。請大家不要再走回頭路,可能...
    Zane_Samuel閱讀 55,627評論 8 93
  • 聲明 這篇文章更多的是做一個整理,內(nèi)容來自于ProGuard官方文檔以及各種博客等,相關(guān)文章的鏈接在參考目錄里,感...
    夷陵小祖閱讀 3,805評論 0 23
  • 混淆是 Android 打包過程中最重要的流程之一,基本上所有 app 都應(yīng)該開啟混淆,增加app的安全性?;煜?..
    shenhuniurou閱讀 1,661評論 0 2
  • 混淆代碼能有效防止被反編譯,防止自己的勞動成果被別人竊取; ProGuard是一個開源的Java代碼混淆器。它可以...
    appzy閱讀 2,404評論 2 18
  • 什么是代碼混淆 代碼混淆就是將代碼中的各種元素,如變量,方法,類和包的名字改寫成無意義的名字,增加項目反編譯后被讀...
    蝸牛家族史閱讀 5,321評論 1 4

友情鏈接更多精彩內(nèi)容