---
description: 自動編譯 Android APK、輸出至專屬目錄並安裝至實體手機
---

# 編譯與安裝 APK 工作流 (compiler-apk)

這個 Workflow 協助您一鍵完成 Android 專案的編譯、匯出與安裝。當您呼叫 `/compiler-apk` 時，AI 會自動執行下列步驟。

> [!IMPORTANT]
> **客戶專案（購買流程）已收斂為執行期 `shopping_mode`（雲端 B014 下發），不再用 flavor 分家。**
> 打包對象只剩 **硬體規格（hardware flavor）**：`S12XYU`（10 吋）/ `S9XYU`（21.5 吋 / Android 9）。
> 同一支 APK 在現場會依雲端 `shopping_mode` 自動切換為 basic（購物車）/ employee_card（員工卡）/ pickup_sheet（取貨單）。

> [!TIP]
> **參數 = 硬體規格：**
> * 預設（不帶參數）：編譯 **`S12XYU`（10 吋）**。
> * `/compiler-apk S9`（或 `S9XYU` / `21.5` / `大螢幕`）→ 編譯 **`S9XYU`（21.5 吋 / Android 9）**。
> * `/compiler-apk S12`（或 `S12XYU` / `10`）→ 編譯 **`S12XYU`（10 吋）**。
> * 相容舊用語：`中國醫`→S9XYU、`晟崴`/`通用`→S12XYU（僅作硬體對應，流程仍由雲端決定）。

## 步驟零：自動檢查變更與升級版號
在開始編譯之前，AI 助手會自動檢查是否有程式碼變更，以落實實體機台的 OTA 升級規範：
1. AI 助手將檢查 `git status --porcelain app/` 的輸出，以偵測是否有未提交的程式碼修改。
2. 若偵測到變更，且本次任務尚未增加版號，AI 助手將自動讀取 `app/build.gradle` 並將其中的 `verPatch` 變數數值遞增 1。
3. 遞增完成後，向使用者呈報最新的版本號資訊，接著繼續執行步驟一。

## 步驟一：設定環境並編譯 Debug APK
使用 Java 17 與 Gradle 編譯對應硬體規格的 Debug 程式碼。

```bash
// turbo
# 終止殘留的 Gradle Daemon 程序，避免多個 Daemon 互搶資源，同時避免誤殺 VS Code Gradle 擴充功能
# 防呆：先優雅 --stop；僅在仍殘留時才升級終止（先 TERM 再 KILL），避免無差別強殺撞鎖導致 clean 編譯隨機失敗
#
# ⚠️ 關鍵：pgrep/pkill 的比對字串必須「拆開」拼接，不可在本檔字面寫出完整 class 名。
# 否則在背景任務（bash -c "...eval '整段腳本'..."）情境下，腳本自己的命令列會含有
# 完整的 GradleDaemon class 字串 → pgrep -f 比對到自己 → pkill 把跑腳本的 bash 自殺
# → exit 144，編譯根本還沒開始。再加 -v $$ 排除自身 PID 雙重保險。
DAEMON_PAT='org.gradle.launcher.daemon.bootstrap''.GradleDaemon'   # 字面被拆開，pgrep 不會命中本腳本
daemon_alive() { pgrep -f "$DAEMON_PAT" 2>/dev/null | grep -vx "$$" | grep -q .; }
./gradlew --stop 2>/dev/null || true
sleep 2
if daemon_alive; then
    pkill -TERM -f "$DAEMON_PAT" 2>/dev/null || true
    sleep 3
    if daemon_alive; then
        pkill -9 -f "$DAEMON_PAT" 2>/dev/null || true
        sleep 2
    fi
fi

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
cd /home/mama/projects/TaiwanStar_general_size_s_Chengwai

# 取得目標硬體規格（預設 S12XYU；接受 S9/S12 與相容舊用語）
RAW_INPUT="$1"
TARGET_HARDWARE="S12XYU"
if [ -n "$RAW_INPUT" ]; then
    LOWER=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    case "$LOWER" in
        s9|s9xyu|21.5|大螢幕|中國醫|中國醫版|cmuh) TARGET_HARDWARE="S9XYU" ;;
        s12|s12xyu|10|晟崴|晟崴版|chengwai|通用|通用版|general) TARGET_HARDWARE="S12XYU" ;;
        *) echo "⚠️ 無法識別「$RAW_INPUT」，沿用預設 S12XYU" ;;
    esac
fi

echo "🚀 開始編譯: assemble${TARGET_HARDWARE}Debug"

# 使用 clean 確保完整重新編譯，避免舊快取遮蔽 import 缺失等錯誤
./gradlew clean :app:assemble${TARGET_HARDWARE}Debug --no-daemon
```

## 步驟二：導出 APK 到 outputs 資料夾
將編譯出來的 APK 複製到專案最外層的 `outputs` 資料夾。

```bash
// turbo
cd /home/mama/projects/TaiwanStar_general_size_s_Chengwai
mkdir -p outputs

RAW_INPUT="$1"
TARGET_HARDWARE="S12XYU"
if [ -n "$RAW_INPUT" ]; then
    LOWER=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    case "$LOWER" in
        s9|s9xyu|21.5|大螢幕|中國醫|中國醫版|cmuh) TARGET_HARDWARE="S9XYU" ;;
        s12|s12xyu|10|晟崴|晟崴版|chengwai|通用|通用版|general) TARGET_HARDWARE="S12XYU" ;;
    esac
fi

if [ "$TARGET_HARDWARE" = "S9XYU" ]; then
    FORMATTED_HW="S_9_XY_U"; MAJOR=21
else
    FORMATTED_HW="S_12_XY_U"; MAJOR=10
fi

# 動態尋找編譯產出的最新 APK 檔案（檔名已無 project 段：app-<HW>-<ver>-debug.apk）
APK_SOURCE=$(find app/build/outputs/apk/${TARGET_HARDWARE}/debug/ -name "app-${FORMATTED_HW}-*-debug.apk" | head -n 1)

if [ -n "$APK_SOURCE" ]; then
    APK_NAME=$(basename "$APK_SOURCE")
    APK_DEST="outputs/$APK_NAME"
    cp "$APK_SOURCE" "$APK_DEST"
    echo "✅ APK 已經複製到 outputs 資料夾，路徑為：$APK_DEST"

    MINOR=$(grep "def verMinor" app/build.gradle | awk '{print $4}')
    PATCH=$(grep "def verPatch" app/build.gradle | awk '{print $4}')
    VERSION_NAME="${MAJOR}_0${MINOR}_${PATCH}_D"
    VERSION_CODE=$((MAJOR * 10000 + MINOR * 100 + PATCH))

    echo "=================================================="
    echo "📢 後台更新 keyin 參考資料："
    echo "--------------------------------------------------"
    echo "* 硬體規格 (hardware)：$TARGET_HARDWARE（${MAJOR} 吋）"
    echo "* 版本名稱 (versionName)：$VERSION_NAME"
    echo "* 版本代碼 (versionCode)：$VERSION_CODE"
    echo "* APK 檔案名稱：$APK_NAME"
    echo "* 購買流程：由雲端 shopping_mode 決定（basic / employee_card / pickup_sheet）"
    echo "* 更新說明：[請在此處附上口語化的一句話更新說明]"
    echo "=================================================="
else
    echo "❌ 找不到編譯產出的 APK 檔案，複製失敗！"
    exit 1
fi
```

## 步驟三：安裝並啟動 App (如有連接設備)
偵測到設備後才執行安裝。如果未偵測到，則保留 APK 檔案並結束工作流。

```bash
// turbo
ADB_PATH="/mnt/c/Users/User/AppData/Local/Android/Sdk/platform-tools/adb.exe"

RAW_INPUT="$1"
TARGET_HARDWARE="S12XYU"
if [ -n "$RAW_INPUT" ]; then
    LOWER=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    case "$LOWER" in
        s9|s9xyu|21.5|大螢幕|中國醫|中國醫版|cmuh) TARGET_HARDWARE="S9XYU" ;;
        s12|s12xyu|10|晟崴|晟崴版|chengwai|通用|通用版|general) TARGET_HARDWARE="S12XYU" ;;
    esac
fi

if [ "$TARGET_HARDWARE" = "S9XYU" ]; then
    FORMATTED_HW="S_9_XY_U"
else
    FORMATTED_HW="S_12_XY_U"
fi

DEVICE_COUNT=$($ADB_PATH devices | grep -v "List of devices" | grep "device" | wc -l)

if [ "$DEVICE_COUNT" -gt 0 ]; then
    echo "📱 偵測到 $DEVICE_COUNT 個設備，開始安裝..."
    APK_TARGET=$(find outputs/ -name "app-${FORMATTED_HW}-*-debug.apk" | head -n 1)
    if [ -n "$APK_TARGET" ]; then
        $ADB_PATH install -r -d -t "/home/mama/projects/TaiwanStar_general_size_s_Chengwai/$APK_TARGET"
        echo "🚀 安裝完成，正在啟動 App..."
        $ADB_PATH shell am start -n com.unibuy.smartdevice/com.unibuy.smartdevice.HomeActivity
    else
        echo "❌ 找不到 outputs 目錄下的 APK 檔案，安裝失敗！"
        exit 1
    fi
else
    echo "⚠️ 未偵測到連接的手機或設備，已保留 APK 檔案，跳過安裝步驟。"
fi
```
