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

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

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

> [!TIP]
> **支援智慧硬體判斷與參數化覆寫：**
> * 預設（不帶參數）：編譯 **`Chengwai` 晟崴版 (S12XYU)**。
> * **智慧判斷**：當編譯 **`中國醫 (Cmuh)`** 時，會自動識別並預設編譯 **`S9XYU` (Android 9 / 21.5 吋)**；編譯 **`General`** 與 **`Chengwai`** 時則預設編譯 **`S12XYU` (10 吋)**。
> * **參數手動覆寫**：支援手動指定硬體尺寸。例如 `/compiler-apk Cmuh S12` 可強行編譯中國醫的 10 吋版本；`/compiler-apk General S9` 可強行編譯通用版的大螢幕 21.5 吋版本。

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

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

```bash
// turbo
# 終止殘留的 Gradle Daemon 程序，避免多個 Daemon 互搶資源，同時避免誤殺 VS Code Gradle 擴充功能
./gradlew --stop 2>/dev/null; pkill -9 -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" 2>/dev/null; sleep 3

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

# 取得目標 Flavor 參數
RAW_INPUT="$1"
TARGET_FLAVOR="Chengwai"

if [ -n "$RAW_INPUT" ]; then
    LOWER_INPUT=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_INPUT" = "general" ] || [ "$LOWER_INPUT" = "通用" ] || [ "$LOWER_INPUT" = "通用版" ] || [ "$LOWER_INPUT" = "標準" ] || [ "$LOWER_INPUT" = "標準版" ]; then
        TARGET_FLAVOR="General"
    elif [ "$LOWER_INPUT" = "chengwai" ] || [ "$LOWER_INPUT" = "晟崴" ] || [ "$LOWER_INPUT" = "晟崴版" ]; then
        TARGET_FLAVOR="Chengwai"
    elif [ "$LOWER_INPUT" = "cmuh" ] || [ "$LOWER_INPUT" = "中國醫" ] || [ "$LOWER_INPUT" = "中國醫版" ]; then
        TARGET_FLAVOR="Cmuh"
    else
        TARGET_FLAVOR=$(echo "$RAW_INPUT" | awk '{print toupper(substr($0,1,1))tolower(substr($0,2))}')
    fi
fi

# 根據 Flavor 動態設定智慧硬體規格預設值
TARGET_HARDWARE="S12XYU"
if [ "$TARGET_FLAVOR" = "Cmuh" ]; then
    TARGET_HARDWARE="S9XYU"
fi

# 取得手動指定的第二個硬體規格參數 (S9 / S12)
RAW_HW_INPUT="$2"
if [ -n "$RAW_HW_INPUT" ]; then
    LOWER_HW=$(echo "$RAW_HW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_HW" = "s9" ] || [ "$LOWER_HW" = "s9xyu" ] || [ "$LOWER_HW" = "大螢幕" ] || [ "$LOWER_HW" = "21.5" ]; then
        TARGET_HARDWARE="S9XYU"
    elif [ "$LOWER_HW" = "s12" ] || [ "$LOWER_HW" = "s12xyu" ] || [ "$LOWER_HW" = "10" ]; then
        TARGET_HARDWARE="S12XYU"
    fi
fi

# 安全防護：檢查是否為支援的客製項目
if [ "$TARGET_FLAVOR" != "General" ] && [ "$TARGET_FLAVOR" != "Chengwai" ] && [ "$TARGET_FLAVOR" != "Cmuh" ]; then
    echo "❌ 不支援的 Flavor: $TARGET_FLAVOR，請使用 General, Chengwai 或 Cmuh。"
    exit 1
fi

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

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

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

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

# 取得 Flavor 參數
RAW_INPUT="$1"
TARGET_FLAVOR="Chengwai"

if [ -n "$RAW_INPUT" ]; then
    LOWER_INPUT=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_INPUT" = "general" ] || [ "$LOWER_INPUT" = "通用" ] || [ "$LOWER_INPUT" = "通用版" ] || [ "$LOWER_INPUT" = "標準" ] || [ "$LOWER_INPUT" = "標準版" ]; then
        TARGET_FLAVOR="General"
    elif [ "$LOWER_INPUT" = "chengwai" ] || [ "$LOWER_INPUT" = "晟崴" ] || [ "$LOWER_INPUT" = "晟崴版" ]; then
        TARGET_FLAVOR="Chengwai"
    elif [ "$LOWER_INPUT" = "cmuh" ] || [ "$LOWER_INPUT" = "中國醫" ] || [ "$LOWER_INPUT" = "中國醫版" ]; then
        TARGET_FLAVOR="Cmuh"
    else
        TARGET_FLAVOR=$(echo "$RAW_INPUT" | awk '{print toupper(substr($0,1,1))tolower(substr($0,2))}')
    fi
fi

# 根據 Flavor 動態設定智慧硬體規格預設值
TARGET_HARDWARE="S12XYU"
if [ "$TARGET_FLAVOR" = "Cmuh" ]; then
    TARGET_HARDWARE="S9XYU"
fi

# 取得手動指定的第二個硬體規格參數 (S9 / S12)
RAW_HW_INPUT="$2"
if [ -n "$RAW_HW_INPUT" ]; then
    LOWER_HW=$(echo "$RAW_HW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_HW" = "s9" ] || [ "$LOWER_HW" = "s9xyu" ] || [ "$LOWER_HW" = "大螢幕" ] || [ "$LOWER_HW" = "21.5" ]; then
        TARGET_HARDWARE="S9XYU"
    elif [ "$LOWER_HW" = "s12" ] || [ "$LOWER_HW" = "s12xyu" ] || [ "$LOWER_HW" = "10" ]; then
        TARGET_HARDWARE="S12XYU"
    fi
fi

# 解析硬體規格來決定輸出檔案名格式 (S9 -> S_9, S12 -> S_12)
FORMATTED_HW=""
if [ "$TARGET_HARDWARE" = "S9XYU" ]; then
    FORMATTED_HW="S_9_XY_U"
else
    FORMATTED_HW="S_12_XY_U"
fi

# 動態尋找編譯產出的最新 APK 檔案
APK_SOURCE=$(find app/build/outputs/apk/${TARGET_FLAVOR}${TARGET_HARDWARE}/debug/ -name "app-${FORMATTED_HW}_${TARGET_FLAVOR}-*-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"
    
    # 提取與計算版本資訊
    MAJOR=$(grep "def verMajor" app/build.gradle | awk '{print $4}')
    
    # 若在 build.gradle 內 Major 是由 hardware 動態判定，直接讀取並在 Shell 依據當前規格計算
    if [ "$TARGET_HARDWARE" = "S9XYU" ]; then
        MAJOR=21
    else
        MAJOR=10
    fi
    
    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}_R"
    VERSION_CODE=$((MAJOR * 10000 + MINOR * 100 + PATCH))
    FLAVOR="${TARGET_FLAVOR}${TARGET_HARDWARE}"
    
    echo "=================================================="
    echo "📢 後台更新 keyin 參考資料："
    echo "--------------------------------------------------"
    echo "* 產品風味 (Flavor)：$FLAVOR"
    echo "* 版本名稱 (versionName)：$VERSION_NAME"
    echo "* 版本代碼 (versionCode)：$VERSION_CODE"
    echo "* APK 檔案名稱：$APK_NAME"
    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"

# 取得 Flavor 參數
RAW_INPUT="$1"
TARGET_FLAVOR="Chengwai"

if [ -n "$RAW_INPUT" ]; then
    LOWER_INPUT=$(echo "$RAW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_INPUT" = "general" ] || [ "$LOWER_INPUT" = "通用" ] || [ "$LOWER_INPUT" = "通用版" ] || [ "$LOWER_INPUT" = "標準" ] || [ "$LOWER_INPUT" = "標準版" ]; then
        TARGET_FLAVOR="General"
    elif [ "$LOWER_INPUT" = "chengwai" ] || [ "$LOWER_INPUT" = "晟崴" ] || [ "$LOWER_INPUT" = "晟崴版" ]; then
        TARGET_FLAVOR="Chengwai"
    elif [ "$LOWER_INPUT" = "cmuh" ] || [ "$LOWER_INPUT" = "中國醫" ] || [ "$LOWER_INPUT" = "中國醫版" ]; then
        TARGET_FLAVOR="Cmuh"
    else
        TARGET_FLAVOR=$(echo "$RAW_INPUT" | awk '{print toupper(substr($0,1,1))tolower(substr($0,2))}')
    fi
fi

# 根據 Flavor 動態設定智慧硬體規格預設值
TARGET_HARDWARE="S12XYU"
if [ "$TARGET_FLAVOR" = "Cmuh" ]; then
    TARGET_HARDWARE="S9XYU"
fi

# 取得手動指定的第二個硬體規格參數 (S9 / S12)
RAW_HW_INPUT="$2"
if [ -n "$RAW_HW_INPUT" ]; then
    LOWER_HW=$(echo "$RAW_HW_INPUT" | tr '[:upper:]' '[:lower:]')
    if [ "$LOWER_HW" = "s9" ] || [ "$LOWER_HW" = "s9xyu" ] || [ "$LOWER_HW" = "大螢幕" ] || [ "$LOWER_HW" = "21.5" ]; then
        TARGET_HARDWARE="S9XYU"
    elif [ "$LOWER_HW" = "s12" ] || [ "$LOWER_HW" = "s12xyu" ] || [ "$LOWER_HW" = "10" ]; then
        TARGET_HARDWARE="S12XYU"
    fi
fi

# 解析硬體規格來決定輸出檔案名格式 (S9 -> S_9, S12 -> S_12)
FORMATTED_HW=""
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}_${TARGET_FLAVOR}-*-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
```
