說明:由于翻譯水平有限,可能會存在一些不恰當(dāng)?shù)牡胤?,歡迎指出,我會馬上改正。系列的剩余部分會陸續(xù)翻譯完。
- 原文地址:Little Things That Matter
- 原文作者:Dmytro Danylyk
- 譯者 / 校對者:bincn
本文是配置 Android 項目系列的一部分:
我們在這篇文章中討論的一切都可以在 template 項目中找到
gitignore
當(dāng)你在 Android Studio 中創(chuàng)建一個新的 Android 項目時,它就已經(jīng)生成了 gitignore 文件,但是通常并不包含所有必要的規(guī)則。
為了快速生成和下載 gitignore 文件,我推薦你使用 gitignore.io 網(wǎng)站。只要輸入必要的關(guān)鍵詞,例如 Android,Intellij,然后點擊生成按鈕。

查看 template 項目的 gitignore 文件。
tools folder
如果你有一些第三方腳本、規(guī)則集或者其他和你項目相關(guān)的文件,不要放在根目錄下,會造成混亂。(特別是哪些使用項目視圖,而不是 Android 視圖)
嘗試創(chuàng)建一個文件夾(例如:tools),并把這些文件放入這個文件夾。

通常我會放入自定義的 gradle 腳本文件、混淆 (proguard) 規(guī)則和靜態(tài)代碼分析工具,例如:pmd、findbugs、lint。
查看 template 項目的 tools 文件夾
flavors
Flavors 用于創(chuàng)建不同設(shè)置的構(gòu)建。在大多數(shù)情況下,我會設(shè)置兩種風(fēng)格,它們的不同在于:
- applicationId
- versionCode / versionName
- server endpoints
- google services keys
- ...
productFlavors {
dev {
signingConfig signingConfigs.debug
versionCode gitVersionCodeTime
versionName gitVersionName
}
prod {
signingConfig signingConfigs.release
versionCode gitVersionCode
versionName gitVersionName
}
}
查看 template 項目的 productFlavors
keystore
密鑰庫是一個二進制文件,包含一個或多個私鑰用于簽名你的應(yīng)用程序。
當(dāng)你在 IDE 中運行或者調(diào)試項目,Android Studio 會通過 Android SDK 工具生成一個調(diào)試證書自動的簽名你的 APK。
使用本地調(diào)試密鑰庫時有幾個問題:
- 365天期滿
- 通過多臺電腦安裝應(yīng)用需要先卸載
- 谷歌的服務(wù)需要密鑰庫 SHA-1 指紋
這就是為什么我通常生成調(diào)試密鑰庫提交到版本控制系統(tǒng)。
signingConfigs {
debug {
keyAlias 'androiddebugkey'
keyPassword 'android'
storePassword 'android'
storeFile file('../keystore/debug.keystore')
}
release {
...
}
}
查看 template 項目的 signingConfigs
proguard
Android 上的混淆器用于三件事:
- 縮小未使用的代碼,幫助你免于64K限制 (64k limit)
- 優(yōu)化代碼和 APK
- 混淆代碼,使你的 APK 難逆向工程
問題是,混淆和代碼優(yōu)化顯著增加編譯時間,使調(diào)試更難。
這就是為什么最好是針對發(fā)布和調(diào)試構(gòu)建使用不同的混淆器規(guī)則:
- rules-proguard.pro
- rules-proguard-debug.pro
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
"$project.rootDir/tools/rules-proguard.pro"
signingConfig signingConfigs.release
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
"$project.rootDir/tools/rules-proguard-debug.pro"
signingConfig signingConfigs.debug
}
}
對于調(diào)試構(gòu)建,混淆器規(guī)則必須具備以下內(nèi)容,強制忽略警告,跳過代碼混淆與優(yōu)化:
# Add project specific ProGuard rules here.
-dontobfuscate
-dontoptimize
-ignorewarnings
對于發(fā)布版本設(shè)置混淆器規(guī)則是很難的,因為幾乎每一個庫都會有它自己特定的規(guī)則。幸好有開源庫 android-proguard-snippets,包含所有主要庫的混淆規(guī)則。
# Add project specific ProGuard rules here.
# Remove logs
-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(...);
}
# Proguard configurations for common Android libraries:
# https://github.com/krschultz/android-proguard-snippets
查看 template 項目的 rules-proguard.pro 和 rules-proguard-debug.pro
strict mode
Android 的嚴(yán)格模式 (StrictMode) 幫助你檢測不同種類的問題:
- 可以關(guān)閉的對象沒有關(guān)閉
- 在主線程執(zhí)行文件讀取和網(wǎng)絡(luò)請求
- 暴露 uri
- ...
每當(dāng)檢測到這樣的問題,它可以顯示適當(dāng)?shù)娜罩净蜃寫?yīng)用程序崩潰,這取決于你的配置。
我建議你在調(diào)試版本中打開它,并且使用 detectAll 方法檢測各種問題。
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}
以下是示例 log,當(dāng)你忘記關(guān)閉 SQLiteCursor :
StrictMode:
A resource was acquired at attached stack trace but never released.
See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at android.database.CursorWindow.<init>(CursorWindow.java:111)
at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:139)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197)
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:237)
at com.dd.template.MainActivity.onCreate(MainActivity.java:124)
查看 template 項目的 StrictMode
譯文