Android Studio(十一):代碼混淆及打包apk

Android Studio相關博客:

Android Studio(二):快捷鍵設置、插件安裝


  最近終於把項目做完了,天天加班,累成狗了。 而昨日又忽聞慕和網絡CEO吳波猝然離世的消息,深感互聯網行業在高薪(其實好多人並不高薪哇大哭大哭大哭)的同時,也是高壓力高風險的啊,也在此希望廣大同行可以珍惜生命,遠離代碼,啊呸,是遠離加班熬夜!

  好啦,繼續今天的話題,當項目做完之後,作爲一個稱職的開發者,接下來任務自然是打包測試發佈了。

  而打包之前,你必須要混淆你的代碼,前提是你不希望別人看到你的代碼!


  如果你不混淆你的代碼,會有怎樣的後果呢?知道不?

  通過反編譯你的apk文件,你的源代碼和資源文件都將暴漏無疑,就像光着屁股在別人眼瞎亂晃一樣,我覺得它們一定不好受。 作爲一手造就它的你來說,怎麼能讓它不好受呢?

  

  嘿,說到這裏,我想有些初學的開發者已經會有所好奇了:如何反編譯apk文件擦查看源碼呢?再此,給大家推薦兩篇博客,很精簡很易懂《android 代碼 混淆- 原來如此簡單》和 《 Android APK反編譯就這麼簡單 詳解》; 相信你看完這兩篇博客(能跟着做一遍更佳),一定會覺得蛋疼: 尼瑪老子辛辛苦苦搞了幾個月的項目,你幾分鐘就把源碼給我搞到了,當我開源的啊!


 好啦,知道不去混淆代碼會有怎樣的影響之後,那我們來看看如何在Android Studio上混淆你的工程代碼吧。


代碼混淆


首先,在你的工程目錄下,找到proguard-rules.pro文件,它就是你要進行編寫混淆配置的文件:


光編寫該文件還不夠哦,你還需要在你module的build.gradle文件中引用該混淆文件:



好了,知道在哪配置混淆文件後,下面開始講講如何配置混淆:


混淆文件 proguard-rules.pro 參數詳解:

-optimizationpasses 5                                                           # 指定代碼的壓縮級別
-dontusemixedcaseclassnames                                                     # 是否使用大小寫混合
-dontskipnonpubliclibraryclasses                                                # 是否混淆第三方jar
-dontpreverify                                                                  # 混淆時是否做預校驗
-verbose                                                                        # 混淆時是否記錄日誌
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆時所採用的算法

-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                      # 保持哪些類不被混淆
-keep public class com.android.vending.licensing.ILicensingService              # 保持哪些類不被混淆

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

-keepclasseswithmembers class * {                                               # 保持自定義控件類不被混淆
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);     # 保持自定義控件類不被混淆
}

-keepclassmembers class * extends android.app.Activity {                        # 保持自定義控件類不被混淆
   public void *(android.view.View);
}

-keepclassmembers enum * {                                                      # 保持枚舉 enum 類不被混淆
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {                                # 保持 Parcelable 不被混淆
  public static final android.os.Parcelable$Creator *;
}


以上是最基礎的配置,幾乎每個項目都需要進行這些地方的混淆(或保持不混淆)。

如果你仔細看過上方的註釋,就會了解一些基本代碼混淆策略了。 

只是,這還遠遠不夠,因爲你在項目中,總會不可避免的引用第三方的library庫或是jar包,那,如果你不能夠正確的混淆第三方的資源,可能會導致你的應用無法使用。(我就因爲忘了配置Gson相關的混淆,導致頁面一直沒有數據顯示,蛋疼的一筆)。

貼出我項目中關於第三方的混淆部分:


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


#如果引用了v4或者v7包,可以忽略警告,因爲用不到android.support
-dontwarn android.support.**


 
#保持自定義組件不被混淆
-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

 
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
 
#保持 Serializable 不被混淆並且enum 類也不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
 
#保持枚舉 enum 類不被混淆 如果混淆報錯,建議直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
-keepclassmembers enum * {
  public static **[] values();
 public static ** valueOf(java.lang.String);
}
 
-keepclassmembers class * {
    public void *ButtonClicked(android.view.View);
}
 
#不混淆資源類
#-keepclassmembers class **.R$* {
#    public static <fields>;
#}


#xUtils(保持註解,及使用註解的Activity不被混淆,不然會影響Activity中你使用註解相關的代碼無法使用) 
-keep class * extends java.lang.annotation.Annotation {*;}
-keep class com.otb.designerassist.activity.** {*;}


#自己項目特殊處理代碼(這些地方我使用了Gson類庫和註解,所以不希望被混淆,以免影響程序)
-keep class com.otb.designerassist.entity.** {*;}
-keep class com.otb.designerassist.http.rspdata.** {*;}
-keep class com.otb.designerassist.service.** {*;}

 
##混淆保護自己項目的部分代碼以及引用的第三方jar包library(想混淆去掉"#")
#-libraryjars libs/umeng-analytics-v5.2.4.jar
#-libraryjars libs/alipaysecsdk.jar
#-libraryjars libs/alipayutdid.jar
#-libraryjars libs/weibosdkcore.jar 


# 以libaray的形式引用的圖片加載框架,不想混淆(注意,此處不是jar包形式,想混淆去掉"#")
#-keep class com.nostra13.universalimageloader.** { *; }


###-------- Gson 相關的混淆配置--------
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }




###-------- pulltorefresh 相關的混淆配置---------
-dontwarn com.handmark.pulltorefresh.library.**
-keep class com.handmark.pulltorefresh.library.** { *;}
-dontwarn com.handmark.pulltorefresh.library.extras.**
-keep class com.handmark.pulltorefresh.library.extras.** { *;}
-dontwarn com.handmark.pulltorefresh.library.internal.**
-keep class com.handmark.pulltorefresh.library.internal.** { *;}


###---------  reservoir 相關的混淆配置-------
-keep class com.anupcowkur.reservoir.** { *;}


###-------- ShareSDK 相關的混淆配置---------
-keep class cn.sharesdk.** { *; }
-keep class com.sina.sso.** { *; }


###--------------umeng 相關的混淆配置-----------
-keep class com.umeng.** { *; }
-keep class com.umeng.analytics.** { *; }
-keep class com.umeng.common.** { *; }
-keep class com.umeng.newxp.** { *; }


###-----------MPAndroidChart圖庫相關的混淆配置------------
-keep class com.github.mikephil.charting.** { *; }


以上的配置,即是對一個項目的混淆配置了,相對比較完整,大家可以依葫蘆畫瓢,寫更多的配置,對於一些第三方項目的使用,一般官方會給出如何配置混淆,大家需要小心,別忘了配置。


好啦,如果你已經寫好自己的混淆配置文件,不要忘了在build.gradle文件中再次配置下,打開混淆文件:

signingConfigs {
        assist {
            keyAlias 'assist.keystore'
            keyPassword 'assist2017'
            storeFile file('../assist.keystore')
            storePassword 'assist2017'
        }
    }
 buildTypes {
        debug {
            // 顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"


            versionNameSuffix "-debug"
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
            signingConfig signingConfigs.assist
        }


        release {
            // 不顯示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            //混淆
            minifyEnabled true

            //Zipalign優化
            zipAlignEnabled true


            // 移除無用的resource文件
            shrinkResources true
            //加載默認混淆配置文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //簽名
            signingConfig signingConfigs.assist

        }
    }

release節點下,minifyEnabled設置爲true。


導出APK文件


  學會了如何混淆你的項目代碼之後,接下來,我們看下,如何使用Android Studio導出APK文件吧。

(1)Android Studio菜單Build->Generate Signed APK 


(2)彈出簽名選擇、創建窗口


(3)創建密鑰庫及密鑰,創建後會自動選擇剛創建的密鑰庫和密鑰(已擁有密鑰庫跳過) 
    點擊“Create new...”按鈕創建密鑰庫 


Key store path:密鑰庫文件的地址 
Password/Confirm:密鑰庫的密碼 
Alias:密鑰名稱 
Password/Confirm:密鑰密碼 
Validity(years):密鑰有效時間 
First and Last Name:密鑰頒發者姓名 
Organizational Unit:密鑰頒發組織 
City or Locality:城市 
Country Code(XX):國家 


(4)選擇已存在密鑰庫及密鑰(在(3)中創建密鑰庫後跳過此步驟) 

    點擊“Choose existing...”按鈕找到密鑰庫文件 
    Key store password輸入已選擇的密鑰庫文件的密碼 
    點擊Key alias後的“...”按鈕,選擇或者創建一個密鑰 


(5)點擊“Next”按鈕,選擇保存路徑後,點擊“Finish”按鈕完成 



(全章結束)

發佈了118 篇原創文章 · 獲贊 209 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章