什么是代碼混淆
代碼混淆(Obfuscated code)亦稱花指令,是將計(jì)算機(jī)程序的代碼,轉(zhuǎn)換成一種功能上等價(jià),但是難于閱讀和理解的形式的行為。代碼混淆可以用于程序源代碼,也可以用于程序編譯而成的中間代碼。執(zhí)行代碼混淆的程序被稱作代碼混淆器。目前已經(jīng)存在許多種功能各異的代碼混淆器。
將代碼中的各種元素,如變量,函數(shù),類的名字改寫成無意義的名字。比如改寫成單個(gè)字母,或是簡(jiǎn)短的無意義字母組合,甚至改寫成“__”這樣的符號(hào),使得閱讀的人無法根據(jù)名字猜測(cè)其用途。重寫代碼中的部分邏輯,將其變成功能上等價(jià),但是更難理解的形式。比如將for循環(huán)改寫成while循環(huán),將循環(huán)改寫成遞歸,精簡(jiǎn)中間變量,等等。打亂代碼的格式。比如刪除空格,將多行代碼擠到一行中,或者將一行代碼斷成多行等等。
(以上摘自百度百科)
一些吐槽:
1.混淆后難以理解,在調(diào)試過程中,崩潰等問題出現(xiàn)后,無法從日志中直觀地看懂錯(cuò)誤信息,加大了調(diào)試難度。
2.并不能完全阻止反向,混淆本身就是為了阻止反編譯,但它的機(jī)制是將類名、方法、變量等名字改為單個(gè)字母之類的東西,只能加大閱讀和反向的難度,并不是無法反向。
3.給反射和Native帶來不便,java反射機(jī)制和jni調(diào)用的機(jī)制,都涉及到確定的類名和方法名等信息,經(jīng)過混淆后,原來正常的邏輯各種出錯(cuò)。
不要問我為啥不說優(yōu)點(diǎn),因?yàn)椴恍枰獌?yōu)點(diǎn),它本身的意義就是最大的優(yōu)點(diǎn),就算槽點(diǎn)再多,該用還是要用啊 (ˉ▽ˉ;)
混淆配置
本文只討論在Android Studio平臺(tái)下開發(fā)的場(chǎng)景。
1.開啟混淆
要使用代碼混淆,需要在當(dāng)前module下的 build.gradle 文件中android節(jié)點(diǎn)下做如下配置:
android {
......
buildTypes {
release {
minifyEnabled true //開啟代碼混淆
shrinkResources true //此句可選是否精簡(jiǎn)無用資源
signingConfig signingConfigs.release
//指定混淆時(shí)用到的配置文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
......
}
......
}
具體的混淆相關(guān)配置要到當(dāng)前module下的 proguard-rules.pro 文件中進(jìn)行配置。
首先是安卓四大組件和其他需要被反射的類。(對(duì)應(yīng)到j(luò)son接口的實(shí)體類在反序列化時(shí)為反射機(jī)制,四大組件聲明在清單文件中,也是由反射實(shí)例化)
-optimizationpasses 5 //指定代碼壓縮級(jí)別
-keep public class * extends android.app.Application
-keep public class * extends android.app.Activity
-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
//一般我們的實(shí)體類要實(shí)現(xiàn) Serializable 接口。(或Parcelable)
-keep classmembers class * implements java.io.Serializable {*;}
然后是引用到的第三方庫(kù),需要避免被混淆。否則,鬼知道它里面哪個(gè)類被反射或和Native交互。所以直接按照包名全部屏蔽。下面是一些我自己常用的三方庫(kù)。
# okhttp retrofit rxjava
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn retrofit2.**
-dontwarn rx.**
-keep class okhttp3.**{ *; }
-keep class okio.** {*;}
-keep class retrofit2.** { *; }
-keep class rx.** { *; }
# rxjava
-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;
}
# json相關(guān)
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keepclassmembers class * { public <init>(org.json.JSONObject); }
# 極光
-dontwarn cn.jpush.**
-dontwarn cn.jiguang.**
-keep class cn.jpush.**{*;}
-keep class cn.jiguang.** { *; }
# 百度(地圖?)
-keep class com.baidu.** {*;}
-keep class vi.com.gdi.bgl.** {*;}
# Glide
-dontwarn com.bumptech.glide.**
-keep class com.bumptech.glide.**{ *; }
# ijkplayer
-keep class tv.danmaku.ijk.media.**{*;}
# zxing
-keep class com.google.zxing.**{*;}
# 支付寶
-keep class com.alipay.**{*;}
# 微信
-keep class com.tencent.**{*;}
如果你的項(xiàng)目中用到一些其它第三方的庫(kù),記得添加進(jìn)來,一般只需要keep一下就好了。
好了,配置完以后,打個(gè)包試試吧。不要直接run as 或者 debug,那樣是不走這個(gè)配置的,打包正常的話就是配置好啦,如果報(bào)錯(cuò)的話,記得去看gradle輸出的日志,看看是找不到類還是什么的,定位到需要屏蔽混淆的類。
------(˙<>˙)/------完。
轉(zhuǎn)載請(qǐng)注明出處,[@via 小風(fēng)風(fēng)吖-基于AS的代碼混淆配置 蟹蟹。