Files
mtgodot-poc/docs/ANDROID-TESTING.md
shenleiandClaude Opus 5 fb4d2d222b docs: 文档审计——修正失效链接与过期结论
按 docs/ 目录逐篇核对,只改与事实/路径不符的部分,不动尚未验证的计划条目:

- `docs/steps/**` 在早前整理时已迁到 `docs/reference/steps/**`,全仓的旧路径
  引用(PLAN.md / README.md / M0-gr2-reader.md 及 libgr2 的头注释)一并改正。
- CLIENT-GAP.md / CLIENT-GAP-FIX.md / BACKLOG.md / MIDREVIEW.md:把已经落地的
  条目从「待办」改为已完成,删掉与代码现状矛盾的描述。
- ANDROID-TESTING.md / CLIENT-PORT.md / CLIENT-ROADMAP.md / GODOT-POC-PLAN.md /
  SHINSOO-WORLD-RENDERING.md / PARITY-GAP.md:同上,另补当前实际的构建/测试入口。
- THIRD-PARTY.md:补齐实际在用的第三方来源与许可说明。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJugvEJwz3FK4hw9ti3SRb
2026-09-08 17:15:17 +09:00

15 KiB
Raw Permalink Blame History

Android 真机测试指南

本文说明如何在 Android 真机上安装本客户端(APK 产物名仍是 mtgodot-poc.apk,包名 org.internal.mtgodotpoc)、生成并导入资源包、验证资源挂载,以及进行 40250 客户端测试。

1. 当前测试范围与已知前置条件

当前 Android 导出目标是 arm64-v8aAPK 包名为 org.internal.mtgodotpoc,最低 Android SDK 为 24。APK 只包含代码和 Godot 工程资源;Metin2 的 assets/bgm/ 不打进 APK,测试时必须单独导入 assets.zip

当前仓库的资源部署存在一个需要特别注意的限制:

  • export-android.sh --install 会把资源推到 /sdcard/Android/data/org.internal.mtgodotpoc/files/assets.zip
  • project/asset_pack.gd 的候选顺序是 MT_ASSETS_ZIP 环境变量 → user://assets.zipOS.get_user_data_dir()/assets.zip → 可执行文件目录 → res://../assets.zip(见 _find_local_zip());上述外部目录不在候选路径里。
  • 因此,Debug 真机测试应把外部目录中的压缩包再复制到应用私有 files/ 目录,确保客户端的 user://assets.zip 能命中。

另外,40250 classic 网络栈当前由进程环境变量 MT_PROTOCOL=classic 选择。Android 通过 Activity 启动 APK 时不能直接继承 Mac 终端的环境变量;如果 APK 尚未增加 Android 侧的协议配置入口或将 classic 设为移动端默认值,则只能完成 APK、资源和 UI 验证,不能据此宣称已经完成真实 40250 登录验收。

公会功能按当前项目范围暂缓;龙魂玩法不属于目标 40250 服务器功能,不纳入 Android 验收。

2. 主机环境

以下版本来自当前 Android Gradle 配置和构建脚本:

项目 要求
主机 macOSApple Silicon 构建脚本已按当前机器验证
Godot 4.7.1.stable,并安装对应 Android 导出模板
Android SDK compile/target SDK 36Build Tools 36.1.0
Android NDK 29.0.14206865
Java Gradle 配置最低 Java 17;当前脚本默认使用 OpenJDK 21
Android 手机 arm64-v8a,建议使用 Vulkan 设备
磁盘 至少预留 APK、资源包和临时构建空间;当前 assets.zip 约 2.12.2 GB

进入仓库并设置环境变量。路径按本机安装位置调整:

cd /Users/shenlei/Work/mt/metin2-client

export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"
export ANDROID_HOME="$ANDROID_SDK_ROOT"
export ANDROID_NDK_ROOT="$ANDROID_SDK_ROOT/ndk/29.0.14206865"
export JAVA_HOME="/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home"
export GODOT="/opt/homebrew/bin/godot"
export ADB="$ANDROID_SDK_ROOT/platform-tools/adb"

先确认工具存在:

"$GODOT" --version
java -version
"$ADB" version
test -f "$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake"

如果 Android SDK/NDK 尚未安装,可在 Android Studio 的 SDK Manager 中安装,或使用 sdkmanager 安装与上表一致的版本。不要只安装一个较旧 NDK 后直接构建;Gradle 模板要求的 NDK 版本以 project/android/build/config.gradle 为准。

Godot 还需要安装与 4.7.1 完全匹配的 Android 导出模板。可在 Godot 的“编辑器设置 → 导出 → 导出模板”中安装。

首次导出前生成 Debug keystore

./gen-debug-keystore.sh

3. 连接 Android 真机

在手机上完成以下设置:

  1. 设置 → 关于手机 → 连续点击版本号,开启开发者选项。
  2. 开发者选项中开启“USB 调试”。
  3. USB 连接模式选择“文件传输/MTP”。
  4. 首次连接时,在手机上确认“允许 USB 调试”。

在 Mac 上检查设备:

"$ADB" kill-server
"$ADB" start-server
"$ADB" devices -l

期望看到:

<设备序列号>    device

状态为 unauthorized 时,解锁手机并接受 RSA 授权;没有设备时,优先检查 USB 线、USB 模式、开发者选项和手机是否允许该电脑调试。

4. 生成资源包

资源包必须从与 APK 同一份工作树生成。执行:

./pack-assets.sh

该脚本会:

  1. 执行 bake_asset_index.gd,生成 assets/asset_index.txt
  2. assets/bgm/ 打成 build/export/assets.zip
  3. 使用 zip -0 原样存储,不压缩 .dds.gr2 等大型资源。
  4. 排除 .git.DS_Storeassets/.gdignore

检查资源包:

ls -lh build/export/assets.zip
unzip -l build/export/assets.zip | rg 'assets/asset_index\.txt|assets/|bgm/' | head -n 20

不要手工解压到 APK,也不要把完整 assets/ 强行放进 res://。客户端启动时通过 ProjectSettings.load_resource_pack() 挂载 zip,挂载成功后资源以 res://assets/...res://bgm/... 访问。

资源发生变化后必须重新执行 ./pack-assets.sh。只重新导出 APK 不会更新已经生成的 assets.zip

5. 构建 APK

建议先单独构建,不要在第一次测试时直接使用 --install

./export-android.sh Debug

构建成功后应得到:

build/export/mtgodot-poc.apk

检查 APK 和 native library

ls -lh build/export/mtgodot-poc.apk
unzip -l build/export/mtgodot-poc.apk | rg 'lib/arm64-v8a/.*\.so'

应至少包含 lib/arm64-v8a/ 下的 Godot Android 库和 libmtgodot 扩展库。

6. 安装 APK 并导入资源

6.1 安装 APK

"$ADB" install -r build/export/mtgodot-poc.apk

-r 会保留应用数据。若要完全清理测试数据,可选执行:

"$ADB" shell pm clear org.internal.mtgodotpoc

清理后必须重新导入资源包。

6.2 先推送到 Android 外部目录

PKG=org.internal.mtgodotpoc
EXT_DIR="/sdcard/Android/data/$PKG/files"

"$ADB" shell mkdir -p "$EXT_DIR"
"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip"
"$ADB" shell ls -lh "$EXT_DIR/assets.zip"

6.3 Debug 测试复制到 Godot user://

当前 Debug APK 可使用 run-as 把外部文件复制到应用私有 files/ 目录:

"$ADB" shell run-as "$PKG" sh -c \
  "cp '$EXT_DIR/assets.zip' files/assets.zip"

"$ADB" shell run-as "$PKG" ls -lh files/assets.zip

最后一条命令能看到约 2.1–2.2 GB 的文件,才继续启动客户端。这个步骤是当前代码路径下的关键步骤;只执行 adb push/sdcard/Android/data/.../files/,不能替代它。

如果 run-as 报告应用不可调试,确认安装的是 Debug APK,而不是 Release APK。Release 流程需要先修改资源查找/部署实现,使客户端明确支持外部目录,不能假设 run-as 可用。

6.4 资源更新

客户端退出后,只更新资源包时执行:

./pack-assets.sh

"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip"
"$ADB" shell run-as "$PKG" sh -c \
  "cp '$EXT_DIR/assets.zip' files/assets.zip"

资源挂载只在 client_main.gd::_ready() 中执行,因此更新后必须重启客户端,不能只切回前台:

"$ADB" shell am force-stop "$PKG"

7. 启动客户端并确认资源挂载

清空旧日志后启动:

"$ADB" logcat -c
"$ADB" shell am start -n \
  org.internal.mtgodotpoc/com.godot.game.GodotApp

实时查看日志:

"$ADB" logcat -v time -s godot GodotError AndroidRuntime

资源挂载成功的关键日志是:

[AssetPack] mounted .../assets.zip

以下日志表示资源没有被找到或挂载失败:

[AssetPack] 找不到 assets.zip
[AssetPack] load_resource_pack 失败
[client] 资源目录不存在

启动验收至少包含:

  • 登录界面正常出现,而不是黑屏或立即退出。
  • 登录背景、控件和字体资源正常显示。
  • 选人页能加载职业模型、背景和界面资源。
  • 进入游戏后能看到地图、地形、建筑、树木或角色模型。
  • 日志中没有持续出现资源文件缺失、FileAccess 打开失败或 native library 加载失败。

可保存截图作为测试证据:

mkdir -p build/export/android-evidence
"$ADB" exec-out screencap -p > build/export/android-evidence/launch.png

8. 40250 服务器连接配置

8.1 手机网络要求

手机必须能直接访问认证服/游戏服的 IP 和端口:

  • 手机与局域网测试服连接到同一网络,或服务器开放公网访问。
  • 客户端不能使用 127.0.0.1localhost 指向 Mac;在手机上它们指向手机自身。
  • 防火墙和 FreeBSD jail 的端口映射必须允许手机来源地址访问。
  • 服务器端口以实际 CONFIG 为准,不要照抄示例端口。

8.2 serverlist.txt

客户端启动时会优先读取 res://serverlist.txt;没有该文件时使用 project/net/serverinfo.gd 中的内置默认值。真实 40250 测试应在导出前准备 project/serverlist.txt,格式为 TSV

# 名称\t认证地址\t认证端口\t游戏地址\t游戏端口\t频道列表\t端口步长\t会徽端口
龙魂40250\t<服务器IP>\t<auth-port>\t<服务器IP>\t<channel1-port>\t1,2,3,4\t1\t0

例如 40250 仓库脚本中的默认 channel1 端口与当前客户端内置默认值并不相同,必须以目标 FreeBSD 服务器的 CONFIG 和实际监听结果为准。

8.3 classic 协议选择限制

当前 native 代码仅在进程环境变量满足以下条件时切换 40250 classic 后端:

MT_PROTOCOL=classic

在 Mac 上运行 Godot 时可以通过环境变量设置;但 Android APK 是由 Activity 启动的,普通的 adb shell am start 不会把 Mac 的环境变量传入 APK。因此,真实 Android 40250 登录测试前必须确认以下任一项已经完成:

  1. Android 版本把 classic 设置为默认网络后端;
  2. 客户端增加可持久化的协议配置并在 Android 导出中设为 classic;或
  3. Android 测试包提供协议选择入口。

不要把下面的命令当作可靠解决方案:

adb shell MT_PROTOCOL=classic am start ...

它设置的是 am 命令进程的环境,不等于给已启动的 Android Activity 设置环境变量。

9. 真机功能验收清单

以下项目按实际 40250 测试账号、角色和 NPC 条件逐项记录:

启动与网络

  • APK 安装成功,包名为 org.internal.mtgodotpoc
  • assets.zip 已复制到应用私有 files/,大小与主机一致。
  • 日志出现 [AssetPack] mounted
  • 登录界面资源完整显示。
  • 服务器/频道检测能得到预期结果。
  • 认证成功后进入选人页。
  • 选择角色后进入游戏场景。

世界与基础操作

  • 地图、地形、建筑、树木、角色和纹理正常加载。
  • 点击地面移动,角色位置与服务器同步。
  • 普通攻击、目标选择、技能和动作没有异常断线。
  • 聊天发送与接收正常。
  • 切换前后台后连接和场景状态符合预期;断线时能看到重连提示。

已接入的常用功能

  • 背包打开、物品使用、丢弃、移动和快捷栏操作。
  • NPC 对话、脚本选项、输入框和确认框。
  • 普通商店查看、切换货架和购买。
  • 私人商店物品选择、定价、开设和撤收。
  • 交易发起、物品/金币添加、确认和取消。
  • 仓库密码、存入、取出和物品移动。
  • 商城物品列表和取出。
  • 组队邀请、接受、离队、成员状态和治疗入口。
  • ESC 系统菜单、音量、镜头、雾效和显示设置持久化。

明确不纳入本轮

  • 公会相关功能:按当前范围暂缓。
  • 龙魂:目标 40250 服务器没有该功能,不进行功能验收。
  • 真实 FreeBSD + MySQL 全流程验收:需要服务器环境和测试账号,不能用本机离线测试结果替代。

10. 测试证据保存

建议每次测试保留 APK、资源包校验值、设备信息和日志:

mkdir -p build/export/android-evidence

shasum -a 256 build/export/mtgodot-poc.apk \
  build/export/assets.zip \
  > build/export/android-evidence/artifacts.sha256

"$ADB" shell getprop ro.product.model \
  > build/export/android-evidence/device-model.txt
"$ADB" shell getprop ro.build.version.release \
  > build/export/android-evidence/android-version.txt
"$ADB" logcat -d -v time -s godot GodotError AndroidRuntime \
  > build/export/android-evidence/logcat.txt

测试记录至少填写:构建时间、Git commit、APK SHA-256、assets.zip SHA-256、手机型号、Android 版本、服务器地址/端口、账号、测试结果和失败日志。

11. 常见问题

现象 处理
adb devices 没有设备 开启 USB 调试、接受 RSA、切换 MTP、检查数据线;必要时重新执行 adb kill-server / adb start-server
状态是 unauthorized 解锁手机并接受“允许 USB 调试”,然后重新执行 adb devices
APK 安装失败 检查设备是否为 arm64;卸载旧包后再安装;查看 adb install 的具体错误
run-as 报不可调试 安装 Debug APKRelease APK 不能依赖 run-as 导入资源
日志找不到 assets.zip 确认外部 push 成功,再执行 run-as ... cp ... files/assets.zip,然后重启应用
load_resource_pack 失败 检查压缩包完整性、磁盘空间、是否由 ./pack-assets.sh 生成,以及 zip 内是否存在 assets/asset_index.txt
登录连接超时 手机不能使用 localhost;检查服务器 IP、端口、Wi-Fi/VPN、防火墙和 FreeBSD jail 映射
登录协议不对或立即断线 确认 Android 包实际选择了 classic,仅在 Mac 终端设置 MT_PROTOCOL 不会自动传入 APK
黑屏或 Vulkan 崩溃 保存完整 logcat;当前 Android 移动 Vulkan 的 shader/GPU-skin 真机验证仍需在目标设备上进行
更新资源后画面不变 资源包挂载发生在启动阶段,执行 am force-stop 后重新启动;必要时清理应用数据并重新导入

12. 推荐的最短测试流程

首次测试按以下顺序执行:

cd /Users/shenlei/Work/mt/metin2-client

./pack-assets.sh
./export-android.sh Debug

export ADB="${ANDROID_SDK_ROOT:-$HOME/Library/Android/sdk}/platform-tools/adb"
PKG=org.internal.mtgodotpoc
EXT_DIR="/sdcard/Android/data/$PKG/files"

"$ADB" install -r build/export/mtgodot-poc.apk
"$ADB" shell mkdir -p "$EXT_DIR"
"$ADB" push build/export/assets.zip "$EXT_DIR/assets.zip"
"$ADB" shell run-as "$PKG" sh -c \
  "cp '$EXT_DIR/assets.zip' files/assets.zip"
"$ADB" shell run-as "$PKG" ls -lh files/assets.zip

"$ADB" logcat -c
"$ADB" shell am start -n "$PKG/com.godot.game.GodotApp"
"$ADB" logcat -v time -s godot GodotError AndroidRuntime

只有在看到 [AssetPack] mounted、登录界面资源正常、并确认 Android 包使用正确的 40250 classic 后端后,才进入真实服务器功能验收。