SEO 信息
- SEO 标题:动图魔方技术拆解 19:HarmonyOS SDK 配置修正与 Hvigor 构建排查
- SEO 摘要 :基于 HarmonyOS NEXT / ArkTS 项目"动图魔方",本文拆解一次真实的构建配置收口:为什么
build-profile.json5里的targetSdkVersion、compatibleSdkVersion不能把 API 编号和 SDK 版本串混写,怎样用 Hvigor 命令复现构建结果,如何把签名材料、strictMode、模块列表和 3D 能力边界拆成可验收的排查清单。 - 关键词:HarmonyOS, harmonyOS, ArkTS, Hvigor, build-profile.json5, SDK 配置, targetSdkVersion, compatibleSdkVersion, 构建排查
- 文章封面 :
doc/csdn-series/covers/cover-19-hvigor-sdk-build-check.jpg - 投稿方向:普通技术拆解文
- 项目环境 :HarmonyOS SDK
6.1.0(23)、ArkTS、DevEco Studio、GIFRubiksCube - 验证时间:2026-06-27 16:30 +08:00
- 验证对象 :
build-profile.json5、entry/src/main/ets/products/main/Index.ets、HvigorassembleHap输出、doc/screenshots_current/*.jpeg
第 18 篇把 3D 能力边界讲清楚之后,工程上马上会遇到另一个问题:能力路线写得再稳,如果本地构建配置不稳定,3D 入口、GIF 导出、主题和作品页验收都无法进入发布链路。第 19 篇只处理一件事:把 HarmonyOS SDK 版本串、Hvigor 构建命令、签名材料和警告分类拆成一套能复现、能排查、能交付的工程规则。
一、真实工程问题背景
这次不是"写一篇构建教程",而是项目里真的出现过一组容易互相影响的问题。为什么要单独写第 19 篇?因为动图魔方已经从普通 GIF 工具扩展到了素材导入、真实图片序列、3D 预览、服务卡片、深浅色主题和 CSDN 系列发布。功能越来越多以后,构建配置就不再是 DevEco Studio 自动生成的背景文件,而是发布链路的一部分。
- SDK 版本串容易写错 。项目讨论 3DGS 和 API 26 时,很容易把能力目标、设备 API 和当前构建 SDK 混成一句"切到 API 26"。但
build-profile.json5实际需要的是当前工程可识别的 SDK 版本格式,例如6.1.0(23)。 - 构建命令必须可复制。如果只说"IDE 能跑",下一台机器、下一次自动化、下一篇 CSDN 文章都无法复验。本文使用的命令是 Hvigor CLI,不依赖编辑器当前页面。
- 签名材料不能被文章泄漏 。
build-profile.json5里真实存在 p12、p7b、证书路径和加密后的密码字段,文章只能展示结构和脱敏值,不能把完整材料当作代码块贴出去。 - 警告和错误要分级 。构建输出里有些任务是
UP-TO-DATE,有些是Finished,真正要盯的是BUILD SUCCESSFUL或失败码。不能把所有黄色输出都当成阻塞,也不能把签名异常当成普通提示跳过。 - 功能验收依赖构建边界 。第 18 篇的
CapabilityService已经把设备能力和构建能力分开;如果当前构建仍是6.1.0(23),文章和产品说明就不能宣称真实 3DGS 执行体已经落地。
这类问题的风险很现实:用户看到的是一个能导出 GIF 的工具,测试看到的是一个需要稳定构建和安装的 HAP,文章读者看到的是一条技术路线。如果三者的版本口径不一致,后续每一篇文章都会被"到底按哪个 SDK 验收"拖住。
二、目标与边界
本文的目标不是升级 SDK,也不是演示所有 Hvigor 参数,而是把当前项目已经可用的构建口径固定下来。
| 目标 | 本文处理方式 | 为什么这么定 |
|---|---|---|
| SDK 版本串 | 以 build-profile.json5 当前值为准 |
避免把 API 26 能力规划写成当前构建事实 |
| Hvigor 命令 | 使用 assembleHap --mode module -p product=default --no-daemon |
自动化和人工终端都能复现 |
| 签名配置 | 只展示脱敏结构 | 保护证书路径、密码和 profile 材料 |
| 构建结果 | 记录真实输出摘要 | 支撑文章不是空泛经验 |
| 3D 能力 | 继续承认当前包的边界 | 和第 18 篇能力路由保持一致 |
| 发布清单 | 写入 CSDN 系列本地记录 | 让第 20 篇收官能继承这次证据 |
边界也要说清楚:本文不替换证书、不重建 AGC profile、不改变包名,不修改 EntryAbility.ets 或页面业务逻辑。当前仓库还有用户已有的大量工程改动,本文只围绕构建配置、命令复现和发布文档展开。
三、源码对象与证据链
这篇文章的主对象是 build-profile.json5,但构建排查不能只盯一个文件。一个 HarmonyOS 工具 App 能否发布,至少要把工程级配置、入口页面、功能截图、构建命令和发布记录串起来。
| 证据类型 | 文件或命令 | 本文使用方式 |
|---|---|---|
| 工程级构建配置 | build-profile.json5 |
说明 SDK、签名、模块和 strictMode |
| 主页面入口 | entry/src/main/ets/products/main/Index.ets |
验证当前构建对象不是空壳页面 |
| 3D 能力层 | entry/src/main/ets/features/threeD/services/CapabilityService.ets |
承接第 18 篇能力边界 |
| GIF 导出层 | entry/src/main/ets/features/gif/services/ExportService.ets |
确认核心业务仍进入构建 |
| 发布规划 | doc/csdn-series/20篇系列规划.md |
保持第 19 篇编号、标题和封面一致 |
| 发布记录 | doc/csdn-series/publish-record.json |
发布成功后记录 articleId、封面和状态 |
| 首页截图 | https://i-blog.csdnimg.cn/direct/efeec2074b0247fe8b4629b27a1a90aa.jpeg |
验收构建对象对应真实 App |
| 编辑页截图 | https://i-blog.csdnimg.cn/direct/11214b59c5d0419cb03f0357f69ac06e.jpeg |
验收 GIF 工具主链路 |
| 3D 截图 | https://i-blog.csdnimg.cn/direct/3d18169d59e94382b04727cfd1aa0d50.jpeg |
验收第 18 篇延续能力 |
| 作品页截图 | https://i-blog.csdnimg.cn/direct/8d56691f324d40d5885465386d1e5322.jpeg |
验收发布前回看闭环 |
这里有一个取舍:文章要写真实工程问题,但不能把本地签名密钥、密码、证书材料完整暴露出来。所以后面的代码块会保留字段名和结构,只用 *** 表示敏感值。
四、先定位 SDK 配置,不要先猜报错
构建排查第一步不是去改页面,也不是重新安装 DevEco Studio,而是定位真正的配置文件。当前项目的 SDK 配置在工程级 build-profile.json5 里:
rg -n "targetSdkVersion|compatibleSdkVersion|runtimeOS|strictMode" build-profile.json5
本次定位结果来自真实项目:
build-profile.json5:22: // 切到 API 26(版本串 26.0.0)以启用真实 3DGS 端侧能力。
build-profile.json5:23: "targetSdkVersion": "6.1.0(23)",
build-profile.json5:24: "compatibleSdkVersion": "6.1.0(23)",
build-profile.json5:25: "runtimeOS": "HarmonyOS",
build-profile.json5:27: "strictMode": {
这几行很有价值,因为它们暴露了一个常见问题:注释里仍然保留了"API 26 / 26.0.0"的历史说法,但实际可构建配置已经回到了 6.1.0(23)。如果文章或发布说明只引用注释,就会误导读者;如果只看实际字段,又会忘记为什么第 18 篇强调 3DGS 仍是预留路线。
我的处理规则是:构建以字段为准,路线以能力层为准,注释只作为历史线索。
五、SDK 版本串为什么不能和能力目标混写
HarmonyOS 工程里经常会同时出现三种说法:
- 当前 SDK 版本,例如
6.1.0(23)。 - 设备或系统能力的 API 编号,例如讨论中的 API 26。
- 某个未来能力的产品目标,例如 3DGS 重建、Spatial Recon 或多模态素材生成。
这三者互相关联,但不是同一个配置项。官方文档里,build-profile.json5 是工程构建配置的一部分,Hvigor 也会读取工程级和模块级配置来组织 product、module、target、buildMode 和 buildOption。参考:命令行构建工具 hvigorw 与 build-profile.json5 配置说明。
项目里的脱敏配置可以写成这样:
{
"app": {
"products": [
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.1.0(23)",
"compatibleSdkVersion": "6.1.0(23)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
}
]
}
}
这段配置表达的是"当前包按 HarmonyOS 6.1.0(23) 构建",不是"未来 3DGS 能力不做了"。第 18 篇的能力路由正是为了解决这个矛盾:页面可以展示 3D 入口,服务层可以保留 3DGS 执行体接入口,但当前构建结果必须按 6.1.0(23) 验收。
六、签名材料要检查,但文章和日志里要脱敏
build-profile.json5 里还有签名配置。这个部分对发布很关键,但不适合原样写到文章里。
{
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"storeFile": "D:/.../aichiboboji.p12",
"storePassword": "***",
"keyAlias": "aichiboboji",
"keyPassword": "***",
"profile": "D:/.../动图魔方调试签名Debug.p7b",
"certpath": "D:/.../图形处理项目调试证书.cer"
}
}
]
}
签名排查时,我会把它拆成四类问题:
| 检查项 | 需要看什么 | 不能做什么 |
|---|---|---|
storeFile |
p12 路径是否存在 | 不把完整本机路径当成通用教程 |
storePassword |
是否由 DevEco/AGC 正确生成 | 不在文章或聊天里公开 |
profile |
是否匹配 bundle、设备和调试/发布类型 | 不用错 profile 去解释运行失败 |
certpath |
证书是否和 profile 同源 | 不把证书问题伪装成 ArkTS 编译问题 |
这也是为什么本文把"签名提醒"放进构建排查,而不是发布前最后一分钟再看。签名问题一旦拖到发布前,会和 SDK、设备、模块配置混在一起,排查成本会成倍上升。
七、Hvigor 命令要固定成可复制口径
本次构建使用的是项目根目录下的真实命令:
$env:DEVECO_SDK_HOME = 'D:\HuaweiDevelopFormalStudy\DevEco Studio\sdk'
$env:Path = 'D:\HuaweiDevelopFormalStudy\DevEco Studio\jbr\bin;D:\HuaweiDevelopFormalStudy\DevEco Studio\sdk\default\openharmony\toolchains;D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\node;' + $env:Path
& 'D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\hvigor\bin\hvigorw.bat' assembleHap --mode module -p product=default --no-daemon
这里有几个细节值得保留:
DEVECO_SDK_HOME明确指向本机 DevEco SDK。Path里显式加入 JBR、toolchains 和 DevEco node。assembleHap只构建 HAP,不把 AppGallery 发布动作混进来。--mode module -p product=default对应当前工程的默认 product。--no-daemon让自动化日志更容易收尾,不依赖残留 daemon 状态。
这条命令和官方命令行构建思路一致:把构建从 IDE 当前状态里抽离出来,形成可重复执行的终端口径。
八、真实构建输出怎么读
本次实测输出的关键结果是:
> hvigor UP-TO-DATE :entry:default@CompileArkTS...
> hvigor UP-TO-DATE :entry:default@PackageHap...
> hvigor UP-TO-DATE :entry:default@SignHap...
> hvigor Finished :entry:assembleHap... after 1 ms
> hvigor BUILD SUCCESSFUL in 3 s 189 ms
这段日志说明三件事:
- ArkTS 编译阶段没有报错。
- HAP 打包和签名阶段没有阻塞。
- 本次构建很多任务是
UP-TO-DATE,表示缓存命中,不代表没有经过构建系统检查。
如果后续遇到失败,我会先按阶段归类:
| 阶段 | 常见问题 | 排查入口 |
|---|---|---|
CreateBuildProfile |
SDK 字段、product、module 配置错误 | build-profile.json5 |
CompileArkTS |
语法、类型、导入路径、API 签名不匹配 | entry/src/main/ets/** |
ProcessResource |
资源路径、媒体命名、profile 配置错误 | entry/src/main/resources/** |
PackageHap |
模块依赖、产物目录、oh-package 配置 | entry/build-profile.json5、oh-package.json5 |
SignHap |
p12、p7b、证书或 alias 不匹配 | signingConfigs |
这张表比"构建失败了怎么办"更有用,因为它把问题先拆到构建阶段,再去定位文件,而不是看见红字就去改业务代码。
九、截图证据与源码映射
构建通过只是底线。发布前还需要证明这个包对应的是当前功能集,而不是一个空壳构建。下面四张截图分别对应功能入口、编辑主链路、3D 能力和作品回看。




| 截图 | 对应源码位置 | 需要证明的规则 |
|---|---|---|
| 首页功能入口 | entry/src/main/ets/products/main/Index.ets:28 |
当前构建入口是主产品页 |
| 编辑器主链路 | entry/src/main/ets/products/main/Index.ets:591 |
GIF 导出仍走 ExportService.exportGif() |
| 3D 预览入口 | entry/src/main/ets/products/main/Index.ets:889 |
3D 入口仍由 Model3DView 承接 |
| 作品页回看 | entry/src/main/ets/products/main/Index.ets:595 |
导出结果会进入本地作品列表 |
| 能力路由 | entry/src/main/ets/features/threeD/services/CapabilityService.ets:17 |
构建能力和设备能力分开判断 |
| 导出服务 | entry/src/main/ets/features/gif/services/ExportService.ets:20 |
构建覆盖核心 GIF 服务 |
这里的重点不是截图好不好看,而是截图能否和源码位置互相解释。构建排查文章如果只有命令输出,读者会不知道这个包到底覆盖了哪些业务;只有截图,又会像产品展示页。两者连起来,才是工程证据。
十、构建配置和 3D 能力边界的关系
第 18 篇里,CapabilityService 把能力路由拆成设备能力和构建能力。第 19 篇需要承接这个判断,因为 SDK 配置不只是"能不能编译",它还会决定文章怎么写、测试怎么验收。
export interface CapabilityResult {
route: '3dgs' | 'render' | 'synthetic';
deviceSupportsRecon: boolean;
buildSupportsRecon: boolean;
message: string;
}
这类结构的价值在于它不让页面直接猜 SDK:
const cap = CapabilityService.detect3D();
if (cap.route === '3dgs') {
// 未来真实 3DGS 执行体接入后走这里。
} else if (cap.route === 'render') {
// 当前构建优先走实时 3D 预览与合成导出。
} else {
// 设备或构建都不满足时,保留单图浅 3D 降级。
}
如果 build-profile.json5 当前是 6.1.0(23),那么第 18 篇、第 19 篇和发布说明都应该保持同一个口径:当前版本已有 3D 预览和能力路由,真实 3DGS 执行体仍是预留路线。这个边界看起来保守,但它能保护后续发布。
十一、复现命令与日志留存
为了让下次自动化或人工复核能快速定位,我把本文用到的命令整理成一组最小集合。
rg -n "targetSdkVersion|compatibleSdkVersion|runtimeOS|strictMode" build-profile.json5
rg -n "CapabilityService|Model3DView|ExportService|StorageService" entry/src/main/ets/products/main/Index.ets entry/src/main/ets/features -g "*.ets"
Get-ChildItem -Path 'doc\screenshots_current' -Filter '*.jpeg' | Select-Object -First 20 -ExpandProperty FullName
$env:DEVECO_SDK_HOME = 'D:\HuaweiDevelopFormalStudy\DevEco Studio\sdk'
$env:Path = 'D:\HuaweiDevelopFormalStudy\DevEco Studio\jbr\bin;D:\HuaweiDevelopFormalStudy\DevEco Studio\sdk\default\openharmony\toolchains;D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\node;' + $env:Path
& 'D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\hvigor\bin\hvigorw.bat' assembleHap --mode module -p product=default --no-daemon
node tools/check_csdn_article_quality.js 19
本次构建验收摘要:
BUILD SUCCESSFUL in 3 s 189 ms
本次源码定位摘要:
entry/src/main/ets/products/main/Index.ets:28:@Entry
entry/src/main/ets/products/main/Index.ets:591:const work = await ExportService.exportGif(this.ctx(), preset, signal);
entry/src/main/ets/products/main/Index.ets:889:Model3DView({ viewSize: this.isWide() ? 360 : 320 })
entry/src/main/ets/features/threeD/services/CapabilityService.ets:17:export class CapabilityService
这些命令的价值在于可复现。下次如果有人说"构建又不稳定了",我们可以先跑同一组命令,看问题发生在配置、源码、资源、签名还是平台环境。
十二、常见错误分类与修正顺序
构建排查最怕把所有问题混在一起。我的顺序是先配置,再环境,再源码,最后签名和平台。
| 顺序 | 检查点 | 通过标准 | 风险 |
|---|---|---|---|
| 1 | 项目根目录 | 当前路径是 GIFRubiksCube |
在错误项目里构建 |
| 2 | SDK 环境变量 | DEVECO_SDK_HOME 指向 DevEco SDK |
使用旧 SDK 或缺 toolchains |
| 3 | SDK 字段 | targetSdkVersion 与 compatibleSdkVersion 是当前可识别版本 |
API 编号和 SDK 串混写 |
| 4 | product | product=default 存在 |
命令指向不存在的 product |
| 5 | 模块列表 | entry 模块在 modules 中 |
只改页面但模块没进构建 |
| 6 | ArkTS 编译 | CompileArkTS 通过 |
API 签名、导入路径、类型错误 |
| 7 | 资源处理 | ProcessResource 通过 |
图片、profile、路由配置错误 |
| 8 | 签名 | SignHap 通过 |
profile、证书或 alias 不匹配 |
| 9 | HAP 产物 | assembleHap 成功 |
缓存或产物目录异常 |
| 10 | 截图验收 | 当前功能截图可对应源码 | 构建成功但不是目标版本 |
这个顺序有一点朴素,但很有效:先确保工程能被构建系统理解,再讨论页面和业务。否则每次构建失败都会让人误以为是刚改的 ArkUI 代码坏了。
十三、本文不解决但必须记录的边界
第 19 篇也有几个不越界的地方:
- 不把调试签名当成上架签名。调试 profile 能让本地构建通过,不等于 AppGallery 发布材料已经齐全。
- 不用构建成功证明所有设备兼容。
compatibleSdkVersion和设备镜像仍然要在安装阶段复核。 - 不把 3DGS 预留说成当前已落地。当前构建只证明项目能在
6.1.0(23)下通过,不能证明 API 26 执行体已经存在。 - 不把
UP-TO-DATE误读成未构建。它说明 Hvigor 判断任务无需重跑,最终仍以BUILD SUCCESSFUL为准。 - 不在文章中公开签名密码和完整证书路径。工程排查可以记录"字段存在",不能泄漏材料。
这些边界让文章更可信。技术文不是把所有结果说满,而是把可以证明的事情证明清楚,把暂时不能证明的事情留在后续路线里。
十四、工程验收清单
| 验收项 | 结果 | 证据 |
|---|---|---|
| SDK 字段已定位 | 通过 | build-profile.json5:23-24 |
| 当前构建版本口径明确 | 通过 | targetSdkVersion / compatibleSdkVersion 均为 6.1.0(23) |
| Hvigor 命令可复现 | 通过 | assembleHap --mode module -p product=default --no-daemon |
| ArkTS 编译通过 | 通过 | CompileArkTS 输出 UP-TO-DATE |
| HAP 打包通过 | 通过 | PackageHap / SignHap 未阻塞 |
| 构建最终成功 | 通过 | BUILD SUCCESSFUL in 3 s 189 ms |
| 签名材料已脱敏说明 | 通过 | 本文只展示字段结构和 *** |
| 3D 能力边界未夸大 | 通过 | CapabilityService 仍按构建能力路由 |
| 截图和源码有映射 | 通过 | 首页、编辑、3D、作品页四张截图 |
| 第 19 篇具备发布前本地质检入口 | 通过 | node tools/check_csdn_article_quality.js 19 |
十五、工程复盘
这次构建排查带来的最大收益,是把"版本口径"变成了一个可检查对象。以前写文章时很容易把未来能力、当前 SDK、构建命令和截图验收混在一起;现在它们各自有位置:
build-profile.json5负责当前构建事实。CapabilityService.ets负责能力路由和降级口径。- Hvigor 命令负责可复现构建。
- 截图负责证明构建对象对应真实功能。
publish-record.json负责记录发布状态和 CSDN 链接。
这也是为什么第 19 篇适合放在系列尾声。前 18 篇已经拆了页面、导出、素材、存储、主题、3D 和验收,第 19 篇把它们背后的工程构建底座补齐。这样第 20 篇做发布前清单时,就不需要重新解释"为什么构建也算技术内容"。
十六、下一篇衔接
第 20 篇是系列收官:动图魔方技术拆解 20:HarmonyOS 工具 App 发布前工程清单与复盘。
它会把前面 19 篇分散的证据收成一个发布前清单:
- 功能链路是否覆盖素材导入、编辑、导出、作品回看和 3D 入口。
- 截图、构建输出、本地质检和 CSDN 发布记录是否能互相印证。
- 哪些能力属于当前版本,哪些能力属于后续 SDK 或平台能力演进。
doc/csdn-series如何作为项目文档资产继续维护,而不是发布后就被遗忘。
如果说第 19 篇解决的是"这个工程怎么稳定构建",第 20 篇要解决的就是"这个工程怎么带着清晰证据完成一轮发布复盘"。