# ts-mobile-go 构建指南（新手向）

本文档面向没有 Android 开发经验的同学，手把手教你从零把这个项目跑起来。

---

## 目录

1. [项目是什么](#1-项目是什么)
2. [需要安装哪些软件](#2-需要安装哪些软件)
3. [安装步骤详解](#3-安装步骤详解)
4. [第一次构建（全流程）](#4-第一次构建全流程)
5. [在 IDEA 中打开和运行](#5-在-idea-中打开和运行)
6. [日常开发流程](#6-日常开发流程)
7. [常见问题排查](#7-常见问题排查)

---

## 1. 项目是什么

这是一个 TeamSpeak 客户端的 Android 手机应用，架构分两层：

```
┌─────────────────────────────────────────────┐
│  Android 层（Kotlin + Jetpack Compose）       │
│  负责：界面显示、用户交互、状态管理             │
├─────────────────────────────────────────────┤
│  Go 层（gomobile 编译成 .aar 库）             │
│  负责：TeamSpeak 协议通信、加密、数据处理       │
└─────────────────────────────────────────────┘
```

**关键概念：**
- **Go** — 一门编程语言，这里用来写 TeamSpeak 的底层通信逻辑
- **gomobile** — Go 官方工具，能把 Go 代码编译成 Android 能用的库文件（`.aar`）
- **AAR** — Android Archive，Android 的库文件格式，类似于 Windows 的 `.dll`
- **Gradle** — Android 的构建工具，类似前端的 Webpack/Vite，负责编译、打包、生成 APK
- **APK** — Android Package，安卓手机上安装的应用文件，类似 Windows 的 `.exe`
- **Kotlin** — Android 官方推荐的编程语言（类似 Java，但更现代）
- **Jetpack Compose** — Android 的现代 UI 框架（类似 React/Vue，用代码写界面）

---

## 2. 需要安装哪些软件

| 软件 | 用途 | 必须？ |
|---|---|---|
| **Go 1.26+** | 编译 Go 通信层代码 | ✅ 是 |
| **IntelliJ IDEA** 或 **Android Studio** | 打开项目、编写代码、运行应用 | ✅ 是 |
| **Android SDK** | Android 开发工具包（IDEA/Android Studio 会自带） | ✅ 是 |
| **JDK 17+** | Java 运行环境，Gradle 构建需要 | ✅ 是 |
| **ADB** | 把 APK 安装到手机上（IDEA 自带） | 手机调试需要 |

**你大概率已经有了：** 如果你电脑上已经装过 IntelliJ IDEA 或 Android Studio，JDK 和 Android SDK 应该已经自带了，只需要额外装一个 Go。

---

## 3. 安装步骤详解

### 3.1 安装 Go

1. 打开 https://go.dev/dl/
2. 下载 Windows 的 `.msi` 安装包（选 `go1.26.x.windows-amd64.msi`）
3. 双击安装，全部默认下一步即可
4. 安装完成后，**关闭并重新打开** 命令行（CMD 或 PowerShell），验证：
   ```bash
   go version
   # 应该输出类似：go version go1.26.0 windows/amd64
   ```

### 3.2 安装 gomobile

gomobile 是 Go 的官方工具，用来把 Go 代码编译成 Android 能用的 `.aar` 文件。

打开命令行（CMD 或 PowerShell），执行：

```bash
# 1. 安装 gomobile
go install golang.org/x/mobile/cmd/gomobile@latest

# 2. 初始化 gomobile（下载 Android 相关的工具链）
gomobile init
```

验证：
```bash
gomobile version
# 应该输出版本号，没有报错就说明成功了
```

> **如果 `gomobile` 命令找不到：** 说明 Go 的 `bin` 目录没加到系统 PATH。
> 默认路径是 `C:\Users\你的用户名\go\bin`，把它加到系统环境变量 PATH 里，
> 然后重新打开命令行。

### 3.3 安装 IntelliJ IDEA 或 Android Studio

二选一：

- **IntelliJ IDEA**（推荐，你可能已经有了）— 需要 Ultimate 版或安装 Android 插件
- **Android Studio**（免费）— https://developer.android.com/studio

安装时确保勾选了以下组件：
- ✅ Android SDK
- ✅ Android SDK Platform（API 26 以上）
- ✅ Android SDK Build-Tools
- ✅ JDK 17+（通常会自动安装）

安装完成后，确认 Android SDK 路径：
- **IDEA**: File → Settings → Languages & Frameworks → Android SDK
- **Android Studio**: 自动配置

记下这个路径（类似 `C:\Users\你的用户名\AppData\Local\Android\Sdk`），后面可能用到。

### 3.4 设置环境变量

打开系统环境变量设置（Win + S 搜索"环境变量"）：

| 变量名 | 值 | 说明 |
|---|---|---|
| `ANDROID_HOME` | `C:\Users\你的用户名\AppData\Local\Android\Sdk` | Android SDK 路径 |
| `JAVA_HOME` | `C:\Program Files\JetBrains\IntelliJ IDEA xxx\jbr` | JDK 路径（IDEA 自带的 JBR 即可） |

> **怎么找到 JAVA_HOME？**
> 如果你用的是 IntelliJ IDEA，它自带了一个 JDK（叫 JBR）。
> 路径类似：`C:\Program Files\JetBrains\IntelliJ IDEA 2024.3\jbr`
> 在 IDEA 的 File → Project Structure → SDK 里可以看到具体路径。

把以下路径加到系统 `PATH` 变量中：
```
%ANDROID_HOME%\platform-tools
%ANDROID_HOME%\tools
```

---

## 4. 第一次构建（全流程）

### 4.1 理解构建流程

整个构建分两步：

```
第一步：Go 代码 → .aar 文件
  go/teamspeak/bridge.go  ──(gomobile编译)──>  android/app/libs/teamspeak.aar

第二步：Android 代码 + .aar → .apk 文件
  android/app/src/**/*.kt + teamspeak.aar  ──(Gradle构建)──>  app-debug.apk
```

**必须先完成第一步，才能做第二步。** 因为 Android 代码依赖 Go 编译出来的 `.aar` 文件。

### 4.2 一键构建（推荐）

项目根目录下有一个构建脚本，自动完成所有步骤：

**Windows：**
```bash
cd E:\MyProject\ts-mobile\ts-mobile-go
build.bat
```

**Linux / macOS：**
```bash
cd /path/to/ts-mobile-go
chmod +x build.sh
./build.sh
```

脚本会自动：
1. ✅ 检查 Go、gomobile、Android SDK 是否已安装
2. ✅ 下载 Go 依赖
3. ✅ 编译 Go 代码为 `.aar` 文件
4. ✅ 调用 Gradle 构建 APK

构建成功后，APK 文件在：
```
android/app/build/outputs/apk/debug/app-debug.apk
```

### 4.3 手动构建（了解原理）

如果你想了解每一步在做什么，可以手动执行：

**第一步：编译 Go → AAR**

```bash
# 进入 Go 目录
cd E:\MyProject\ts-mobile\ts-mobile-go\go

# 下载 Go 依赖（类似 npm install）
go mod tidy

# 编译为 AAR（这是关键命令）
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
```

命令解释：
- `gomobile bind` — 把 Go 代码编译成 Android 库
- `-target=android` — 目标平台是 Android（自动包含所有架构：arm64、arm、x86、x86_64）
- `-androidapi=26` — 最低支持 Android 8.0（API 26）
- `-ldflags="-linkmode=external -extldflags=-Wl,--hash-style=both"` — **重要！** 两个关键标志：
  - `-linkmode=external` — 使用外部链接器（NDK 的 clang），避免 Go 内置链接器与 Android 信号处理冲突导致 SIGSEGV 崩溃
  - `-extldflags=-Wl,--hash-style=both` — 强制生成兼容 Android 的 ELF hash 格式
- `-o ../android/app/libs/teamspeak.aar` — 输出文件路径
- `./teamspeak` — 要编译的 Go 包路径

> **为什么要设置 `JAVA_TOOL_OPTIONS`？**
> gomobile 内部会调用 `javac`（Java 编译器）来生成 Java 接口代码。
> Windows 下 javac 默认用 GBK 编码，但我们的 Go 源码注释里有中文，是 UTF-8 编码。
> 不设置这个会导致编译报错"非法字符"。

**第二步：构建 Android APK**

```bash
# 进入 Android 目录
cd E:\MyProject\ts-mobile\ts-mobile-go\android

# 构建 debug 版本的 APK
gradlew.bat assembleDebug
```

构建成功后，APK 在 `app\build\outputs\apk\debug\app-debug.apk`。

### 4.4 安装到手机

#### 方法 A：用 ADB 命令安装

1. 手机开启 **USB 调试**：
   - 进入手机 **设置 → 关于手机**
   - 连续点击 **版本号** 7 次，会提示"你已进入开发者模式"
   - 返回设置，进入 **开发者选项**
   - 打开 **USB 调试**

2. 用 USB 数据线连接手机到电脑

3. 手机上弹出"允许 USB 调试"的提示，点 **允许**

4. 在命令行执行：
   ```bash
   # 查看是否识别到手机
   adb devices
   # 应该显示类似：
   # List of devices attached
   # XXXXXXXX    device

   # 安装 APK
   adb install E:\MyProject\ts-mobile\ts-mobile-go\android\app\build\outputs\apk\debug\app-debug.apk
   ```

5. 安装成功后，手机上找到 "ts-mobile-go" 应用，点击打开即可

#### 方法 B：直接把 APK 传到手机

1. 构建完成后，找到 `app-debug.apk` 文件
2. 通过微信/QQ/邮件/数据线 发送到手机
3. 手机上点击 APK 文件，允许安装未知来源应用，完成安装

---

## 5. 在 IDEA 中打开和运行

### 5.1 打开项目

1. 启动 IntelliJ IDEA
2. **File → Open**
3. 选择 `E:\MyProject\ts-mobile\ts-mobile-go\android\` 目录（注意是 `android` 子目录，不是根目录）
4. 弹出提示框，点击 **Trust Project**
5. 等待右下角进度条走完（Gradle Sync，首次可能需要 2-5 分钟下载依赖）

> **如果提示安装 Android 插件：** 点击安装，然后重启 IDEA。

### 5.2 配置运行设备

#### 使用模拟器（推荐新手）

1. 在 IDEA 中：**Tools → Device Manager**（或工具栏上的手机图标）
2. 点击 **Create Virtual Device**
3. 选择一个手机型号（比如 Pixel 7），点 Next
4. 选择系统镜像：选 **API 34** 或更高版本（需要先点击 Download 下载）
5. 点 Next → Finish
6. 在 Device Manager 中点击 ▶ 启动模拟器

#### 使用真机

1. 手机开启 USB 调试（见 4.4 节）
2. USB 连接电脑
3. IDEA 工具栏的设备下拉框中应该能看到你的手机

### 5.3 运行应用

1. 确保 IDEA 工具栏的设备下拉框中选择了你的手机或模拟器
2. 确保运行配置选择的是 **app**
3. 点击绿色三角 **▶** 按钮（或按 `Shift + F10`）
4. IDEA 会自动编译并安装到设备上

> **注意：** 首次运行前，必须先完成 Go → AAR 的编译（第 4.2 或 4.3 节）。
> IDEA 只负责 Android 部分的构建，不会自动编译 Go 代码。

### 5.4 查看运行日志

在 IDEA 底部面板找到 **Logcat** 标签页，可以看到应用的运行日志，方便调试。

---

## 6. 日常开发流程

### 改了 Go 代码（`go/` 目录下的文件）

```bash
# 重新编译 AAR
cd E:\MyProject\ts-mobile\ts-mobile-go\go
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
```

然后在 IDEA 中重新运行应用（点 ▶）即可。IDEA 会自动检测到 `.aar` 文件变化并重新打包。

### 改了 Kotlin 代码（`android/` 目录下的文件）

直接在 IDEA 中点 ▶ 运行，IDEA 会自动增量编译。

### 常用 IDEA 快捷键

| 操作 | 快捷键 |
|---|---|
| 运行 | `Shift + F10` |
| 调试 | `Shift + F9` |
| 全局搜索 | `Shift + Shift` |
| 格式化代码 | `Ctrl + Alt + L` |
| 查看当前文件结构 | `Ctrl + F12` |

---

## 7. 常见问题排查

### Q: Gradle Sync 失败，提示 "Unresolved reference: dependencyResolutionManagement"

**原因：** `settings.gradle.kts` 中的 API 名称写错了。

**解决：** 确认 `android/settings.gradle.kts` 第 9 行是：
```kotlin
dependencyResolutionManagement {  // ← 不是 dependencyResolution
```

### Q: gomobile bind 报错 "missing golang.org/x/mobile dependency"

**原因：** Go 模块缺少 `golang.org/x/mobile` 依赖。

**解决：**
```bash
cd E:\MyProject\ts-mobile\ts-mobile-go\go
go get -tool golang.org/x/mobile/cmd/gobind
go mod tidy
```

### Q: gomobile bind 报错 "unknown revision v0.0.0"

**原因：** `go.mod` 中的依赖版本号不存在。

**解决：** 确认 `go/go.mod` 中的版本号是有效的：
```
require github.com/honeybbq/teamspeak-go v0.2.0
```
而不是 `v0.0.0`。

### Q: javac 报错 "非法字符" 或 "GBK 不可映射字符"

**原因：** Go 源码中的中文注释在 Windows 下被 javac 当作 GBK 编码处理。

**解决：** 在执行 gomobile 之前设置环境变量：
```bash
set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
```

### Q: gomobile bind 报错 "math.MaxUint32 overflows int"

**原因：** 上游 `teamspeak-go` 库在 32 位目标平台上有整数溢出问题。

**解决：** 这个问题已经通过本地 patch 修复了（见 `go/_patches/` 目录）。如果仍然遇到，可以只编译 64 位版本：
```bash
gomobile bind -target=android/arm64 ...
```
注意是 `android/arm64`，不是 `android`（后者会同时编译 32 位和 64 位）。

### Q: adb devices 显示 "unauthorized"

**原因：** 手机上没有授权这台电脑的 USB 调试。

**解决：** 检查手机屏幕，应该有一个"允许 USB 调试"的弹窗，点击允许。如果没有弹窗，拔掉 USB 重新插入。

### Q: 安装 APK 时提示 "安装包似乎已损坏"

**原因：** 可能是构建过程中出了问题，或者手机架构不匹配。

**解决：**
1. 在 IDEA 中执行 **Build → Clean Project**，然后重新构建
2. 确认手机是 64 位 ARM 架构（2018 年以后的手机基本都是）

### Q: IDEA 提示 "SDK not found" 或 "JAVA_HOME not set"

**解决：**
1. **File → Project Structure → SDKs**，添加 Android SDK 路径
2. **File → Project Structure → Project**，设置 JDK 为 17 或更高
3. 确认系统环境变量中 `ANDROID_HOME` 和 `JAVA_HOME` 已正确设置

### Q: 应用安装后打开闪退，Logcat 显示 "dlopen failed: empty/missing DT_HASH/DT_GNU_HASH"

**原因：** Go 1.24+ 编译器生成的 .so 文件使用了 Android 链接器不认识的新 hash 格式（`DT_SUNW_HASH`）。Android 需要传统的 `DT_HASH` 或 `DT_GNU_HASH` 格式。

**解决：** 重新编译 AAR 时加上 `-ldflags` 标志（构建脚本已包含）：
```bash
cd E:\MyProject\ts-mobile\ts-mobile-go\go
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
```
然后重新构建 APK 并安装。

### Q: 应用启动后几秒闪退，Logcat 显示 "Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR)"

**原因：** Go 运行时的信号处理与 Android 内存保护机制冲突。Go 使用 SIGSEGV 做垃圾回收和协程调度，但 Android 的 SEGV_ACCERR 策略会阻止这种用法。

**解决：** 重新编译 AAR 时加上 `-linkmode=external` 标志（构建脚本已包含）：
```bash
gomobile bind ... -ldflags="-linkmode=external -extldflags=-Wl,--hash-style=both" ...
```
`-linkmode=external` 强制 Go 使用 NDK 的外部链接器，避免内置链接器的信号处理冲突。

### Q: 应用安装后打开闪退（其他原因）

**可能原因：** Go 编译的 `.aar` 文件有问题，或者没有 `.aar` 文件。

**排查：**
1. 确认 `android/app/libs/teamspeak.aar` 文件存在且大小不为 0
2. 重新执行 Go 编译步骤
3. 在 IDEA 的 Logcat 中查看崩溃日志
4. 如果看到 `UnsatisfiedLinkError`，说明 .aar 中的 .so 文件架构不匹配或格式有问题

---

## 附录：项目目录结构说明

```
ts-mobile-go/
├── go/                              ← Go 源码（底层通信）
│   ├── go.mod                       ← Go 的依赖声明（类似 package.json）
│   ├── go.sum                       ← Go 的依赖锁文件（类似 package-lock.json）
│   └── teamspeak/
│       └── bridge.go                ← 核心：TeamSpeak 客户端桥接代码
│
├── android/                         ← Android 项目（IDEA 打开这个目录）
│   ├── build.gradle.kts             ← 根级构建配置（定义 Kotlin、AGP 版本）
│   ├── settings.gradle.kts          ← 项目设置（仓库地址、模块声明）
│   ├── gradle.properties            ← Gradle 参数（内存、编码等）
│   ├── gradle/wrapper/              ← Gradle 版本管理（自动下载指定版本的 Gradle）
│   └── app/
│       ├── build.gradle.kts         ← 应用级构建配置（依赖、SDK 版本、签名等）
│       ├── libs/
│       │   └── teamspeak.aar        ← ← ← Go 编译产物，放在这里！
│       ├── proguard-rules.pro       ← 代码混淆规则
│       └── src/main/
│           ├── AndroidManifest.xml  ← 应用声明（权限、入口 Activity 等）
│           └── java/com/tsmobile/app/
│               ├── MainActivity.kt      ← 应用入口
│               ├── TSBridge.kt          ← Kotlin 调用 Go 的桥接层
│               ├── ui/
│               │   ├── components/      ← 可复用 UI 组件
│               │   ├── screens/         ← 各页面（连接、频道、聊天等）
│               │   ├── navigation/      ← 页面路由
│               │   └── theme/           ← 主题颜色、字体
│               └── viewmodel/           ← 状态管理（ViewModel）
│
├── build.bat                        ← Windows 一键构建脚本
├── build.sh                         ← Linux/macOS 一键构建脚本
└── BUILD.md                         ← 本文件
```
