4.4 KiB
AGENTS.md
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Project Overview
TeamSpeak Android native client with a two-layer architecture:
- Protocol layer: Go + teamspeak-go → compiled to
.aarvia gomobile - UI layer: Kotlin + Jetpack Compose + Material Design 3
Build Commands
Full Build (Recommended)
# Windows
build.bat
# Linux/macOS
./build.sh
Manual Build (Two Steps Required)
Step 1: Compile Go → AAR
cd go
set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 # Windows only
gomobile bind -target=android -androidapi=26 -ldflags="-linkmode=external -extldflags=-Wl,--hash-style=both" -o ../android/app/libs/teamspeak.aar ./teamspeak
Step 2: Build Android APK
cd android
gradlew.bat assembleDebug # Windows
./gradlew assembleDebug # Linux/macOS
Development Workflow
- Modified Go code (
go/): Re-run Step 1, then run from IDE - Modified Kotlin code (
android/): Just run from IDE (IntelliJ/Android Studio)
Open the android/ directory (not root) in IntelliJ IDEA or Android Studio.
Architecture
Go ↔ Kotlin Bridge
Communication flows through two bridge layers:
- Go side (
go/teamspeak/bridge.go): ExportsTSClientclass via gomobile - Kotlin side (
android/app/src/main/java/com/tsmobile/app/TSBridge.kt): Wraps gomobile API
Key constraints (gomobile limitations):
- Cannot export
[]string,[]*T, or Goerrortypes - Complex data passed as JSON strings (channels, clients)
- Events delivered via callback interfaces
- All JNI callbacks serialized through an event queue to avoid threading issues
Event flow: Go library → event queue → single consumer goroutine → JNI callback → Kotlin callback → ViewModel
Android Layer Structure
android/app/src/main/java/com/tsmobile/app/
├── MainActivity.kt # Entry point
├── TSBridge.kt # Go bridge wrapper
├── ui/
│ ├── components/ # Reusable UI components
│ ├── screens/ # Top-level screens
│ ├── navigation/NavGraph.kt # App navigation
│ └── theme/ # Material Design 3 theme
└── viewmodel/ # State management
├── ChannelViewModel.kt # Channel list & navigation
├── ChatViewModel.kt # Text messaging
├── ServerViewModel.kt # Connection & server info
└── VoiceViewModel.kt # Voice communication
State flows from ViewModels → Screens via StateFlow. User actions flow back via ViewModel methods.
Critical Build Details
Required Flags for gomobile
The -ldflags are mandatory to avoid runtime crashes:
-
-linkmode=external: Use NDK's external linker instead of Go's built-in linker- Why: Prevents
SIGSEGVcrashes due to signal handling conflicts between Go runtime and Android - Go uses SIGSEGV for GC and goroutine scheduling; Android's memory protection blocks this
- Why: Prevents
-
-extldflags=-Wl,--hash-style=both: Generate compatible ELF hash tables- Why: Go 1.24+ uses
DT_SUNW_HASHby default; Android requiresDT_HASHorDT_GNU_HASH - Without this:
dlopen failed: empty/missing DT_HASH/DT_GNU_HASHerror
- Why: Go 1.24+ uses
Local Patches
The go/_patches/github.com/honeybbq/teamspeak-go/ directory contains modified upstream code:
- Fixes 32-bit integer overflow issues (
math.MaxUint32→ platform-specific limits) - Applied via
go.modreplace directive:replace github.com/honeybbq/teamspeak-go => ./_patches/github.com/honeybbq/teamspeak-go
Do not remove this directory or the replace directive.
Common Issues
"javac: 非法字符" or "GBK unmappable character"
Set encoding before running gomobile on Windows:
set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
App crashes with "SIGSEGV" on startup
Missing -linkmode=external flag. Rebuild AAR with correct flags.
App crashes with "empty/missing DT_HASH"
Missing -Wl,--hash-style=both flag. Rebuild AAR with correct flags.
"Unresolved reference: teamspeak"
AAR not compiled or not in android/app/libs/teamspeak.aar. Run Step 1 of manual build.
Testing
Run from IDE with connected device or emulator. Check Logcat in IDE for runtime logs.
No automated test suite currently exists.