在 Android 開發中,現在大多使用 Gradle 來處理編譯。如果你已經有專案原始碼,可以直接在專案根目錄使用 ./gradlew 指令。這是最常見也最推薦的做法。
使用 Gradle Wrapper 編譯
Gradle Wrapper 是一個腳本。它能確保專案在不同機器上使用相同的 Gradle 版本。打開終端機並切換到專案路徑,執行以下指令:
./gradlew assembleDebug
這個指令會編譯出一個用於測試的 Debug 版本 APK。如果你需要正式上架的版本,則改用:
./gradlew assembleRelease
執行成功後,產出的檔案通常會放在 app/build/outputs/apk/ 目錄下。你會在裡面看到 debug 或 release 資料夾,副檔名就是 .apk。
常用指令與路徑
如果你的環境是 Windows,指令要改成 gradlew.bat assembleDebug。在執行編譯前,建議先清理舊的暫存檔:
./gradlew clean assembleDebug
這樣可以避免舊的檔案影響新的編譯結果。如果你的專案有多個不同的 Product Flavors,你可以用 ./gradlew tasks 查看所有可用的編譯指令。
關於 AAB 格式
現在 Google Play 要求上架必須使用 .aab 格式。如果你是為了上架準備,指令會稍微不同:
./gradlew bundleRelease
這會產生 Android App Bundle 檔案。位置在 app/build/outputs/bundle/release/ 之下。這比傳統的 APK 能提供更小的下載體積。
如果修改了 keystore 的存放路徑,最直接的調整位置是在專案中的 build.gradle 檔案。通常這個檔案位於 app 目錄下。你需要找到 signingConfigs 區塊。
修改 build.gradle 設定
在 signingConfigs 裡面,有一個屬性叫做 storeFile。你需要把後面的路徑指向新的位置。如果路徑是相對路徑,它是以專案根目錄為基準。
android {
signingConfigs {
release {
storeFile file('/新的路徑/my-release-key.jks')
storePassword '你的密碼'
keyAlias '你的別名'
keyPassword '你的密碼'
}
}
}
建議把路徑寫成相對路徑。例如 file(‘../keystores/release.jks’)。這樣換一台電腦開發時,只要相對位置正確,就不會出錯。
使用 gradle.properties 管理
為了安全與方便,很多人會把路徑寫在 gradle.properties 檔案裡。這樣就不會把私密路徑寫死在程式碼。你可以打開 gradle.properties 調整變數值。
MYAPP_RELEASE_STORE_FILE=/新的路徑/my-release-key.jks
然後在 build.gradle 引用這個變數。改完後記得執行一次 ./gradlew clean。這能確保 Gradle 抓到最新的路徑設定。
檢查環境變數
有些團隊會把路徑放在系統環境變數。如果你的設定是透過 System.getenv 取得。那你就要去修改作業系統的環境設定。修改完後可能需要重啟終端機或 IDE 才會生效。
在 build.gradle 引用 gradle.properties 的變數很簡單。Gradle 會自動將 properties 檔案中的屬性載入。
引用變數的方式
假設你在 gradle.properties 設定了變數名為 MYAPP_RELEASE_STORE_FILE。在 app/build.gradle 裡,你可以直接像這樣寫:
android {
signingConfigs {
release {
// 直接使用變數名稱即可
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
使用專案屬性檢查
有時候為了保險,會建議使用 project.hasProperty 來檢查變數是否存在。這樣即使變數沒設定,編譯也不會直接噴錯。這在多人協作時很好用。
Gradle
storeFile file(project.hasProperty('MYAPP_RELEASE_STORE_FILE') ? MYAPP_RELEASE_STORE_FILE : "default_path.jks")
關於路徑的提醒
如果你在變數中寫的是相對路徑,它是相對於專案根目錄。如果你希望路徑更靈活,可以搭配 rootDir 變數來組合:
Gradle
storeFile file("${rootDir}/keystores/${MYAPP_RELEASE_STORE_FILE}")
這樣無論在哪個層級的 gradle 檔引用,路徑都不會跑掉。改完設定後,建議執行 ./gradlew assembleRelease 測試看看能不能成功讀取。
看到 unsigned 代表這個 APK 還沒有經過數位簽署。Android 系統出於安全考慮,不會允許安裝任何未簽署的 APK。這通常是因為你的編譯指令或設定沒有正確關聯到簽署設定。
檢查 build.gradle 的類型設定
在 build.gradle 中,你雖然定義了 signingConfigs,但還必須在 buildTypes 裡面告訴 Gradle,release 版本要使用哪一組簽署設定。
android {
buildTypes {
release {
// 這一行是關鍵,必須手動指定
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
如果漏掉了 signingConfig signingConfigs.release 這行,Gradle 就會預設產生不帶簽署的 APK,檔名就會出現 unsigned。
檢查簽署內容是否完整
如果設定已經寫了,但產出還是 unsigned,請檢查 gradle.properties 或 signingConfigs 區塊中的資訊是否齊全。簽署需要這四個要素:
storeFile: keystore 檔案的路徑。storePassword: 儲存庫的密碼。keyAlias: 密鑰的別名。keyPassword: 該密鑰的獨立密碼。
只要缺一個,Gradle 有時候會因為找不到資訊而跳過簽署步驟,直接產出 unsigned 版本。
清除快取重試
有時候是之前的編譯產物殘留,導致你看到的是舊檔案。調整完設定後,請務必先執行清理指令再編譯:
./gradlew clean assembleRelease
如果設定正確,生成的檔名應該會變成 app-release.apk。
你需要我幫你檢查 signingConfigs 和 buildTypes 的對應程式碼嗎?
error message:
gradlew clean assembleRelease
* What went wrong:
A problem occurred evaluating project ':app'.
> Could not get unknown property 'release' for SigningConfig container of type org.gradle.api.internal.FactoryNamedDomainObjectContainer.
這個錯誤訊息代表你在 buildTypes 裡面引用了一個還沒定義的 signingConfigs 名稱。Gradle 的執行順序是由上而下,如果你先在 buildTypes 寫了 signingConfig signingConfigs.release,但當時 release 這個設定還沒被建立,就會報錯。
調整 build.gradle 的順序
在 Gradle 腳本中,定義的順序非常重要。你必須確保 signingConfigs 區塊寫在 buildTypes 之前。請檢查你的 app/build.gradle 結構是否如下:
android {
// 1. 先定義簽署設定
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
// 2. 這裡才能引用上面定義好的 release
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-bundle.txt'), 'proguard-rules.pro'
}
}
}
常見的命名陷阱
錯誤訊息提到的 Could not get unknown property 'release',有時候是因為你在 signingConfigs 裡面把名稱取錯了。例如:
- 如果你在
signingConfigs裡寫的是myConfig { ... }。 - 那在
buildTypes就必須寫signingConfig signingConfigs.myConfig。
兩邊的名稱必須完全對應。請確認你的 signingConfigs 括號內確實有名為 release 的區塊。
暫時註解法排查
如果你想確認是不是路徑變數導致的問題,可以先試著在 buildTypes 裡把 signingConfig signingConfigs.release 這一行註解掉。如果編譯能過(雖然產出又是 unsigned),那就代表問題百分之百出在簽署區塊的定義。
修正順序後,再執行一次編譯試試看。
你需要我幫你看一下你目前 build.gradle 第 20 行附近的程式碼長什麼樣子嗎?