fix:修复中文显示

This commit is contained in:
spiritlhl
2025-10-31 10:12:40 +08:00
parent 1f36225960
commit 2c664f90bb
11 changed files with 217 additions and 443 deletions

20
.build/README.md Normal file
View File

@@ -0,0 +1,20 @@
# Android APK 构建产物
此目录存放 GitHub Actions 自动构建的 APK 文件。
## 文件命名规则
`goecs-android-{arch}-{version}.apk`
- arch: arm64 或 x86_64
- version: 版本号格式为 v1.0.0-YYYYMMDD-{git-hash}
## 架构说明
- **arm64**: 适用于真实 Android 设备(推荐)
- **x86_64**: 适用于 Android 模拟器
## 使用方法
下载对应架构的 APK 文件,传输到 Android 设备上安装即可。

View File

@@ -1,94 +0,0 @@
name: Build Android APK
on:
push:
branches:
- android-app
pull_request:
branches:
- android-app
workflow_dispatch:
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-android-${{ hashFiles('go.sum') }}
restore-keys: |
${{ runner.os }}-go-android-
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc libgl1-mesa-dev xorg-dev
- name: Install Fyne CLI
run: |
go install fyne.io/fyne/v2/cmd/fyne@latest
echo "$HOME/go/bin" >> $GITHUB_PATH
- name: Set up Android SDK
uses: android-actions/setup-android@v3
- name: Install Android NDK
run: |
echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;25.2.9519653"
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/25.2.9519653" >> $GITHUB_ENV
- name: Download dependencies
run: |
go mod download
go mod tidy
- name: Build Android APK
run: |
fyne package -os android -appID com.oneclickvirt.goecs -name GoECS
env:
CGO_ENABLED: 1
- name: Get version
id: version
run: |
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="dev-$(git rev-parse --short HEAD)"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Rename APK
run: |
if [ -f GoECS.apk ]; then
mv GoECS.apk goecs-android-${{ steps.version.outputs.version }}.apk
fi
- name: Upload APK artifact
uses: actions/upload-artifact@v4
with:
name: goecs-android-${{ steps.version.outputs.version }}
path: goecs-android-*.apk
retention-days: 30
- name: Create Release (on tag)
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: goecs-android-*.apk
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

18
.gitignore vendored
View File

@@ -1,6 +1,20 @@
*.apkvendor/
# APK and AAB files (keep .build directory)
*.apk
!.build/*.apk
*.aab
*.aab.idea/
# Vendor
vendor/
# IDE
.idea/
# macOS
.DS_Store
# Fyne cross-compilation cache
fyne-cross/
.fyne-cross/
# Build binaries
goecs-android

View File

@@ -1,8 +1,13 @@
Website = "https://github.com/oneclickvirt/ecs"
[Details]
Icon = "icon.png"
Icon = "logo.png"
Name = "GoECS"
ID = "com.oneclickvirt.goecs"
Version = "1.0.0"
Build = 1
[Android]
MinVersion = 24
TargetVersion = 33
Arch = ["arm64", "x86_64"]

139
README.md
View File

@@ -17,33 +17,19 @@ GoECS 服务器性能测试工具的 Android 版本。支持 **图形界面模
-**结果导出**
-**完整的参数支持**
## 🚀 快速开始
## 快速开始
### GUI 模式(图形界面)
### 运行应用
```bash
# 直接运行(默认启动 GUI
# 直接运行
./goecs-android
# 或明确指定 GUI 模式
./goecs-android -gui
```
# 显示帮助
./goecs-android --help
### CLI 模式(命令行)
```bash
# 运行所有测试
./goecs-android -all
# 运行指定测试
./goecs-android -basic -cpu -memory
# 指定配置运行
./goecs-android -cpu -cpu-method sysbench -thread multi
./goecs-android -disk -disk-path /tmp -disk-method fio
# 英文环境
./goecs-android -all -lang en
# 显示版本
./goecs-android -version
```
## 📖 命令行参数
@@ -79,35 +65,112 @@ GoECS 服务器性能测试工具的 Android 版本。支持 **图形界面模
go run .
```
### 编译二进制
## 本地开发
### 前置要求
- Go 1.21+
- Fyne v2.4.5+
- 用于 Android 构建Android SDK + NDK
### macOS 上测试
```bash
# 安装依赖
go mod download
# 运行桌面版本(用于开发测试)
go run .
# 或编译后运行
go build -o goecs-android .
./goecs-android
```
### 构建 Android APK
#### 方法 1: 使用 Fyne CLI本地构建
```bash
# 安装 Fyne CLI
go install fyne.io/fyne/v2/cmd/fyne@latest
# 构建 APK多架构
mkdir -p .build
# ARM64 架构(主流 Android 设备)
fyne package -os android -appID com.oneclickvirt.goecs -name GoECS
mv GoECS.apk .build/goecs-android-arm64.apk
# x86_64 架构(模拟器)
ANDROID_ARCH=x86_64 fyne package -os android -appID com.oneclickvirt.goecs -name GoECS
mv GoECS.apk .build/goecs-android-x86_64.apk
```
## 🤖 自动构建
#### 方法 2: 使用 GitHub Actions推荐
推送到 `android-app` 分支会自动触发 CI 构建 APK。
手动触发构建:
## 📦 技术栈
1. 访问 GitHub 仓库的 Actions 页面
2. 选择 "Build Android APK" workflow
3. 点击 "Run workflow" 按钮
4. 等待构建完成
- **UI 框架**: Fyne v2.4.5
- **语言**: Go 1.24.5
- **核心依赖**: github.com/oneclickvirt/ecs v0.1.91
- **最低 Android 版本**: Android 7.0 (API Level 24+)
构建成功后:
- APK 文件会自动提交到 `android-app` 分支的 `.build/` 目录
- 同时在 Actions 的 Artifacts 中也可以下载
## 🌳 分支说明
文件命名格式:
- `goecs-android-arm64-v1.0.0-YYYYMMDD-{hash}.apk` - 真机使用
- `goecs-android-x86_64-v1.0.0-YYYYMMDD-{hash}.apk` - 模拟器使用
## 技术栈
- **UI 框架**: [Fyne](https://fyne.io/) v2.4.5
- **核心库**: [github.com/oneclickvirt/ecs](https://github.com/oneclickvirt/ecs) v0.1.91
- **语言**: Go 1.21+
- **目标平台**: Android 7.0+ (API Level 24+)
- **支持架构**: ARM64, x86_64
## 常见问题
### Q: 为什么界面显示方块字符?
A: 需要确保 Android 系统有中文字体支持。本应用使用 Android 系统默认字体,应该能正常显示中文。如果问题依然存在,请检查设备的语言设置。
### Q: 如何在 macOS 上测试?
A: 使用 `go run .``go build` 编译后直接运行。macOS 版本仅用于开发测试,最终产品为 Android APK。
### Q: APK 文件在哪里?
A: 本地构建后在 `.build/` 目录GitHub Actions 构建后会自动提交到 android-app 分支的 `.build/` 目录,也可从 Artifacts 下载。
### Q: 支持哪些 Android 设备?
A: Android 7.0 (API 24) 及以上版本。ARM64 APK 适用于大多数现代设备x86_64 APK 适用于模拟器。
### Q: 如何手动触发 APK 构建?
A: 访问 GitHub 仓库的 Actions 页面,选择 "Build Android APK" workflow点击 "Run workflow" 按钮即可。
## 贡献
欢迎提交 Issue 和 Pull Request
## 许可证
遵循主项目 https://github.com/oneclickvirt/ecs 的许可证。
## 相关链接
- 主项目: https://github.com/oneclickvirt/ecs
- Android 分支: https://github.com/oneclickvirt/ecs/tree/android-app
## 分支说明
这是一个**孤儿分支**orphan branch与 master 分支完全独立:
- 没有 master 的提交历史
- 根目录直接是应用代码
- 使用远程依赖而非本地引用
- 独立的 CI/CD 流程
## 📝 许可证
遵循 https://github.com/oneclickvirt/ecs 项目的许可证。
- 没有 master 的提交历史
- 根目录直接是应用代码
- 使用远程依赖而非本地引用
- 独立的 CI/CD 流程

171
cli.go
View File

@@ -1,171 +0,0 @@
package main
import (
"fmt"
"time"
"github.com/oneclickvirt/ecs/cputest"
"github.com/oneclickvirt/ecs/disktest"
"github.com/oneclickvirt/ecs/memorytest"
"github.com/oneclickvirt/ecs/speedtest"
"github.com/oneclickvirt/ecs/unlocktest"
"github.com/oneclickvirt/ecs/utils"
)
// CLIRunner CLI 模式的测试运行器
type CLIRunner struct {
language string
cpuMethod string
threadMode string
diskPath string
diskMethod string
}
// NewCLIRunner 创建新的 CLI 运行器
func NewCLIRunner(language, cpuMethod, threadMode, diskPath, diskMethod string) *CLIRunner {
if diskPath == "" {
diskPath = "/tmp"
}
return &CLIRunner{
language: language,
cpuMethod: cpuMethod,
threadMode: threadMode,
diskPath: diskPath,
diskMethod: diskMethod,
}
}
// Run 运行测试
func (r *CLIRunner) Run(basic, cpu, memory, disk, speed, unlock, route bool) {
startTime := time.Now()
fmt.Printf("\n测试开始时间: %s\n", startTime.Format("2006-01-02 15:04:05"))
fmt.Println("=" + repeatString("=", 80))
testCount := 0
// 基础信息测试
if basic {
testCount++
r.runBasicTest()
}
// CPU 测试
if cpu {
testCount++
r.runCPUTest()
}
// 内存测试
if memory {
testCount++
r.runMemoryTest()
}
// 磁盘测试
if disk {
testCount++
r.runDiskTest()
}
// 网络测速
if speed {
testCount++
r.runSpeedTest()
}
// 流媒体解锁
if unlock {
testCount++
r.runUnlockTest()
}
// 路由追踪
if route {
testCount++
r.runRouteTest()
}
// 总结
elapsed := time.Since(startTime)
fmt.Println("\n" + repeatString("=", 80))
fmt.Printf("测试完成! 共执行 %d 项测试,耗时: %v\n", testCount, elapsed)
fmt.Println(repeatString("=", 80))
}
func (r *CLIRunner) runBasicTest() {
fmt.Println("\n[1/N] 基础信息测试")
fmt.Println(repeatString("-", 80))
ipv4, ipv6, result := utils.OnlyBasicsIpInfo(r.language)
fmt.Printf("IPv4: %s\n", ipv4)
fmt.Printf("IPv6: %s\n", ipv6)
fmt.Println(result)
}
func (r *CLIRunner) runCPUTest() {
fmt.Println("\n[N/N] CPU 性能测试")
fmt.Println(repeatString("-", 80))
fmt.Printf("测试方法: %s\n", r.cpuMethod)
fmt.Printf("线程模式: %s\n", r.threadMode)
realMethod, result := cputest.CpuTest(r.language, r.cpuMethod, r.threadMode)
fmt.Printf("实际使用方法: %s\n", realMethod)
fmt.Println(result)
}
func (r *CLIRunner) runMemoryTest() {
fmt.Println("\n[N/N] 内存性能测试")
fmt.Println(repeatString("-", 80))
realMethod, result := memorytest.MemoryTest(r.language, "auto")
fmt.Printf("测试方法: %s\n", realMethod)
fmt.Println(result)
}
func (r *CLIRunner) runDiskTest() {
fmt.Println("\n[N/N] 磁盘性能测试")
fmt.Println(repeatString("-", 80))
fmt.Printf("测试路径: %s\n", r.diskPath)
fmt.Printf("测试方法: %s\n", r.diskMethod)
realMethod, result := disktest.DiskTest(r.language, r.diskMethod, r.diskPath, false, true)
fmt.Printf("实际使用方法: %s\n", realMethod)
fmt.Println(result)
}
func (r *CLIRunner) runSpeedTest() {
fmt.Println("\n[N/N] 网络测速")
fmt.Println(repeatString("-", 80))
speedtest.ShowHead(r.language)
fmt.Println("正在进行附近节点测速...")
speedtest.NearbySP()
fmt.Println("测速完成")
}
func (r *CLIRunner) runUnlockTest() {
fmt.Println("\n[N/N] 流媒体解锁测试")
fmt.Println(repeatString("-", 80))
result := unlocktest.MediaTest(r.language)
if result == "" {
fmt.Println("未检测到可用的网络连接")
} else {
fmt.Println(result)
}
}
func (r *CLIRunner) runRouteTest() {
fmt.Println("\n[N/N] 路由追踪测试")
fmt.Println(repeatString("-", 80))
fmt.Println("路由追踪功能开发中...")
}
func repeatString(s string, count int) string {
result := ""
for i := 0; i < count; i++ {
result += s
}
return result
}

2
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/oneclickvirt/ecs-android
go 1.24.5
require (
fyne.io/fyne/v2 v2.4.5
fyne.io/fyne/v2 v2.5.2
github.com/oneclickvirt/ecs v0.1.91
)

Binary file not shown.

149
main.go
View File

@@ -9,81 +9,34 @@ import (
)
var (
// UI 模式标志
guiMode bool
// 测试选项标志
basicTest bool
cpuTest bool
memoryTest bool
diskTest bool
speedTest bool
unlockTest bool
routeTest bool
allTests bool
// 配置选项
language string
cpuMethod string
threadMode string
diskPath string
diskMethod string
// 其他选项
showVersion bool
showHelp bool
)
func init() {
// UI 模式
flag.BoolVar(&guiMode, "gui", false, "启动图形界面模式 / Launch GUI mode")
// 测试选项
flag.BoolVar(&basicTest, "basic", false, "基础信息测试 / Basic info test")
flag.BoolVar(&cpuTest, "cpu", false, "CPU 性能测试 / CPU performance test")
flag.BoolVar(&memoryTest, "memory", false, "内存性能测试 / Memory performance test")
flag.BoolVar(&diskTest, "disk", false, "磁盘性能测试 / Disk performance test")
flag.BoolVar(&speedTest, "speed", false, "网络测速 / Network speed test")
flag.BoolVar(&unlockTest, "unlock", false, "流媒体解锁测试 / Media unlock test")
flag.BoolVar(&routeTest, "route", false, "路由追踪测试 / Route trace test")
flag.BoolVar(&allTests, "all", false, "运行所有测试 / Run all tests")
// 配置选项
flag.StringVar(&language, "lang", "zh", "语言: zh/en / Language: zh/en")
flag.StringVar(&cpuMethod, "cpu-method", "sysbench", "CPU测试方法: sysbench/geekbench/winsat")
flag.StringVar(&threadMode, "thread", "multi", "线程模式: single/multi")
flag.StringVar(&diskPath, "disk-path", "", "磁盘测试路径 / Disk test path")
flag.StringVar(&diskMethod, "disk-method", "auto", "磁盘测试方法: fio/dd/auto")
// 其他选项
flag.BoolVar(&showVersion, "version", false, "显示版本信息 / Show version")
flag.BoolVar(&showVersion, "v", false, "显示版本信息 / Show version")
flag.BoolVar(&showHelp, "help", false, "显示帮助信息 / Show help")
flag.BoolVar(&showHelp, "h", false, "显示帮助信息 / Show help")
flag.BoolVar(&showVersion, "version", false, "显示版本信息")
flag.BoolVar(&showVersion, "v", false, "显示版本信息")
flag.BoolVar(&showHelp, "help", false, "显示帮助信息")
flag.BoolVar(&showHelp, "h", false, "显示帮助信息")
}
func main() {
flag.Parse()
// 显示版本信息
if showVersion {
fmt.Println("GoECS Android v1.0.0")
fmt.Println("Based on github.com/oneclickvirt/ecs v0.1.91")
fmt.Println("基于 github.com/oneclickvirt/ecs v0.1.91")
fmt.Println("仅支持图形界面模式")
os.Exit(0)
}
// 显示帮助信息
if showHelp {
printHelp()
os.Exit(0)
}
// 如果指定了 GUI 模式或没有任何参数,启动 UI
if guiMode || (!hasAnyTest() && flag.NFlag() == 0) {
runGUIMode()
} else {
runCLIMode()
}
// 启动图形界面
runGUIMode()
}
func runGUIMode() {
@@ -94,81 +47,29 @@ func runGUIMode() {
ui.window.ShowAndRun()
}
func runCLIMode() {
fmt.Println("========== GoECS Android CLI 模式 ==========")
// 如果指定了 -all启用所有测试
if allTests {
basicTest = true
cpuTest = true
memoryTest = true
diskTest = true
speedTest = true
unlockTest = true
routeTest = true
}
// 执行测试
runner := NewCLIRunner(language, cpuMethod, threadMode, diskPath, diskMethod)
runner.Run(basicTest, cpuTest, memoryTest, diskTest, speedTest, unlockTest, routeTest)
}
func hasAnyTest() bool {
return basicTest || cpuTest || memoryTest || diskTest || speedTest || unlockTest || routeTest || allTests
}
func printHelp() {
fmt.Println(`
GoECS Android - 服务器性能测试工具 (Android 版本)
GoECS Android - 服务器性能测试工具
用法 / Usage:
goecs-android [选项] [测试项]
用法:
goecs-android 启动图形界面
模式 / Modes:
-gui 启动图形界面模式(默认)
Launch GUI mode (default)
选项:
-version, -v 显示版本信息
-help, -h 显示此帮助信息
测试项 / Tests:
-basic 基础信息测试
-cpu CPU 性能测试
-memory 内存性能测试
-disk 磁盘性能测试
-speed 网络测速
-unlock 流媒体解锁测试
-route 路由追踪测试
-all 运行所有测试
功能:
本应用提供图形界面,支持以下测试
- 基础信息测试
- CPU 性能测试
- 内存性能测试
- 磁盘性能测试
- 网络测速
- 流媒体解锁测试
- 路由追踪测试
配置选项 / Configuration:
-lang string 语言: zh/en (默认: zh)
-cpu-method CPU测试方法: sysbench/geekbench/winsat (默认: sysbench)
-thread 线程模式: single/multi (默认: multi)
-disk-path 磁盘测试路径 (默认: 自动检测)
-disk-method 磁盘测试方法: fio/dd/auto (默认: auto)
其他选项 / Other:
-version, -v 显示版本信息
-help, -h 显示此帮助信息
示例 / Examples:
# 启动 GUI 模式
goecs-android
goecs-android -gui
# 运行所有测试CLI 模式)
goecs-android -all
# 运行指定测试
goecs-android -basic -cpu -memory
# 指定配置运行测试
goecs-android -cpu -cpu-method sysbench -thread multi
goecs-android -disk -disk-path /tmp -disk-method fio
# 英文环境运行
goecs-android -all -lang en
更多信息 / More info:
更多信息:
GitHub: https://github.com/oneclickvirt/ecs
分支 / Branch: android-app
分支: android-app
`)
}

View File

@@ -20,9 +20,38 @@ func (m *customTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
}
func (m *customTheme) Font(style fyne.TextStyle) fyne.Resource {
return theme.DefaultTheme().Font(style)
// 使用 Fyne 内置字体资源,支持中文
// Fyne 2.4+ 内置了 Noto Sans 字体,包含中文支持
if style.Monospace {
return theme.DefaultTheme().Font(fyne.TextStyle{Monospace: true})
}
if style.Bold {
if style.Italic {
return theme.DefaultTheme().Font(fyne.TextStyle{Bold: true, Italic: true})
}
return theme.DefaultTheme().Font(fyne.TextStyle{Bold: true})
}
if style.Italic {
return theme.DefaultTheme().Font(fyne.TextStyle{Italic: true})
}
// 返回默认字体
return theme.DefaultTheme().Font(fyne.TextStyle{})
}
func (m *customTheme) Size(name fyne.ThemeSizeName) float32 {
return theme.DefaultTheme().Size(name)
// 增大字体以提高可读性
switch name {
case theme.SizeNameText:
return 16 // 默认 14
case theme.SizeNameHeadingText:
return 22 // 默认 20
case theme.SizeNameSubHeadingText:
return 18 // 默认 16
case theme.SizeNameCaptionText:
return 13 // 默认 11
case theme.SizeNamePadding:
return 6 // 增加间距
default:
return theme.DefaultTheme().Size(name)
}
}

27
ui.go
View File

@@ -59,10 +59,14 @@ type TestUI struct {
func NewTestUI(app fyne.App) *TestUI {
ui := &TestUI{
app: app,
window: app.NewWindow("GoECS - 服务器性能测试"),
window: app.NewWindow("融合怪测试"),
}
ui.window.Resize(fyne.NewSize(800, 600))
// 设置窗口大小 - 支持桌面和移动设备
// 移动设备会自动全屏
ui.window.Resize(fyne.NewSize(900, 700))
ui.window.SetPadded(true)
ui.buildUI()
return ui
}
@@ -80,7 +84,7 @@ func (ui *TestUI) buildUI() {
// 创建结果显示区域
resultArea := ui.createResultArea()
// 左侧面板:选项和配置
// 左侧面板:选项和配置(添加内边距以适应移动设备)
leftPanel := container.NewVBox(
testOptionsGroup,
widget.NewSeparator(),
@@ -92,12 +96,12 @@ func (ui *TestUI) buildUI() {
// 右侧面板:结果显示
rightPanel := resultArea
// 使用分割容器
// 使用分割容器 - 在移动设备上会自动调整为垂直布局
split := container.NewHSplit(
container.NewScroll(leftPanel),
rightPanel,
)
split.Offset = 0.35 // 左侧占35%
split.Offset = 0.4 // 左侧占40%,为移动设备优化
ui.window.SetContent(split)
}
@@ -239,15 +243,18 @@ func (ui *TestUI) createControlButtons() *fyne.Container {
ui.startButton = widget.NewButton("开始测试", ui.startTests)
ui.startButton.Importance = widget.HighImportance
ui.stopButton = widget.NewButton("停止测试", ui.stopTests)
ui.stopButton = widget.NewButton("停止", ui.stopTests)
ui.stopButton.Disable()
ui.clearButton = widget.NewButton("清空结果", ui.clearResults)
ui.clearButton = widget.NewButton("清空", ui.clearResults)
return container.NewGridWithColumns(3,
// 使用VBox布局以适应小屏幕
return container.NewVBox(
ui.startButton,
ui.stopButton,
ui.clearButton,
container.NewGridWithColumns(2,
ui.stopButton,
ui.clearButton,
),
)
}