最近打包公司的項目中遇到一些問題序厉,在此記錄一下。
Android Studio下打包APK
本文只講AS打包Apk的方式,eclispe的打包方式可以自行百度熟尉。
-
打包Apk的兩種方式:
- 第一種方式
使用Android Studio自帶的工具生成Apk。具體步驟為 Build >Generate Signed APK,則會出現(xiàn)如圖所示的界面熙卡,如果是第一次生成APK杖刷,則需要創(chuàng)建新的簽名文件(圖在下二)。
- 第一種方式
-
下面來一一解釋其中方框需要填寫的東西
- 1.選擇新建簽名文件保存的路徑驳癌,選擇好路徑并新建好簽名文件的名稱
- 2.輸入簽名文件密碼(生成Apk 導(dǎo)入簽名文件需要這個密碼)
- 3.確認密碼
- 4.簽名文件別名
- 5--6 別名密碼和確認密碼
- 7.你的名字或者代號
- 接下來的8---12 分別是公司滑燃、組織、城市喂柒、地區(qū)不瓶、國家(不是必須填寫,如果是公司項目可以填寫公司名稱等)
-
填寫完成后就新建好了本項目的簽名文件灾杰,而如果以前已經(jīng)打包了本項目蚊丐,則直接導(dǎo)入以前生成的簽名文件并輸入密碼就可以了(簽名文件的密碼一定要記住,下面會解釋為什么)艳吠。如圖所示填入剛剛設(shè)置的密碼麦备,點擊下一步。
-
最后可以選擇生成Apk的輸出路徑昭娩,Apk名稱凛篙,其中有兩個選項Signature Versions,他的含義為打包一個文件的簽名版本栏渺,選V1打包出來的app是jar的(一般這種就是當(dāng)做第三方導(dǎo)入項目來用的)呛梆,選v2打包出來的APP是apk版本的(也就是可以直接在手機上安裝的,可是上線的)磕诊,一般兩個都勾選上不會有什么問題填物。好了,到此第一種生成Apk的方式就弄完了霎终,是不是很簡單滞磺。
- 第二種方式,在控制臺使用命令的方式打包
首先配置gradle簽名文件信息莱褒,如圖所示:
然后在Build Types中選擇剛剛配置好的release(即簽名配置信息)击困,如圖所示
這時候我們可以去gradle中查看我們剛剛配置好的簽名文件信息,并且已經(jīng)在 buildTypes有引用广凸,說明簽名文件已經(jīng)配置好了阅茶,如圖所示。
但是我們直接將簽名文件的密碼放在Gradle中會不安全谅海,可能會被他人反編譯看到目派,這時候我們可以在Gradle這樣設(shè)置,如圖
- 這時候我們就可以在AS中的控制臺用命令gradlew assembleRelease來生成我們的Apk(如果使用讀取密碼的方式胁赢,輸入完命令之后會被要求輸入簽名文件的密碼)企蹭,如圖所示輸入完命令白筹,構(gòu)建完成生成的Apk在 app >build>outputs>apk 中(名稱有debug的Apk是未簽名的APK,名稱中有release則是我們簽名打包好的APK)谅摄。
最后徒河,有可能遇到的問題
- 我們寫好代碼測試的時候?qū)?yīng)用安裝到到手機上,然后我們打包好的應(yīng)用再次安裝到手機上就會出現(xiàn)“已存在簽名沖突的同名數(shù)據(jù)包”送漠,導(dǎo)致應(yīng)用安裝失敗顽照,這就是我們簽名文件出現(xiàn)了沖突,測試安裝的應(yīng)用使用的簽名文件是IDE工具的測試簽名文件(默認為debug闽寡,使用的簽名文在$HOME/.android/debug.keystore)代兵,而我們打包的APK使用的簽名文件是我們自己創(chuàng)建的簽名文件,所以有沖突是肯定的爷狈,所以我們上面說一定要保存好我們自己生成的簽名文件和密碼植影,否則當(dāng)你做版本更新的時候是無法進行覆蓋安裝的。
- 選擇已經(jīng)存在的簽名文件涎永,如果密碼打錯思币,也是可以繼續(xù)進行打包的,只是最后會顯示打包失敗羡微,錯誤日志顯示無法讀取這個日志文件谷饿,如果使用控制臺輸入命令生成Apk則沒有這個問題。
- app 包下build.gradle妈倔,如果開啟混淆(minifyEnabled true)博投,但是混淆文件規(guī)則沒有配置,也會打包失敗盯蝴,如果不開啟混淆贬堵,則minifyEnabled false,開啟混淆的同時也是配合去除無用資源(shrinkResources true)一起使用的,如果结洼,關(guān)閉混淆,也要相應(yīng)設(shè)置shrinkResources false叉跛,如果為true也會打包失斔扇獭;如果單獨設(shè)置minifyEnabled true筷厘,并且混淆文件中的規(guī)則設(shè)置正確鸣峭,也是可以成功打包的。
buildTypes {
release {
......
minifyEnabled true
shrinkResources true
......
}
}
- 混淆配置
混淆配置一般用于發(fā)布上線的Apk中酥艳,混淆Apk有兩個好處:- 可以防止你的項目被他人反編譯獲取源碼(如何反編譯Apk這里不做討論摊溶,反編譯用到的工具一般有apktool(反編譯Apk 得到資源文件,其中smile 文件是 .java 文件編譯后的文件充石,如果想破解Apk,需要熟悉smile語法莫换,有興趣大家可以去研究) ;dex2jar 將解壓的Apk 中的dex文件轉(zhuǎn)換成.jar文件;jd-gui 這個用具查看前面生成的.jar文件拉岁,到此就可以看到反編譯Apk的代碼坷剧,如果混淆,則會看到包名和類名用a b c等字符代替喊暖,讓你無法閱讀源碼惫企,如下圖)
- 可以減小Apk的體積,混淆代碼陵叽,打包出來的Apk體積肯定會減小狞尔,這也是Apk瘦身的一種方案。
-
如何混淆
- 首先在app目錄下的build.gradle中做混淆配置巩掺,配置debug和release都使用proguard-rules.pro這個混淆規(guī)則文件偏序,我們可以先debug測試混淆規(guī)則通過后才release打包正式版,如下圖:
- 其次锌半,配置混淆規(guī)則文件禽车,要配置混淆文件規(guī)則,首先要了解規(guī)則是什么刊殉,了解規(guī)則殉摔,具體的細節(jié)這里就不細說了,可以看這篇文章记焊,傳送門(http://www.reibang.com/p/b471db6a01af)
參數(shù):
-include {filename} 從給定的文件中讀取配置參數(shù)
-basedirectory {directoryname} 指定基礎(chǔ)目錄為以后相對的檔案名稱
-injars {class_path} 指定要處理的應(yīng)用程序jar,war,ear和目錄
-outjars {class_path} 指定處理完后要輸出的jar,war,ear和目錄的名稱
-libraryjars {classpath} 指定要處理的應(yīng)用程序jar,war,ear和目錄所需要的程序庫文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的庫類逸月。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可見的庫類的成員。
保留選項
-keep {Modifier} {class_specification} 保護指定的類文件和類的成員
-keepclassmembers {modifier} {class_specification} 保護指定類的成員遍膜,如果此類受到保護他們會保護的更好
-keepclasseswithmembers {class_specification} 保護指定的類和類的成員碗硬,但條件是所有指定的類和類成員是要存在。
-keepnames {class_specification} 保護指定的類和類的成員的名稱(如果他們不會壓縮步驟中刪除)
-keepclassmembernames {class_specification} 保護指定的類的成員的名稱(如果他們不會壓縮步驟中刪除)
-keepclasseswithmembernames {class_specification} 保護指定的類和類的成員的名稱瓢颅,如果所有指定的類成員出席(在壓縮步驟之后)
-printseeds {filename} 列出類和類的成員-keep選項的清單恩尾,標準輸出到給定的文件
壓縮
-dontshrink 不壓縮輸入的類文件
-printusage {filename}
-whyareyoukeeping {class_specification}
優(yōu)化
-dontoptimize 不優(yōu)化輸入的類文件
-assumenosideeffects {class_specification} 優(yōu)化時假設(shè)指定的方法,沒有任何副作用
-allowaccessmodification 優(yōu)化時允許訪問并修改有修飾符的類和類的成員
混淆
-dontobfuscate 不混淆輸入的類文件
-printmapping {filename}
-applymapping {filename} 重用映射增加混淆
-obfuscationdictionary {filename} 使用給定文件中的關(guān)鍵字作為要混淆方法的名稱
-overloadaggressively 混淆時應(yīng)用侵入式重載
-useuniqueclassmembernames 確定統(tǒng)一的混淆類的成員名稱來增加混淆
-flattenpackagehierarchy {package_name} 重新包裝所有重命名的包并放在給定的單一包中
-repackageclass {package_name} 重新包裝所有重命名的類文件中放在給定的單一包中
-dontusemixedcaseclassnames 混淆時不會產(chǎn)生形形色色的類名
-keepattributes {attribute_name,...} 保護給定的可選屬性挽懦,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 設(shè)置源文件中給定的字符串常量
- 最后翰意,貼出我打包項目的混淆配置規(guī)則文件,僅供參考信柿,如果直接復(fù)制進你項目冀偶,可能會打包出錯,具體需要根據(jù)自己的項目來酌情配置渔嚷, 如果項目中使用了第三方的包进鸠,一般可以去官網(wǎng)找到相應(yīng)的混淆配置。到此形病,混淆配置完成客年,這樣打包出來的Apk的代碼就已經(jīng)實現(xiàn)混淆霞幅。
#指定代碼的壓縮級別
-optimizationpasses 5
#包明不混合大小寫
-dontusemixedcaseclassnames
#不去忽略非公共的庫類
-dontskipnonpubliclibraryclasses
#優(yōu)化 不優(yōu)化輸入的類文件
-dontoptimize
#預(yù)校驗
-dontpreverify
#混淆時是否記錄日志
-verbose
# 混淆時所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保護注解
-keepattributes *Annotation*
# 保持哪些類不被混淆
-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
-keep public class com.android.vending.licensing.ILicensingService
#如果有引用v4包可以添加下面這行
-keep public class * extends android.support.v4.app.Fragment
#忽略警告
-ignorewarning
##記錄生成的日志數(shù)據(jù),gradle build時在本項目根目錄輸出##
#apk 包內(nèi)所有 class 的內(nèi)部結(jié)構(gòu)
-dump proguard/class_files.txt
#未混淆的類和成員
-printseeds proguard/seeds.txt
#列出從 apk 中刪除的代碼
-printusage proguard/unused.txt
#混淆前后的映射
-printmapping proguard/mapping.txt
########記錄生成的日志數(shù)據(jù),gradle build時 在本項目根目錄輸出-end######
#如果引用了v4或者v7包
-dontwarn android.support.**
####混淆保護自己項目的部分代碼以及引用的第三方j(luò)ar包library-end####
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持自定義控件類不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定義控件類不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-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*(...);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 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;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚舉 enum 類不被混淆
-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>;
}
#避免混淆泛型 如果混淆報錯建議關(guān)掉
-keepattributes Signature
#移除Log類打印各個等級日志的代碼搀罢,打正式包的時候可以做為禁log使用蝗岖,這里可以作為禁止log打印的功能使用,另外的一種實現(xiàn)方案是通過BuildConfig.DEBUG的變量來控制
-assumenosideeffects class android.util.Log {
public static *** v(...);
public static *** i(...);
public static *** d(...);
public static *** w(...);
public static *** e(...);
}
#gson
#如果用用到Gson解析包的榔至,直接添加下面這幾行就能成功混淆抵赢,不然會報錯。
-keepattributes Signature
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.** { *; }
-keep class com.google.gson.stream.** { *; }
#mob
-keep class android.net.http.SslError
-keep class android.webkit.**{*;}
-keep class cn.sharesdk.**{*;}
-keep class com.sina.**{*;}
-keep class m.framework.**{*;}
-keep class **.R$* {*;}
-keep class **.R{*;}
-dontwarn cn.sharesdk.**
-dontwarn **.R$*
#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
# 如果使用了Gson之類的工具要使被它解析的JavaBean類即實體類不被混淆唧取。
-keep class com.lecloud.base.** { *; }
-keep class com.lecloud.imlib.** { *; }
-keep class com.lecloud.leblockmodelmanager.** { *; }
# --------------- 友盟統(tǒng)計避免混淆 -------------------------
-dontwarn Android.support.v4.**
-dontwarn org.apache.commons.net.**
-dontwarn com.tencent.**
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(Android.content.Context, Android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(Android.content.Context, Android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements Android.os.Parcelable {
public static final Android.os.Parcelable$Creator *;
}
-keepclasseswithmembers class * {
public <init>(Android.content.Context);
}
-dontshrink
-dontoptimize
-dontwarn com.google.Android.maps.**
-dontwarn Android.webkit.WebView
-dontwarn com.umeng.**
-dontwarn com.tencent.weibo.sdk.**
-dontwarn com.facebook.**
-keep enum com.facebook.**
-keepattributes Exceptions,InnerClasses,Signature
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep public interface com.facebook.**
-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 public class javax.**
-keep public class Android.webkit.**
-keep class com.facebook.**
-keep class com.umeng.scrshot.**
-keep public class com.tencent.** {*;}
-keep class com.umeng.socialize.sensor.**
-keep class com.tencent.mm.sdk.openapi.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.openapi.** implements com.tencent.mm.sdk.openapi.WXMediaMessage$IMediaObject {*;}
-keep class im.yixin.sdk.api.YXMessage {*;}
-keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}
-keep public class [your_pkg].R$*{
public static final int *;
}
#極光推送
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
#retroift
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
#ButterKnife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
#fastjson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
#webView處理铅鲤,項目中沒有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
-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.webViewClient {
public void *(android.webkit.webView, jav.lang.String);
}
#融云
-keepattributes Exceptions,InnerClasses
-keepattributes Signature
# RongCloud SDK
-keep class io.rong.** {*;}
-keep class * implements io.rong.imlib.model.MessageContent {*;}
-dontwarn io.rong.push.**
-dontnote com.xiaomi.**
-dontnote com.google.android.gms.gcm.**
-dontnote io.rong.**
# VoIP
-keep class io.agora.rtc.** {*;}
# Location
-keep class com.amap.api.**{*;}
-keep class com.amap.api.services.**{*;}
# 紅包
-keep class com.google.gson.** { *; }
-keep class com.uuhelper.Application.** {*;}
-keep class net.sourceforge.zbar.** { *; }
-keep class com.google.android.gms.** { *; }
-keep class com.alipay.** {*;}
-keep class com.jrmf360.rylib.** {*;}
-ignorewarnings
#播放器框架
-keep class tv.danmaku.ijk.media.player.** {*;}
好了,本次記錄就到這里了枫弟,如果大家有發(fā)現(xiàn)不對的地方邢享,歡迎給我指出,大家一起學(xué)習(xí)進步淡诗。如果覺得文章對你有幫助骇塘,也請給我一個喜歡。
參考文章:http://blog.csdn.net/u012124438/article/details/54958757