# 步骤 01：项目基础设施

> 搭建项目骨架、构建系统、依赖配置，确保能编译运行空白应用。

---

## 一、目标

- [x] 建立 Android 项目基本结构
- [x] 配置 Go + gomobile 构建流程
- [x] 集成 teamspeak-go SDK
- [x] 确保能编译生成空白 APK

---

## 二、任务清单

### 2.1 Android 项目结构

**根目录**：`android/`（在 IDE 中打开此目录，非仓库根目录）

```
android/
├── build.gradle.kts              # 根构建脚本（插件声明）
├── settings.gradle.kts           # 项目设置（仓库、模块）
├── gradle.properties             # Gradle 属性
├── gradlew / gradlew.bat         # Gradle Wrapper
└── app/
    ├── build.gradle.kts          # 应用构建脚本（依赖、SDK 版本）
    ├── libs/                     # gomobile AAR 产物存放处
    │   └── teamspeak.aar         # Go 编译产物（git ignore）
    └── src/main/
        ├── AndroidManifest.xml   # 清单文件
        └── java/com/tsmobile/app/
            ├── MainActivity.kt   # 入口 Activity
            ├── TSBridge.kt       # Go 桥接封装
            └── voice/            # 语音模块（后续步骤扩展）
                ├── OpusEncoder.kt
                ├── OpusDecoder.kt
                └── VoiceService.kt
```

**关键配置项**：

| 配置 | 值 | 说明 |
| --- | --- | --- |
| `namespace` | `com.tsmobile.app` | 包名 |
| `compileSdk` | 35 | Android 15 |
| `minSdk` | 26 | Android 8.0（gomobile 要求最低 API 26） |
| `targetSdk` | 35 | 目标 Android 15 |
| `jvmTarget` | 17 | Java 17 |
| `compose` | true | 启用 Jetpack Compose |

**AndroidManifest.xml 权限声明**：

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
```

- `INTERNET` / `ACCESS_NETWORK_STATE`：连接 TeamSpeak 服务器
- `RECORD_AUDIO`：语音功能（运行时动态申请）

---

### 2.2 Go 模块配置

**目录**：`go/`

```
go/
├── go.mod                        # Go 模块定义
├── go.sum                        # 依赖校验
├── teamspeak/                    # gomobile 导出包（bridge.go 所在）
└── _patches/                     # 上游补丁（不可删除）
    └── github.com/honeybbq/teamspeak-go/
```

**go.mod 关键内容**：

```go
module tsmobile

go 1.26.0

require github.com/honeybbq/teamspeak-go v0.2.0

// 本地补丁替换（必须保留）
replace github.com/honeybbq/teamspeak-go => ./_patches/github.com/honeybbq/teamspeak-go
```

**gomobile 工具声明**（go.mod 中）：

```go
tool golang.org/x/mobile/cmd/gobind
```

**关键依赖**：

| 依赖 | 用途 |
| --- | --- |
| `github.com/honeybbq/teamspeak-go` | TeamSpeak 协议实现 |
| `golang.org/x/mobile` | gomobile 工具链 |
| `golang.org/x/crypto` | 加密支持 |

**本地补丁说明**：

`go/_patches/github.com/honeybbq/teamspeak-go/` 包含修改后的上游代码：
- 修复 32 位整数溢出问题（`math.MaxUint32` → 平台相关限制）
- 通过 `go.mod` 的 `replace` 指令应用

> ⚠️ **不可删除**此目录或移除 replace 指令，否则编译或运行时会出错。

---

### 2.3 构建脚本

项目提供两个构建脚本，位于仓库根目录：

| 脚本 | 平台 | 说明 |
| --- | --- | --- |
| `build.bat` | Windows | 批处理脚本 |
| `build.sh` | Linux/macOS | Shell 脚本 |

**构建流程分 4 步**：

```
[1/4] 检查依赖 → [2/4] 下载 Go 依赖 → [3/4] Go → AAR → [4/4] Android → APK
```

**Step 1：检查依赖**
- 检查 `go` 命令是否可用
- 检查 `gomobile` 是否安装（不存在则自动安装并 init）
- 检查 `ANDROID_HOME` 环境变量

**Step 2：下载 Go 依赖**
```bash
cd go && go mod tidy
```

**Step 3：Go → AAR**（核心步骤）
```bash
# Windows 需先设置编码
set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8

gomobile bind \
  -target=android \
  -androidapi=26 \
  -ldflags="-linkmode=external -extldflags=-Wl,--hash-style=both" \
  -o android/app/libs/teamspeak.aar \
  ./teamspeak
```

**必须的 ldflags**：
- `-linkmode=external`：使用 NDK 外部链接器，防止 Go 运行时与 Android 信号处理冲突导致 SIGSEGV
- `-extldflags=-Wl,--hash-style=both`：生成兼容的 ELF 哈希表，防止 `dlopen failed: empty/missing DT_HASH`

**Step 4：Android → APK**
```bash
cd android && ./gradlew assembleDebug
```

**输出**：`android/app/build/outputs/apk/debug/app-debug.apk`

---

### 2.4 依赖管理

#### Kotlin/Android 依赖（app/build.gradle.kts）

**Compose 相关**：

| 依赖 | 版本 | 用途 |
| --- | --- | --- |
| `compose-bom` | 2024.12.01 | Compose 版本目录 |
| `material3` | BOM 管理 | Material Design 3 |
| `material-icons-extended` | BOM 管理 | 扩展图标库 |
| `ui-tooling` | BOM 管理 | 调试工具 |

**架构组件**：

| 依赖 | 版本 | 用途 |
| --- | --- | --- |
| `activity-compose` | 1.9.3 | Compose Activity 集成 |
| `navigation-compose` | 2.8.5 | 导航框架 |
| `lifecycle-runtime-compose` | 2.8.7 | 生命周期感知 |
| `lifecycle-viewmodel-compose` | 2.8.7 | ViewModel 集成 |

**工具库**：

| 依赖 | 版本 | 用途 |
| --- | --- | --- |
| `datastore-preferences` | 1.1.1 | 持久化键值存储（替代 SharedPreferences） |
| `kotlinx-coroutines-android` | 1.9.0 | 协程支持 |
| `kotlinx-serialization-json` | 1.7.3 | JSON 序列化 |

**gomobile AAR 引入方式**：

```kotlin
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
```

将 `teamspeak.aar` 放入 `app/libs/` 目录即可自动引入。

#### Gradle 插件（根 build.gradle.kts）

| 插件 | 版本 | 用途 |
| --- | --- | --- |
| `com.android.application` | 8.7.3 | Android 构建 |
| `org.jetbrains.kotlin.android` | 2.1.0 | Kotlin Android 支持 |
| `org.jetbrains.kotlin.plugin.compose` | 2.1.0 | Compose 编译器插件 |
| `org.jetbrains.kotlin.plugin.serialization` | 2.1.0 | 序列化插件 |

---

## 三、验收标准

| # | 验证项 | 验证方法 |
| --- | --- | --- |
| 1 | Go 模块可正常编译 | `cd go && go build ./teamspeak` 无报错 |
| 2 | gomobile 生成 AAR | 运行 `build.bat` / `build.sh` 第 3 步，`app/libs/teamspeak.aar` 存在且大小 > 0 |
| 3 | Android 项目可编译 | `cd android && gradlew.bat assembleDebug` 成功 |
| 4 | 空白 APK 可安装 | 安装 `app-debug.apk` 到设备/模拟器，启动无崩溃 |
| 5 | TSBridge 可调用 | 在 MainActivity 中添加 `TSBridge.isConnected()` 调用，编译通过 |

---

## 四、已完成清单

| 项目 | 状态 | 文件 |
| --- | --- | --- |
| Android 项目结构 | ✅ | `android/` 目录 |
| Gradle 构建配置 | ✅ | `android/build.gradle.kts`, `android/app/build.gradle.kts` |
| AndroidManifest | ✅ | `android/app/src/main/AndroidManifest.xml` |
| Go 模块配置 | ✅ | `go/go.mod` |
| 本地补丁 | ✅ | `go/_patches/` |
| 构建脚本 | ✅ | `build.bat`, `build.sh` |
| TSBridge 封装 | ✅ | `android/app/src/main/java/com/tsmobile/app/TSBridge.kt` |
| VoiceService 骨架 | ✅ | `android/app/src/main/java/com/tsmobile/app/voice/` |

---

## 五、参考文档

- `CLAUDE.md` — 构建命令、关键 flags 说明
- `docs/sdk文档-go.md` — SDK 依赖与 API
- `docs/UI架构设计.md` — 整体架构设计
