編輯:關於Android編程
謹以此文,記我在公司實習時,所接到的第一個正式的、真正有意義的任務——將公司即將發布的APK進行代碼混淆。
混淆就是對發布出去的程序進行重新組織和處理,使得處理後的代碼與處理前代碼完成相同的功能,而混淆後的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義。被混淆過的程序代碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將代碼中的所有變量、函數、類的名稱變為簡短的英文字母代號,在缺乏相應的函數名和程序注釋的況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。
以下資料,來自網絡:
除了在壓縮操作刪除的無用類,字段和方法外,“ProGuard”也能在字節碼級提供性能優化,內部方法有: >常量表達式求值。 >刪除不必要的字段存取。 >刪除不必要的方法調用。 >刪除不必要的分支。 >刪除不必要的比較和instanceof驗證。 >刪除未使用的代碼。 >刪除只寫字段。 >刪除未使用的方法參數。 >像push/pop簡化一樣的各種各樣的peephole優化。 >在可能的情況下為類添加static和final修飾符。 >在可能的情況下為方法添加private, static和final修飾符。 >在可能的情況下使get/set方法成為內聯的。 >當接口只有一個實現類的時候,就取代它。 >選擇性的刪除日志代碼。實際的優化效果是依賴於你的代碼和執行代碼的虛擬機的。簡單的虛擬機比有復雜JIT編譯器的高級虛擬機更有效。無論如何,你的字節碼會變得更小。
仍有一些明顯需要優化的技術不被支持:
>使非final的常量字段成為內聯。
>像get/set方法一樣使其他方法成為內聯。
>將常量表達式移到循環之外。
在Android 2.3以前,混淆Android代碼只能手動添加proguard來實現代碼混淆,非常不方便。而2.3以後,Google已經將這個工具加入到了SDK的工具集裡。該工具的具體路徑:SDK\tools\proguard。當創建一個新的Android工程時,在工程目錄的根路徑下,會出現一個proguard的配置文件proguard.cfg。也就是說,我們可以通過簡單的配置,在我們的elipse工程中直接使用ProGuard混淆Android工程。
在工程的根路徑下,找到”project-properties.txt”文件,源碼如下:
# This file is automaticallygenerated by Android Tools.
# Do not modify this file -- YOURCHANGES WILL BE ERASED!
#
# This file must be checked inVersion Control Systems.
#
# To customize properties used bythe Ant build system edit
# "ant.properties", andoverride values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink andobfuscate your code,uncomment this (available properties: sdk.dir,user.home):
# proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-22
你只要將藍色那段代碼,前面那個“#”號去掉,就能啟動“ProGuard”工具,當然藍色不是這個文件裡面這段代碼原有顏色,是我在文章裡面為了說明加上的。現在進行導包操作,在導包的過程當中,“Eclipse”會自動使用“ProGuard”工具。另外需要說明的一點是,你直接“run”到設備的應用是沒有經過混淆的,即便你已經啟動了“ProGuard”工具,只有手動導包之後所獲得的APK,才是經過混淆工具處理過的。在“proguard-project.txt”文件裡面編寫混淆規則,其實只有一個目的:如果某個類混淆後,將會導致應用無法正常運行(或者部分功能無法正常運行)那麼就要在配置文件裡,聲明不要混淆這些類。我不關心為什麼這些類混淆之後會出錯,只關心哪些類在混淆後出錯,然後在文件裡面聲明不要去混淆這些類。當然如果你非得要刨根問底,你也可以在網上找更詳細地資料。
以下,是通用的,幾乎所有工程都要避開的類(所謂避開,就是聲明這些類不要被混淆):
>四大組件以及系統基本的API不要混淆。
語法規則:-keep public class * extends xxxx
代碼示例:
#所有“Activity”及其子類不要混淆,同理,所有“Service”、“BroadcastReceiver”等等系統級別的類,不要混淆。 -keep public class * extendsandroid.app.Activity -keep public class * extendsandroid.app.Application -keep public class * extendsandroid.app.Service -keep public class * extendsandroid.content.BroadcastReceiver -keep public class * extendsandroid.content.ContentProvider -keep public class * extendsandroid.app.backup.BackupAgentHelper -keep public class * extendsandroid.preference.Preference -keep public classcom.android.vending.licensing.ILicensingService
>保持”native”層的方法不要混淆。
-keepclasseswithmembernamesclass * { native; }
>保持自定義控件,以及指定格式構造方法不要混淆。
-keepclasseswithmembers class * { public(android.content.Context, android.util.AttributeSet); #保持自定義控件類不被混淆,指定格式的構造方法不去混淆 } -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet, int); }
>保持指定規則的方法不被混淆(Android layout 布局文件中為控件配置的onClick方法不能混淆)
-keepclassmembersclass * extends android.app.Activity { public void *(android.view.View); }
>保持自定義控件指定規則的方法不被混淆
-keeppublic class * extends android.view.View { public(android.content.Context); public (android.content.Context, android.util.AttributeSet); public (android.content.Context, android.util.AttributeSet, int); public void set*(...); }
>所有枚舉類型不要混淆
-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }
>需要序列化和反序列化的類不能被混淆(注:Java反射用到的類也不能被混淆)
#保持實現"Serializable"接口的類不被混淆 -keepnamesclass * implements java.io.Serializable #保護實現接口Serializable的類中,指定規則的類成員不被混淆 -keepclassmembersclass * implements java.io.Serializable { static final long serialVersionUID; private static finaljava.io.ObjectStreamField[] serialPersistentFields; !static !transient; private voidwriteObject(java.io.ObjectOutputStream); private voidreadObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }
>保持實現"Parcelable"接口的類不被混淆
-keepclass * implements android.os.Parcelable { public static finalandroid.os.Parcelable$Creator *; }
>所有泛型不能混淆
-keepattributes Signature
>假如項目中有用到注解,應加入這行配置
-keepattributes *Annotation*
>保持R文件不被混淆,否則,你的反射是獲取不到資源id的
-keep class **.R$*{*;}
>保護WebView對HTML頁面的API不被混淆
-keep class **.Webview2JsInterface {*; }
>如果你的項目中用到了webview的復雜操作 ,最好加入
-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.WebChromeClient { public void *(android.webkit.WebView,java.lang.String); }至此,主要通用規則已經介紹完畢,你可以直接拷貝到“ProGuard”配置文件裡面去,這些規則都通用的。
其實保持第三方庫不被混淆並不復雜,最關鍵的就是要細心+耐心。為什麼呢?保持第三方庫不被混淆,是要將你所引用的所有第三方庫,按照一定語法格式,寫在混淆配置文件裡面,簡單地說,就是將你"Eclipse"工程裡的"Android Private Libraries"目錄下面所有的第三方的引用包,按照給定語法格式,全部(注意是全部)寫到你的"proguard.project.txt"文件裡面。來讓我們看圖說話。
一圖勝千言,然後我們總結一下,對於每一個第三方的導入包,我們只要: >-libraryjars libs/xxxx.jar >-dontwarn 包名.** >-keep class 包名.** { *;} 大部分的第三方包都能按照這個規則配置,有些第三方引用包,在其官方網站上面會有混淆代碼配置說明,比如高德地圖就有,這個時候你抄上去就可以了。 好了現在讓我們把所有(對是所有)第三方包全都寫上,寫到手軟~>mapping.txt:表示混淆前後代碼的對照表,這個文件非常重要。如果你的代碼混淆後會產生bug的話,log提示中是混淆後的代碼,希望定位到源代碼的話就可以根據mapping.txt反推。每次發布都要保留它方便該版本出現問題時調出日志進行排查,它可以根據版本號或是發布時間命名來保存或是放進代碼版本控制中。
>dump.txt:描述apk內所有class文件的內部結構。
>seeds.txt:列出了沒有被混淆的類和成員。
>usage.txt:列出了源代碼中被刪除在apk中不存在的代碼。
#保持所有適配器類不被混淆,本應用中,不加這個將會導致適配器類加載失敗,所有列表項沒辦法顯示 -keep public class * extends android.widget.BaseAdapter不過這個不算是混淆的配置規則,因為我的另外一個同時,跟我類似項目結構,但是他沒有加這句,他的列表顯示正常。這是使用"usage.txt"文件進行查漏補缺的例子了。 >混淆過後的APP,越用越卡(其實就是內存洩露),用著用著手機就會莫名其妙的死機了,不單單是應用卡死,整台手機都不動了。不論在APP裡面進行什麼操作,都會導致APP將手機給弄死了。這個異常最終不是通過前面四個文件來解決的,而是通過對APP功能進行考慮。基於所發生的現象,可以看出,一定有什麼全局性東西,混淆之後發生錯誤,導致這個全局功能沒法運行,但是卻又不斷請求,最終耗盡系統資源。最終確定的原因是,我們APP的推送以及IM功能,混淆之後沒法工作,最終耗盡系統資源。那麼解決的辦法是,聲明他不要被混淆。
Android屏幕適配出現的原因在我們學習如何進行屏幕適配之前,我們需要先了解下為什麼Android需要進行屏幕適配。由於Android系統的開放性,任何用戶、開發者、O
實現功能:功能1:點擊MyMusicListFragment(本地音樂)底部UI中的專輯封面圖片打開的PlayActivity(獨立音樂播放界面)PlayActivity
網易新聞看起來很簡潔,左邊是一張圖片,右邊是一些文字信息,這樣的排版是十分常見的,給人的感覺就是簡潔明了,下面通過解析網絡json數據並展示到ListView上,來實現同
簡單介紹一下,現在的主流移動設備像Android、iPhone等都使用SQLite作為復雜數據的存儲引擎,在我們為移動設備開發應用程序時,也許就要使用到SQLite來存儲