cocos2d-x 在 Windows 上打包 iOS 并真机调试 C++
这篇讲在 Windows 上把 cocos2d-x 游戏编译成 iOS 版,装到 iPhone 上断点调试 C++ 代码,最后打出上架用的 ipa。3.x 和 4.x 都适用,引擎源码作为子工程一起编译,不用改引擎。你需要 Apple 开发者账号、一台 iPhone 和数据线,并且已经安装 KXBuild。
3.x 和 4.x 的区别
两个大版本的 iOS 工程放在不同位置,后面的命令按版本二选一。
| 引擎版本 | iOS 工程 | 应用 target |
|---|---|---|
| 3.x | proj.ios_mac\MyGame.xcodeproj,新建工程时就有 |
MyGame-mobile |
| 4.x | build-xcode\MyGame.xcodeproj,体检时生成 |
MyGame |
3.x 的工程里还有一个 MyGame-desktop,是 macOS 版,iOS 只用 MyGame-mobile。4.x 官方只提供 CMakeLists.txt,Xcode 工程要由 CMake 生成,这一步在体检时完成。
安装引擎并新建工程
已有工程在 VS Code 中「文件 → 打开文件夹」打开工程根目录,或者把工程目录拖进 VS Code 即可,跳到下一节。没有现成工程的,按下面的步骤新建。
从 cocos2d-x 官网下载引擎压缩包并解压,在引擎目录运行 setup.py 配好 cocos 命令。3.x 和 4.0 的 setup.py 与 cocos 命令都需要 Python 2.7。
1cd D:\cocos2d-x-4.0
2python setup.py
setup.py 会写入环境变量,运行完关掉终端重新打开,再新建工程。
1cd D:\work
2cocos new MyGame -l cpp -p com.example.mygame -d .
-p 是包名,填你在开发者后台注册的 Bundle ID。Lua 工程把 -l cpp 换成 -l lua。工程目录放在 D:\work 这类短路径下,引擎目录层级很深,放得太深在 Windows 上容易遇到路径过长的错误。
打开工程并体检
在 VS Code 中「文件 → 打开文件夹」打开工程根目录 D:\work\MyGame。
**第一次打开工程必须先体检。**它会检查 cocos2d-x 环境,并准备好 iOS 端的工程。4.x 的 Xcode 工程也在这一步生成,放在 build-xcode 目录。以下两种做法任选其一。
- VS Code 插件。在 KXBuild 视图标题栏「···」中运行「体检并修复开发环境」。
- 命令行。执行下面的命令。
1kxbuild doctor D:\work\MyGame
体检完成后 KXBuild 视图会列出 MyGame 工程和它的 target。引擎自带的工程也可能一起列出来,在 MyGame 工程节点上点击,把它设为启动项目。
C++ 代码在 VS Code 中有补全、跳转和错误提示,用法见代码提示与索引。Lua、JS 脚本装上 VS Code 对应的插件即可。
装到 iPhone 上运行
证书目录里要有 Apple Development 证书和包含这部 iPhone UDID 的 Development 描述文件,获取和放置方法见证书与签名。
用数据线连上 iPhone,解锁后点「信任此电脑」,并在「设置 → 隐私与安全性 → 开发者模式」中打开开发者模式,手机会重启一次。驱动和手机设置见设备准备。
确认 KXBuild 视图「构建配置」节点是 Debug,选中这台 iPhone,按 F5。KXBuild 会依次构建、签名、安装、启动游戏并附加调试器。3.x 工程弹出 target 选择时选 MyGame-mobile。
第一次构建要把整个引擎编译一遍,时间比较长,之后只编译改动的文件。第一次调试某个 iOS 版本时还会自动下载对应的符号库,有几个 GB,只需一次。
游戏里 log() 和 CCLOG 的输出显示在 VS Code「输出」面板的 KXBuild Console 通道,构建日志在 KXBuild 通道。输出面板用 Ctrl+Shift+U 打开,右上角下拉框切换。
断点调试 C++
在 Classes\HelloWorldScene.cpp 的 HelloWorld::init 里点行号左侧加一个断点,按 F5,游戏启动后会停在这一行。左侧「变量」面板能展开 this 和局部变量,「调用栈」面板能一直看到引擎的调用链。引擎源码和游戏代码一起编译,单步可以进到引擎函数里。
游戏代码有几处调试时常用的做法。
- 每帧调用的函数。
update(float dt)这类函数加普通断点会一直停,右键「添加条件断点」写一个条件,例如_score > 100,或者用「添加日志点」只打印值不停下。 - C++ 异常。调试时在「断点」面板勾选 C++ Throw,异常一抛出就停在抛出的那一行。
- 崩溃。
EXC_BAD_ACCESS多是访问了已经 release 的节点。用 Debug 配置复现一次,调试器会停在崩溃处,顺着调用栈往上找是哪里持有了野指针。
Lua、JS 脚本用引擎自带的调试方式,和 C++ 断点互不影响。断点、LLDB 命令、崩溃报告的完整用法见在 Windows 上真机调试 iPhone App。
改了资源或代码之后
改了 C++ 代码,直接按 F5,KXBuild 只重新编译改动的文件。
改了 Resources 目录里的图片、音效、配置,3.x 和 4.x 的处理不同。
| 引擎版本 | 修改已有文件 | 新增或删除文件 |
|---|---|---|
| 3.x | 按 F5 | 按 F5 |
| 4.x | 按 F5 | 先运行一次体检,再按 F5 |
4.x 的资源和源文件清单在生成 Xcode 工程时写进 build-xcode。新加的图片、新建的 .cpp 文件,都要重新体检一次,build-xcode 才会包含它们,否则运行时会报找不到资源,或者链接时报找不到符号。新建 .cpp 和 .h 时,先把它们加进 CMakeLists.txt 的 GAME_SOURCE、GAME_HEADER 列表,再体检。
build-xcode 每次体检都会重新生成,不要在里面手动改工程设置。要长期保留的设置写进 CMakeLists.txt。
在真机上看帧率和 CPU
游戏左下角的 FPS 统计来自引擎自己,看整机负载和掉帧用 kxdevice 采样。测之前换成 Release 包,Debug 包没有优化,数据偏低。
1kxdevice instruments sysmon -i 1
sysmon 每秒输出一次整机 CPU 占用。掉帧用 fluidity、内存增长用 allocations、热点函数用 stackshot,用法见性能分析。cocos2d-x 游戏常见的耗时点是每帧新建节点、大图没打进图集导致 draw call 过多,以及在 update 里做文件读写。
打出 Release ipa
上架前证书目录里要有 Apple Distribution 证书和 App Store 类型的描述文件。游戏图标和启动图在 proj.ios_mac\ios 目录里,3.x 和 4.x 都是这个位置,图标可以用资源目录编辑器修改。以下两种做法任选其一。
- VS Code 插件。在 KXBuild 视图的「构建配置」节点切到 Release,命令面板运行
KXBuild: 构建。 - 命令行。在工程根目录按引擎版本执行其中一条。
3.x 工程执行下面这条。
1kxbuild build .\proj.ios_mac\MyGame.xcodeproj -c Release -t MyGame-mobile
4.x 工程执行下面这条。
1kxbuild build .\build-xcode\MyGame.xcodeproj -c Release -t MyGame
工程的 Release 配置没有指定发布证书时,命令行加 -D CODE_SIGN_IDENTITY="Apple Distribution" 临时覆盖。每次上传 App Store Connect,构建号都要比上一次大,命令行可以加 -D CURRENT_PROJECT_VERSION=2 指定。
构建完成后 .xcodeproj 所在目录的 build 文件夹下会生成 .ipa。上传 App Store Connect、TestFlight 测试和提交审核见发布与上架,完整流程见在 Windows 上上架 App Store。
常见问题
cocos 命令或 setup.py 报 SyntaxError。 用的是 Python 3。装 Python 2.7,用它重新运行 setup.py。
KXBuild 视图里没有 4.x 的工程。 build-xcode 还没生成,运行一次体检。
命令行报 target not found。 3.x 的应用 target 是 MyGame-mobile,4.x 是 MyGame。
报文件名过长或找不到文件。 把工程移到 D:\work\MyGame 这类短路径,重新体检。
4.x 游戏运行时找不到新加的图片。 加完资源后要重新体检,见上一节。
断点不停,或者只能看到汇编。 确认构建配置是 Debug,并等第一次调试时的符号库下载完成。
签名或安装时报错。 按提示对照iOS 签名报错与 ipa 安装失败的解决办法处理。
装上后一启动就退出。 用 Debug 配置按 F5 复现,看调试器停在哪一行。设备日志和崩溃报告见排错与 FAQ。