【CJMP Grok Bot实践】用 CJMP 搬游戏时碰到的三个缺口,和我们的绕法

一、这篇讲什么

如果你要把一款用仓颉(一门编程语言)写成、用 Canvas(画布接口,用代码一笔一笔画图形)画界面的鸿蒙应用搬到 iOS 和 Android,并打算用 CJMP(文档里称为跨平台开发框架),这篇讲我们撞上的三个缺口:Canvas 画不了,字体拿不到,@r(引用图片资源的写法)不认识。三个缺口性质不同------能力没做、做了没开、编不过;各自怎么变通、哪些只在 0.2.2 上验证过,也许可以当作你动手前的检查清单。

范围:OpenSDK(CJMP 的开发包)0.2.2 公开版,只在模拟器上跑,没有真机;三个缺口都变通过去了,变通已在 10 月 2 日合进主线(我们自己仓库的主分支)。

二、Canvas 画不了

2.1 现象

鸿蒙版用 Canvas 和 Path2D 画棋盘(代码里 CanvasRenderingContext2D 出现 4 处,Path2D(画路径的接口)出现 11 处),这 4 处和 11 处迁过来都要换一种画法。在 iOS/Android 上,0.2.2 的 SDK 里没有 Canvas、CanvasRenderingContext2D、Path2D。

冒烟测试(先跑一遍最基本的流程,看有没有明显出错;我们给几次小测试按字母编了号)B 的提示词原文是「Keels 0.2.2 SDK has NO Canvas / CanvasRenderingContext2D / Path2D component」。负责查资料、做对比的那个 Grok Bot 在报告里还记了一条实测:团队里负责写代码的那个 Grok Bot 发现,0.2.2 的 cjui 里没有这三个。

2.2 原因:构建配置里就没编进去

更像是没编进去,不是 bug。

这一条要拆开看,一共是三处,分属两个仓库、三个文件:

  • 引擎仓库 cj_frontend 目录下的 BUILD.gn(构建配置文件):canvas 那一行(cj_canvas_ffi.cpp)被注释掉,0.2.2 对应的引擎分支、v0.7.0 和 CJMP 主分支上都是这样;

  • CJFrontend 里的 component.cj(仓颉源文件):path_2d 和 canvas 的导出被注释;

  • CJFrontend 里与 component.cj 同目录的 BUILD.gn:canvas 和 path_2d 那两行也是注释。

CJFrontend 的这几行,在 0.2.2 配套提交和 2026 年 9 月 14 日的最新提交上都仍是注释。

查资料的 Grok Bot 还有一条推断,原话是:「即使前端导出了,引擎这边没有 FfiOHOSAceFrameworkCanvasCreate 的实现,也跑不起来。这是我根据构建配置做的推断,没有链接实测。」

所以这条我想说准确一点:依据是源码里的构建配置,不是一次编译失败的日志。范围是 OpenSDK 0.2.2 和 CJMP 主分支 v0.7.0 的 Android/iOS 引擎构建,给鸿蒙用的构建里 Canvas 是启用的。

运行日志里出现过与 Canvas 相关的 ERROR,但搭基座(应用的基础部分:关卡数据、字体、图片和页面导航)的那批改动在说明里写,应用代码里已经没有 Canvas、这看起来是引擎内部的日志,所以我们不把它当证据。

2.3 做法:改成形状组件

改用 Rect、Line、Circle、Path、Text 这些形状组件,加 onTouch。

冒烟测试 C 在 9 月 27 日用它画出了 6×6 的范阳棋盘,各类组件的数量见图 2(数字取自写代码的 Grok Bot 当时记的工作量记录)。触摸注入后,两个平台的模拟器上都能通关棋盘(这是它自测的,不是正式测试)。帧率和内存我们没有单独测。

图 2|形状组件棋盘(冒烟测试 C,模拟器画面)

三、字体拿不到

3.1 现象

写代码的 Grok Bot 的原话:0.2.2 没有仓颉层的 registerFont。fontFamily("serif") 在两个平台上都会回落成无衬线。

对《驿路巡点》这种带朱印、驿站题字的古代题材游戏,衬线体(笔画末端带装饰的字体,如宋体)可能不只是审美问题:字体一变,朱印和题字的古风就对不上了。无衬线体指笔画粗细均匀的字体,如黑体。

3.2 原因:源码里其实有,但用不到

registerFont 在 0.2.2 的配套提交里有,但应用层拿不到 Font 实例(链路见下图):UIContext 的 getFont() 被注释掉了。

图 3|字体接口的两条路径

3.3 做法:私有 FFI

做法是用私有 FFI(外部函数接口,这里指调用引擎内部导出、没有公开的函数):通过 dlopen/dlsym(运行时按名字找函数)调用,加载结果见上图。升级 CJMP 前,我们会先查 dlopen/dlsym 这条路径:符号还在不在,签名变没变。

这条我想直说:它不是公开 API,项目里的代码注释写的也是「FfiFontManagerRegisterFont is a private engine FFI symbol (workaround, Smoke D)」。

基座最后的做法是随包带 YiluSans 的 400 和 500 字重、YiluSerif 的 Regular 和 Bold,并做字形检查(逐个核对字体文件里有没有游戏要用的字):当时的 346 个必需字符,0 个缺失。

这个"0 个缺失"只对当时那份必需清单成立。10 月 3 日,我们用字体文件的字表核对了变通合进主线前后的两个版本:合并前,随包字体里没有「负」,无衬线字体有 346 个码位(字体收录的字符个数)、衬线字体有 357 个;合并之后,主线补进了「负」(这一处是 10 月 1 日的一次提交补的,随那次合并进入主线),码位数变成 359 和 369。「桥」「断」「去」在两个版本的两套字体里都没有,当前皮肤文案也用不到。

团队里负责设计的那个 Grok Bot 当时核对的是更早的一版代码,它看到衬线缺「负」,与合并前的那一版相符,和主线现状并不冲突。

四、@r 不认识

4.1 现象

冒烟测试 E 的编译输出原文:

81:error: undeclared identifier 'r' 88:error: undeclared identifier 'r' 2 errors generated

写代码的 Grok Bot 的结论是:在 0.2.2 内置的 cjc 1.1.0 上,@r 编译不过,连模板自带的 startIcon 也不行;项目其余部分用的是 1.1.3,是否与编译器版本有关,我们没有验证。

4.2 做法:改走 rawfile 路径

改用 Image("resource://RAWFILE/<文件>"),验证项见下图。

图 4|@r 与 rawfile 路径对照

后续版本方面:0.6.2 的 release note 写修了本地图片资源解析失败,0.7.0 新增 lib/resources 三端自动同步。

五、三个缺口放在一起看,和变通之后

三个缺口的性质不一样,见开头的一图流。

如果要排个先后,我觉得"做了没开"最可惜:代码就在源码里,只差一行没注释;"能力没做"影响最大,它决定了棋盘要怎么重画;"编不过"最没把握:为什么编不过还没弄清,只能先绕开。

三个缺口的变通多少都没有走公开 API 的常规路径:形状组件棋盘要 106 个组件(冒烟测试 C 里 6×6 范阳那一盘),字体靠引擎内部的私有符号,图片改走 rawfile 路径。这些做法在 0.2.2 的模拟器上跑通了;私有符号和 @r 换到别的版本上是否还成立,我们没有验证。它们是不是"正确"的用法,我们不下结论------能力缺口摆在那儿,不绕,棋盘就没法照原样画出来。

下篇讲变通之后发生的事:94 关通关、6 关卡死,最后的根因出在我们自己的数据转换脚本和引擎规则上,不在 CJMP 这一侧------而那 6 关现在在求解器层面也通了。

这几处变通未必最顺手,你有更好的办法,欢迎在评论区讨论。

相关推荐
用户abcde1 小时前
RAG 检索增强生成
人工智能
文谦南宁AI普工1 小时前
RAG 检索全对,回答全错?用位置扫描 10 分钟定位 Lost in the Middle
人工智能·aigc
alonglong1 小时前
183 行 llmctl:把 4 个启动脚本收成一个 CLI,总控该管什么、不该管什么
人工智能
野生码农AI实战1 小时前
一句追问查出停滞 50 天的口径烂账,我把团队规则的锚换到了数字团队花名册
人工智能
宇擎智脑科技1 小时前
Sirchmunk 深度解析(一):一个无需向量数据库的自进化搜索引擎架构设计
人工智能·rag·sirchmunk
小魚8841 小时前
豆包工作的核心能力有哪些
人工智能
用户287043906161 小时前
给一个终端编码代理装上一颗确定性情绪内核:Persisto Mate 的实现记录
人工智能
用户202252215061 小时前
实现变便宜了,品味才是稀缺:一个 AI 产品经理的 Vibe Coding 复盘
人工智能
雪雪爱冲浪1 小时前
AI 智能体如何通过 auth.md 注册 Bright Date:完整实操指南
大数据·人工智能