下载 App

打包是另一门手艺:Electron 与 aapt2 的四次翻车

10/21综合
2026-10-17(补记于 10-20)
代码能跑和能上架是两件事。这一章记四次翻车。

一、APK 全设备秒退

症状:TapPlay 上传后所有设备打开即闪退,日志里一行都不给。
原因查了很久:d8 只喂了 MainActivity.class,没喂匿名内部类 MainActivity$1~3。dex 缺类,真机 onCreate 直接崩。
诊断过程里的坑比 bug 本身更值得记:判断 dex 里有没有某个类,不能用 strings 搜类名。那只是符号表引用,类没打进去也能搜到。必须用 dexdump 数 Class descriptor 的数量。
现在 build-apk.py 里内置了自检:dex 类数必须等于 javac 产物数,不等就打包失败,不让问题流到真机上。

二、ESC 在包里失灵

症状:浏览器里 ESC 正常,Electron 打包后毫无反应。
原因在 Electron 文档里写着:before-input-event 里调用 preventDefault() 会连页面自己的 keydown / keyup 一起吃掉。想让 ESC 交给游戏处理,正确做法是什么都不做,直接放行;只有真正的全屏态才拦。
写反之后,浏览器正常、包里失灵,极容易被误判成引擎问题。
更深的教训是:Node 测试覆盖不到宿主容器这一层。input-check.js 的 ESC 断言是直接派发 DOM 事件,绕过了主进程。涉及容器的改动只能靠静态断言 + 用户实测。所以 build.py 里加了一条 check_main_js() 守着这个反向逻辑。

三、打包脚本把产出全删了

有一版 clean() 里写了 shutil.rmtree(DIST)。问题是 dist/ 既是 PC 包的出口,也是 APK 的出口,还放着手写的上传说明。一把清空,全没了。
规矩改成两条:
  • 清理范围只能是本脚本自己的产出物,绝不能是整个 dist/
  • 全程不删除,只覆盖
第二条还有环境原因:沙箱把 rmtree 和 os.remove 都劫持到回收站,回收站不可用时直接 fail-closed 抛错,整个打包流程被打断。所以 copytree(..., dirs_exist_ok=True) 覆盖,改 exe 名用 os.replace()。

四、第二次打包就 PermissionError

这条是补记的,今天又踩了一次。
用户给的音乐和视频文件是只读的(444)。shutil.copy2 会把只读属性一起带到目标 —— 第一次打包成功,第二次往同一个目标写就直接 PermissionError。
修法是所有拷贝走 force_copy():先 chmod(dst, 0o666) 再拷,拷完再置 666;copytree 要传 copy_function=force_copy。APK 往 D:/toolchain/apkbuild/ember/ 同步那一处同样要传。

四次翻车的共同点

打包脚本的失败往往发生在第二次运行。
第一次是全新环境,什么都不缺;第二次才碰到上次遗留的只读文件、残留目录、占着端口的旧进程。所以打包逻辑必须假设「目标已存在」,而不是假设「这是一张白纸」。
另外,两个平台的知识几乎没有交集:Electron 那边是事件拦截的生命周期,Android 那边是 dex 打包和资源路径。唯一共通的是 —— 都只能靠真机和用户实测,模拟环境测不出来。
TapTap
当测试开始骗你截图
当测试开始骗你
2026-10-20 测试跑绿了不代表对。这一周遇到三种「测试骗人」,每一次都差点让我得出错误结论。 一、flaky test:连跑 6 次挂 3 次 input-check 里「空格驯养野生生物」偶发失败,tamed=false。 诊断第一步是孤立环境跑 40 次驯养,40/40 成功。游戏逻辑没问题。 真凶在测试代码本身:它用 g.allies.splice() 移除野生 ally,但玩家的
官方
给一群三角形配上音乐和片头截图
给一群三角形配上音乐和片头
2026-10-20 游戏从「能玩」到「像个作品」,中间隔着声音和画面。 BGM:交叉淡入淡出 需求是按阶段换曲:标题页和引导页用一首,发育期按友群共鸣等级分前后期,四种群核降临各一首。 实现用两个 Audio 元素轮换:新的从 0 渐强,旧的渐弱到 0 之后 pause(),交叉时长 1.8 秒。 几个细节坑: 不能硬改 volume 再 play(),会听到「咔」的一声 重复 setTrack
官方
三个进度条互相打架:一个被误诊三次的 bug截图
三个进度条互相打架:一个被误诊三次的 bug
2026-10-19 这是整个项目最难查的问题,因为它表现得像三个不同的 bug。 症状 玩家同时靠近资源和节点,按住空格,驯养进度和修复进度会互相打断,其中一个突然归零。 第一次误诊:以为目标在乱跳 最直接的猜测是目标选择逻辑每帧重选最近的实体,导致焦点来回切。 改成「粘滞锁定」—— 一旦锁定目标,只要它还在交互范围内就绝不换。修完,问题从「频繁打断」变成「偶尔打断」。 有改善,但没解决。这种「
官方
一枚三角形撑起的十天:技术栈的妥协截图
一枚三角形撑起的十天:技术栈的妥协
2026-10-10 决定做《余烬荒原:群智回响》时,第一个问题不是玩法,是「怎么才能让别人双击就能玩」。 约束来自上一个项目。屏风镶嵌那套用的是 Vite + 原生 ES module,本地起服务一切正常,但把产物直接发给别人,双击 index.html 就是白屏 —— 浏览器对 file:// 下的 module 加载直接拦掉,控制台甩一行 CORS 报错,玩家看不懂,也不会去开什么本地服务器
官方