編輯:關於Android編程
最近在做Android應用的混淆,踩了一些坑,這裡記錄分享下個人的心得。
首先先簡單說一下什麼是混淆和混淆的作用,其實這個搜索下可以找到一堆官方的說法等等,這裡簡單口語敘述一下,混淆就是把代碼替換成a、b、c基本字母組成的代碼,比如一個方法名為:function(),混淆後可能會被替換成a()。
混淆的好處:
代碼混淆後閱讀性降低,反編譯後破譯程序難度提高 混淆後字節數減少,減少了應用了體積前者只能說有一點作用,後者則需要看代碼的數量
當然不能忽視混淆的缺點:
混淆在Android Studio的項目中默認是關閉的,其中控制開關和規則配置文件分別由項目moudle中的build.gradle和proguard-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.** {*;}
加了就不報錯,則可以繼續一級級往下檢查。
但要注意,有時候可能是幾個包混合問題。
/***@author StormMaybin*@Date 2016-09-1*/ 生命不息,奮斗不止!WebView 對於,WebView 顧名思義,就是顯示各種各樣的
目前,各種App的社區或者用戶曬照片、發說說的地方,都提供了評論功能,為了更好地學習,自己把這個功能實現了一下,做了個小的Demo。首先推薦一款實用的插件LayoutCr
最近幾天寫了一個簡單的朋友圈程序,包含了朋友圈的列表實現,視頻的錄制、預覽與上傳,圖片可選擇拍照或者從相冊選取,從相冊選取可以一次選擇多張照片,並且限制照片的張數。大致也
在Android開發中,我們經常會需要在Android界面上彈出一些對話框,比如詢問用戶或者讓用戶選擇。這些功能我們叫它Android Dialog對話框,AlertDi