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

Android混淆心得

編輯:關於Android編程

最近在做Android應用的混淆,踩了一些坑,這裡記錄分享下個人的心得。

混淆介紹

首先先簡單說一下什麼是混淆和混淆的作用,其實這個搜索下可以找到一堆官方的說法等等,這裡簡單口語敘述一下,混淆就是把代碼替換成a、b、c基本字母組成的代碼,比如一個方法名為:function(),混淆後可能會被替換成a()。

混淆的好處:

代碼混淆後閱讀性降低,反編譯後破譯程序難度提高 混淆後字節數減少,減少了應用了體積

前者只能說有一點作用,後者則需要看代碼的數量
當然不能忽視混淆的缺點:

混淆後,測試不充分可能導致某些功能不能使用

開啟混淆

混淆在Android Studio的項目中默認是關閉的,其中控制開關和規則配置文件分別由項目moudle中的build.gradleproguard-rules.pro控制,如下圖所示:

其中build.gradle中

keep 保留,例如keepattributes:表示保留屬性
dont 不要,例如dontwarn:表示不要提示警告
ignore 忽略,例如ignorewarning:表示忽略警告

混淆配置文件不檢查規則是否重復,如果兩條規則沖突,則采用白名單的,比如設置了開啟優化和不優化兩個選項後,無論順序,最終都會執行不優化的操作。

優化控制

這個是用於控制混淆是否開啟優化代碼,例如一些if/else語句可以被簡化等這些操作:

# 不優化
-dontoptimize

# 代碼循環優化次數,0-7,默認為5
-optimizationpasses 5

值得注意的是默認混淆配置文件開啟了-dontoptimize。

優化進階

開啟優化後可以設置下面的規則,assumenosideeffects表示指定的代碼無效,可以優化,最終效果表現為不執行。

# 混淆時所采用的優化規則
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

# 關閉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(...);
}

基本混淆規則

下面這些一般混淆規則都要加入,其中前兩個在默認文件中已經配置:

# 包名不使用大小寫混合 aA Aa
-dontusemixedcaseclassnames

# 不混淆第三方引用的庫
-dontskipnonpubliclibraryclasses

# 不做預校驗
-dontpreverify

# 忽略警告
-ignorewarning

輸出混淆記錄

混淆後由於閱讀困難性提高,所以為了方便自己查閱,可以輸出mapping對應文件,可以利用AndroidSDK\tools\proguard\bin中的proguardgui.bat打開混淆工具,利用retrace結合mapping和stacktrace調試遇到的錯誤

# 混淆後生產映射文件 map 類名->轉化後類名的映射
# 存放在app\build\outputs\mapping\release中
-verbose

# 混淆前後的映射
-printmapping mapping.txt

# apk 包內所有 class 的內部結構
-dump class_files.txt

# 未混淆的類和成員
-printseeds seeds.txt

# 列出從 apk 中刪除的代碼
-printusage unused.txt

保留源代碼行號

即使使用retrace工具,還是很難定位到錯誤的時候,可以暫時先保留行號,觀察錯誤修改後再關閉掉

# 拋出異常時保留代碼行號
# 這個最後release的時候關閉掉
-keepattributes SourceFile,LineNumberTable

基本組件白名單

Android中的基本組件不能混淆,為了方便,下面提供了兼容性比較高的規則:

-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-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

Support包規則

# 如果有引用v4包可以添加下面這行
-keep public class * extends android.support.v4.app.Fragment

# 如果引用了v4或者v7包
-dontwarn android.support.**

不混淆本地方法

本地方法不能混淆,這個規則在默認配置文件中有:

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native ;
}

WebView混淆規則

使用了WebView的JS功能則開啟下面規則,這個規則在自定義規則文件中已經用注釋說明了:

# WebView使用javascript功能則需要開啟
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
    public *;
}

注解、泛型和反射混淆

下面是混淆規則:

# 保護注解
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation {*;}

# 泛型與反射
-keepattributes Signature
-keepattributes EnclosingMethod

有些注解可能不能被混淆,需要手動混淆一下

內部類混淆

# 不混淆內部類
-keepattributes InnerClasses

第三方混淆參考規則

Gson

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

otto

# otto混淆規則
-keepattributes *Annotation*
-keepclassmembers class ** {
    @com.squareup.otto.Subscribe public *;
    @com.squareup.otto.Produce public *;
}

universal-image-loader

-dontwarn com.nostra13.universalimageloader.**
-keep class com.nostra13.universalimageloader.** {*;}

友盟統計

# 友盟統計
-keepclassmembers class * {
    public  (org.json.JSONObject);
}

# 友盟統計5.0.0以上SDK需要
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 友盟統計R.java刪除問題
-keep public class com.gdhbgh.activity.R$*{
    public static final int *;
}

OkHttp

# OkHttp
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.** {*;}
-keep interface com.squareup.okhttp.** {*;}
-dontwarn okio.**

nineoldandroids

-dontwarn com.nineoldandroids.*
-keep class com.nineoldandroids.** {*;}

支付寶

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

Socket.io

# socket.io
-keep class socket.io-client.
-keepclasseswithmembers,allowshrinking class socket.io-client.* {*;}
-keep class io.socket.
-keepclasseswithmembers,allowshrinking class io.socket.* {*;}

JPUSH

# jpush
-dontwarn cn.jpush.**
-keep class cn.jpush.** {*;}

# protobuf(jpush依賴)
-dontwarn com.google.**
-keep class com.google.protobuf.** {*;}

友盟分享

這個只有部分熱門的SDK,具體可以參考分享文檔:

# 友盟分享
-dontwarn com.umeng.**
-dontwarn com.tencent.weibo.sdk.**

-keep public interface com.tencent.**
-keep public interface com.umeng.socialize.**
-keep public interface com.umeng.socialize.sensor.**
-keep public interface com.umeng.scrshot.**

-keep public class com.umeng.socialize.* {*;}

-keep class com.umeng.scrshot.**
-keep public class com.tencent.** {*;}
-keep class com.umeng.socialize.sensor.**
-keep class com.umeng.socialize.handler.**
-keep class com.umeng.socialize.handler.*
-keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;}

-keep class im.yixin.sdk.api.YXMessage {*;}
-keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}

-keep class com.tencent.** {*;}
-dontwarn com.tencent.**
-keep public class com.umeng.soexample.R$*{
    public static final int *;
}
-keep class com.tencent.open.TDialog$*
-keep class com.tencent.open.TDialog$* {*;}
-keep class com.tencent.open.PKDialog
-keep class com.tencent.open.PKDialog {*;}
-keep class com.tencent.open.PKDialog$*
-keep class com.tencent.open.PKDialog$* {*;}

-keep class com.sina.** {*;}
-dontwarn com.sina.**
-keep class  com.alipay.share.sdk.** {*;}

個人遇到的一些坑

網絡層混淆

混淆要注意,一般網絡層都不進行混淆,可以經過劃分包後直接不混淆網絡層的包:

-keep class com.xxx.xxx.http.** {*;}

數據模型混淆

所有bean都不要混淆,可以使用下面的:

-keep class * implements java.io.Serializable {*;}
-keepclassmembers class * implements java.io.Serializable {*;}

但是有時候上述代碼可能導致應用卡住,沒用任何錯誤提示,所以我建議采用分包模式,把所有bean放在一個包中,直接對該包加白名單:

-keep class com.xxx.xxx.domain.** {*;}

XML映射問題

如果你遇到一些控件無法Inflate,報NullPointException,比如ListView,NavigationView等等,這個問題花了我幾個小時自己研究出了規則:

-keep class org.xmlpull.v1.** {*;}

混淆規則編寫方法

如果混淆後報錯,通過retrace後找到錯誤的問題後可以直接編寫規則來去掉混淆,但是如果報的錯誤莫名其妙,而且報錯的類沒有混淆,那麼你可以采用極端的方法:

加入下面規則:

-keep class *.** {*;}

這條規則表示不混淆所有類及其中所有代碼,加了這條規則之後,
還不能運行表示是其他問題,例如注解,內部類等等,
可以運行後,可以通過反編譯,尋找所有包名,記錄下來,把上述規則改為:

-keep class android.** {*;}
-keep class com.** {*;}
-keep class io.** {*;}
-keep class org.** {*;}
...

一個個去掉檢查是否有報錯,例如查到

-keep class com.** {*;}

加了就不報錯,則可以繼續一級級往下檢查。
但要注意,有時候可能是幾個包混合問題。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved