# Android CI/CD with Jenkins & Fastlane
> 本文件僅描述技術流程與設計思路,所有名稱與範例皆為示意用途。
---
## 📌 專案說明
本專案使用 **Jenkins(macOS Agent)** 搭配 **Expo、Gradle、Fastlane**,
實作 **Android App Bundle(AAB)** 的自動建置與上傳至
**Google Play Console(Internal Testing)**。
所有敏感資訊(如 **Keystore、Google Play Service Account**)
皆由 **Jenkins Credentials** 統一管理,**不進入版本控制系統**,
確保 CI/CD 流程的安全性。
---
## 🎯 專案目標
- 自動化 Expo Android 專案建置流程
- 在 CI 環境中安全注入 Android Release Signing
- 產生 Android App Bundle(`.aab`)
- 使用 Fastlane 自動上傳至 Google Play Console
- 建立一套:
- ✅ 可重現
- ✅ 可維護
- ✅ 可交接
的 CI/CD 流程
---
## 🏗️ CI 架構概述
### Jenkins Controller
- Pipeline 定義
- 任務調度與執行管理
### macOS Agent(MacBook / Mac mini)
- 執行 Expo、Gradle、Fastlane
- 使用本地安裝環境:
- Android SDK
- Java
- Node.js
---
## 🧰 使用工具
- **Jenkins**:CI Pipeline 管理
- **Expo**:React Native Android Prebuild
- **Gradle**:Android AAB 建置
- **Fastlane(supply)**:Google Play 上傳
- **Google Play Service Account**:Google Play Developer API 存取
---
## 📁 專案目錄結構
```text
.
├─ Jenkinsfile
├─ fastlane/
│ └─ Fastfile
├─ scripts/
│ └─ patch-android-signing.js
├─ android/
│ └─ app/
│ └─ build/
│ └─ outputs/
│ └─ bundle/
│ └─ release/
│ └─ app-release.aab
├─ app/
├─ ios/
└─ package.json
```
## 說明
- `android/`、`ios/` 由 **Expo Prebuild** 動態產生
- `.aab` 為 **CI 產物**,不進入版本控制
- `Jenkinsfile` 置於 **Repository Root**
---
## Jenkins Pipeline 流程
### 1. 環境設定 (Environment Setup)
Pipeline 啟動時設定以下環境變數:
- `ANDROID_HOME`:Android SDK 路徑
- `PATH`:包含 Node.js 與 Android `platform-tools`
- `GRADLE_USER_HOME`:指向 Jenkins Workspace
- `CI=true`:確保工具以 CI 模式執行
---
### 2. 相依套件安裝 (Dependencies)
- Checkout 原始碼
- 使用 Yarn 安裝 JavaScript 套件
- 使用 `--frozen-lockfile` 鎖定套件版本
---
### 3. Expo Android Prebuild
執行指令:
```bash
yarn expo prebuild --platform android --clean
```
##
- 每次 CI 皆重新產生 乾淨的 Android 原生專案
- 確保 build.gradle 與相關設定為最新狀態
---
### 4. Android Release Signing 注入
CI 執行期間完成以下動作:
- 從 **Jenkins Credentials** 注入 Keystore
- 動態產生 `keystore.properties`
- 執行自製 Script:
- `scripts/patch-android-signing.js`
- 自動 Patch:
- `android/app/build.gradle`
- 確保 Release Build 使用正確的 Signing Config
---
### 5. Android AAB 建置
執行 Gradle 指令:
```bash
./gradlew bundleRelease
```
產出檔案
```bash
android/app/build/outputs/bundle/release/app-release.aab
```
---
### 6. AAB 定位與上傳準備
Jenkins 在上傳前進行以下處理:
- 固定工作目錄為 **Repository Root**
- 僅搜尋 `bundle/release/` 目錄
- 將 AAB 路徑轉為 **絕對路徑**
並設定以下環境變數:
- `AAB_PATH`
- `SUPPLY_JSON_KEY`
---
### 7. applicationId 自動取得
Jenkins 從 `android/app/build.gradle` 解析:
```gradle
applicationId "com.example.app"
```
並設定環境變數:
```gradle
PACKAGE_NAME=com.example.app
```
確保 Fastlane 使用正確的 Package Name。
---
🚀 Fastlane 設計說明
- Fastlane 僅負責上傳
- 不參與建置流程
Fastfile 範例
```
default_platform(:android)
platform :android do
lane :play_internal do
upload_to_play_store(
aab: ENV["AAB_PATH"],
track: "internal",
package_name: ENV["PACKAGE_NAME"],
json_key: ENV["SUPPLY_JSON_KEY"],
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true,
skip_upload_changelogs: true
)
end
end
```
## 安全性設計
- 所有機密資料皆由 **Jenkins Credentials** 管理
- Repository **不包含**:
- Keystore
- Service Account JSON
- Build Outputs
- 可直接移轉至其他 macOS Jenkins Agent(如 Mac mini)
---
## 結論
此 CI/CD 流程透過明確的責任分離:
- **Jenkins**
- 建置流程控制
- 環境準備
- 參數推導
- **Fastlane**
- Google Play 上傳
成功建立一套 **穩定、安全、可維護** 的 Android AAB 自動化流程,
適合長期運行與團隊交接使用。