动图魔方技术拆解 18:ArkGraphics3D 预览、能力检测与 3DGS 降级路线 SEO 信息SEO 标题动图魔方技术拆解 18ArkGraphics3D 预览、能力检测与 3DGS 降级路线SEO 摘要基于 HarmonyOS NEXT / ArkTS 项目“动图魔方”拆解 GIF 工具如何把Model3DView.ets、CapabilityService.ets、Recon3DService.ets与ExportService.ets串成可交付的 3D 路线当前用 ArkGraphics3D 做真实模型预览用deviceInfo.sdkApiVersion判断设备能力并在 3DGS 未接入时稳定回退到合成导出。关键词HarmonyOS, ArkTS, ArkGraphics3D, Component3D, CapabilityService, Recon3DService, 3DGS, Spatial Recon Kit, 能力检测, 降级路线文章封面doc/csdn-series/covers/cover-18-arkgraphics3d-capability-route.jpg投稿方向普通技术拆解 / HarmonyOS 本地 3D 预览与降级工程项目环境HarmonyOS SDK6.1.0(23)、ArkTS、DevEco Studio、GIFRubiksCube验证时间2026-06-27验证对象entry/src/main/ets/features/threeD/components/Model3DView.ets、entry/src/main/ets/features/threeD/services/CapabilityService.ets、entry/src/main/ets/features/threeD/services/Recon3DService.ets、entry/src/main/ets/features/gif/services/ExportService.ets、entry/src/main/ets/products/main/Index.ets、entry/src/main/ets/entryability/EntryAbility.ets、entry/src/main/resources/base/profile/main_pages.json第 05 篇讨论的是“为什么一个 GIF 工具要给 HarmonyOS 7.0 的 3D 能力预埋结构”第 18 篇则把镜头拉回当前工程本身既然项目还在6.1.0(23)又不想在页面里夸大“真实 3DGS 已可用”那就必须把预览、能力判断、导出分流和失败回退做成一条可复验的工程链路。否则 3D 入口只会变成演示文案而不是可以交付的产品能力。一、真实工程问题背景在工具类 App 里“支持 3D”最容易被写成一句很虚的话页面上放一个 3D 卡片、写两句未来能力说明、再放一个实验标签看起来像已经有路线实际上用户和测试都无法判断当前到底支持到哪一步。“动图魔方”里这类风险主要体现在四个层面现象编辑页已经能看到旋转模型团队就容易口头说成“3D 已经支持了”。原因把ArkGraphics3D实时渲染和3DGS重建混写成同一个能力名词。影响测试会误以为当前版本已经具备“从单图/视频到真实 3D 场景”的完整能力。验证路径必须把Model3DView的实时渲染、CapabilityService.route的能力分层、Recon3DService的占位状态同时拿出来核对。现象设备 API 版本足够高但当前安装包仍然只能走合成路线。原因设备支持和构建支持是两套条件当前包未必真的带了3DGS执行体。影响如果 UI 只看sdkApiVersion开入口就会出现“设备支持但包不支持”的伪成功。验证路径同时检查deviceSupportsRecon、buildSupportsRecon和最终route。现象3DGS 执行体尚未完成时3D 导出仍必须能继续工作。原因GIF 工具主线是可导出、可回看、可分享不能让高阶实验能力拖垮当前版本。影响如果没有合成降级路线3D 模式会变成只能看不能导的半成品。验证路径检查ExportService.buildFromSynthetic()是否在Recon3DService不可用时自动回退到FrameProcessor.buildSyntheticGifFrames()。现象页面文案和真实能力边界不一致。原因功能入口、能力卡、导出提示没有围绕同一套路由结果收口。影响运营、测试和用户会拿着互相冲突的口径做判断。验证路径把phase: 实验、真实3DGS预留和导出区提示文案逐项映射到源码。所以第 18 篇要解决的不是“怎么把 3D 做炫”而是一个更朴素的问题如何在 6.1 可交付版本里给 3D 预览和未来 3DGS 留出正式入口同时保证当前用户拿到的是可运行、可解释、可降级的结果。这个问题表面上是在讲 3D实质上是在讲交付口径。只要入口说明、能力判断和导出路径三者中有一个说不清测试结论就会摇摆发布说明也会跟着失真。换句话说第 18 篇不是在证明“我们已经完成了 3DGS”而是在证明“当前版本把能做的、不能做的、未来准备怎么接都写成了可核对的工程结构”。二、目标与边界这篇文章的目标很明确说明Model3DView当前已经落地的是哪种真实能力。说明CapabilityService如何把设备能力和构建能力拆开判断。说明Recon3DService为什么必须作为正式接入点存在即便当前仍是占位实现。说明ExportService怎样把3dgs / render / synthetic三条路线统一收口。说明页面文案怎样避免把“实验预览”误写成“已完成重建”。边界同样需要讲清楚本文不重复第 17 篇已经写过的“真实素材验证闭环”只聚焦 3D 路线。本文不把 ArkGraphics3D 预览说成 3DGS 重建结果两者在能力层级上不同。本文里的 3D 导出当前仍以图片合成转动动效为主不虚构尚未确认的 API 26 重建接口。本文只引用项目现有代码和官方文档不编造“未来可用”的 SDK 调用签名。这组边界先写清楚后面的代码证据才不会被误读成营销文案。尤其是 3D 相关话题最容易出现的偏差就是把“预览已经跑起来”误写成“重建能力已经接入完成”。对读者来说边界越明确后面每一段代码就越容易看懂。因为大家会知道本文到底在验证什么也知道哪些能力仍然只是正式预留而非当前可用。三、源码对象与官方依据这一篇实际对应的源码对象如下entry/src/main/ets/features/threeD/components/Model3DView.etsentry/src/main/ets/features/threeD/services/CapabilityService.etsentry/src/main/ets/features/threeD/services/Recon3DService.etsentry/src/main/ets/features/gif/services/ExportService.etsentry/src/main/ets/products/main/Index.etsentry/src/main/ets/entryability/EntryAbility.etsentry/src/main/resources/base/profile/main_pages.jsondoc/screenshots_current/gifrubik_3d.jpegdoc/screenshots_current/gifrubik_discover_expanded.jpegdoc/screenshots_current/gifrubik_editor.jpegdoc/screenshots_current/gifrubik_editor_export_blocked.jpegdoc/真实3D渲染落地记录.md这些对象分别负责不同层级的事情对象责任为什么是第 18 篇主角Model3DView.ets加载 glTF、初始化相机、驱动模型自转、实时渲染或失败回退证明项目当前已经有真实 3D 预览不只是文案占位CapabilityService.ets判断sdkApiVersion、构建能力与路由结果决定 3D 路线到底走3dgs、render还是syntheticRecon3DService.ets为 API 26 的真实 3DGS 重建保留接入口决定“未来能力”是否有正式挂点而不是散落在页面判断里ExportService.ets按路由分发 3D 导出实现并在失败时自动回退决定当前产品是否可交付Index.ets承接页面文案、能力卡、导出提示和用户可见状态决定用户看到的能力表述是否准确EntryAbility.ets通过windowStage.loadContent(products/main/Index)装载主页面证明第 18 篇分析的是正式产品入口而不是独立 demomain_pages.json声明主页面资源索引包含products/main/Index证明 3D 路线已经进入正式页面路由而不是临时调试页把入口层也纳入证据链能补上一块很容易被忽略的拼图。很多文章会直接从功能页开始讲但真正决定“这是不是项目主线”的是入口和页面注册是否已经接到正式产品结构里。这里补上EntryAbility.ets和main_pages.json之后文章证据链就从“功能实现”延伸到了“应用入口”。这对解释 3D 路线是否真的进入交付面非常关键。对应的官方依据建议同时核对ArkGraphics 3D 场景构建与 Component3D 渲染说明。deviceInfo.sdkApiVersion 兼容性检查说明。ohos.deviceInfo 接口参考。Spatial Recon Kit 简介。加载 3DGS 模型能力说明。spatialRender 参考。这里我做一个明确判断根据官方文档ArkGraphics3D 实时场景渲染和Spatial Recon / 3DGS 数据加载或重建属于不同能力层次。项目现在已经真实接入的是前者后者在当前工程里是“有正式接入口但未在本构建里启用”的状态。四、先把“真实 3D 预览”定义清楚避免和 3DGS 混写第 18 篇首先要做的一件事就是把“当前到底实现了什么”讲清楚。Model3DView.ets不是在做伪 3D 图层平移而是直接使用kit.ArkGraphics3Dimport { Scene, SceneResourceFactory, Camera, Node, Quaternion } from kit.ArkGraphics3D; Component export struct Model3DView { Prop viewSize: number 220; State sceneOpt: SceneOptions | null null; State failed: boolean false; private scene: Scene | null null; private node: Node | null null;组件初始化主线也很直接Scene.load($rawfile(model3d/cube.gltf)) .then(async (result: Scene) { this.scene result; const rf: SceneResourceFactory this.scene.getResourceFactory(); const cam: Camera await rf.createCamera({ name: GifRubikCam }); cam.enabled true; cam.position.z 3.2; this.node this.scene.getNodeByPath(CubeRoot); const opt: SceneOptions { scene: this.scene, modelType: ModelType.SURFACE }; this.sceneOpt opt; this.startSpin(); })这里至少能说明三件事情项目当前已经在加载真实 glTF 模型而不是把 3D 预览写成静态示意图。预览区里的旋转来自场景节点四元数更新不是把一张图片做左右位移假装 3D。当前落地的是真实 3D 模型渲染预览不是“从单图或视频重建 3DGS 场景”。这一段的工程价值在于它把“渲染”这个词钉死在真实场景对象上。只要Scene.load、Camera和Component3D同时出现就能判断这不是简单的位移动画或伪 3D 过场。这也解释了为什么第 18 篇必须单独写。因为一旦团队内部把这一步叫成“3D 已经打通”后面的能力验收就会从第一天开始跑偏。自转逻辑同样是证据private startSpin(): void { this.timerId setInterval(() { if (this.node null) { return; } this.angle 0.03; const half this.angle / 2; const rot: Quaternion { x: 0, y: Math.sin(half), z: 0, w: Math.cos(half) }; this.node.rotation rot; }, 32); }这段代码非常适合拿来解释“为什么第 18 篇和第 05 篇不同”第 05 篇强调 7.0 路线预埋第 18 篇强调当前代码里已经有一个真实 3D 渲染执行体而且它的职责边界明确。五、能力检测不能只看设备还要看当前构建是否真的带上执行体很多团队写“能力检测”时只做一层sdkApiVersion X判断然后在页面里直接开入口。这样最容易出现的问题是设备看起来支持。页面文案也写成支持。但当前安装包根本没带对应实现。项目里这一层被CapabilityService.ets拆开了const API_ARKGRAPHICS3D 12; const API_3DGS_RECON 26; const deviceSupportsRecon sdk API_3DGS_RECON; const buildSupportsRecon Recon3DService.isBuildSupported(); const supportRecon deviceSupportsRecon buildSupportsRecon; const supportRender sdk API_ARKGRAPHICS3D; let route synthetic; if (supportRecon) { route 3dgs; } else if (supportRender) { route render; }这一层设计的价值非常高设备支持和构建支持被拆成两套条件不再混为一谈。真正给下游用的不是一堆零散布尔值而是收口成route。UI、导出服务和后续 3DGS 接入都只需要消费统一路由结果。更关键的是这里把用户能看到的解释文案也一起收口了if (supportRecon) { message 检测到 API ${sdk}启用真实 3DGS 端侧重建路线。; } else if (deviceSupportsRecon !buildSupportsRecon) { message 设备支持 3DGSAPI ${sdk}但当前构建尚未接入 3DGS 重建模块Recon3DService接入后即启用真实重建。当前走实时渲染 合成导出。; } else if (supportRender) { message 检测到 API ${sdk}支持 ArkGraphics3D 实时渲染3DGS 重建需 API 26。当前走实时渲染 合成导出。; } else { message 当前设备 API ${sdk} 较低走单图合成伪 3D 路线。; }这比只在页面上写一个“实验功能”强太多因为它把下面四种状态分开了真正可走3dgs。设备条件到了但当前构建还没带Recon3DService执行体。只支持 ArkGraphics3D 预览。连实时渲染都不支持只能走合成。从发布和测试角度看这种拆分还有一个直接收益问题单可以落到明确责任层。是设备不支持还是 SDK 构建没带上执行体还是仅支持预览不支持重建都能从同一套路由结果里看出来。如果没有这层路由收口页面上出现的每一条提示文案都可能变成新的分叉逻辑。短期看似灵活长期会让 3D 路线越来越难维护。这四种状态如果不拆后续的测试、运营文案、用户反馈都会乱。六、Recon3DService的意义不是“现在就能跑”而是让未来能力有正式接入口第 18 篇最容易被误解的一点是既然Recon3DService当前还是占位为什么还值得单独写原因很简单如果这里没有正式接入口未来 3DGS 接入只会变成一堆散落在页面和导出服务里的临时判断。项目里的Recon3DService.ets已经把这层结构搭出来了export const BUILD_API_SUPPORTS_3DGS false; export class Recon3DService { static isBuildSupported(): boolean { return BUILD_API_SUPPORTS_3DGS; } static async reconstruct(uri: string, frameCount: number, delayCs: number, signal: ExportSignal): PromiseGifFrameBuildResult { throw new Error(3DGS reconstruction not available in this build (requires API 26 SDK)); } }它现在虽然不执行真实重建但已经提前固定了三件重要事情构建层开关在哪里控制。真实重建服务未来以什么函数入口被调用。返回结果必须收口到GifFrameBuildResult复用下游量化和编码链路。这类“先把空接口立住”的做法真正解决的不是今天能不能跑而是明天升级时改动面会不会失控。只要返回结果不变下游导出链路就不用陪着一起重写。对于工具类 App 来说这比“先做一个能演示的实验接口”更靠谱。因为演示版本最怕的不是不能展示而是后面接正式实现时把已有主链路拆散。这就是标准工程思路先把接口位置、返回结构和回退规则固定再等官方 API 或构建条件成熟时补执行体。这样升级到 API 26 时动的是一个服务文件而不是整条产品主流程。七、导出分流必须可交付3D 路线不成熟也不能拖垮 GIF 主链路如果 3D 路线只有预览没有导出兜底那它仍然只是实验页不算真实功能。ExportService.ets里这部分做得很像一个真正可交付的产品路由器if (preset.editorType threeD) { return await ExportService.buildFromSynthetic(preset, rotate3d, signal); } if (preset.editorType depth) { return await ExportService.buildFromSynthetic(preset, parallax, signal); }再往下看rotate3d的分流逻辑已经被能力路由接管if (mode rotate3d CapabilityService.detect3D().route 3dgs Recon3DService.isBuildSupported()) { try { const reconResult await Recon3DService.reconstruct(preset.sourceUris[0], frameCount, delayCs, signal); return await ExportService.encodeResult(reconResult, preset); } catch (err) { // 3DGS 不可用时回退合成路线 } } const result await FrameProcessor.buildSyntheticGifFrames( preset.sourceUris[0], frameCount, delayCs, mode, ExportService.editOptions(preset), signal );这段代码真正体现了第 18 篇的主题3dgs不是一个页面概念而是导出服务里的正式路线。即便未来走进了Recon3DService最后仍然回到统一的encodeResult()下游。只要 3DGS 当前不可用就自动回退到合成路线不让整个导出能力失效。也就是说项目没有因为“真实 3DGS 还没接完”就把 3D 功能整体锁死而是先交付实时渲染预览 合成导出这条当前可稳定跑通的主线。这就是第 18 篇最核心的取舍。当前版本不追求把未来能力一次性讲满而是先保证用户今天打开页面、预览模型、点击导出时拿到的都是一致且可解释的结果。从工程治理角度看这种取舍也更利于持续演进。以后无论接的是 Spatial Recon、3DGS 还是别的重建执行体都可以在既有导出入口上增量替换而不是推翻整条产品链路。八、页面文案必须跟真实能力一致不能把实验入口包装成完成态如果代码里已经做了路由和降级但页面仍写成“真实 3D 已完成”用户照样会被误导。项目当前在Index.ets里把这个边界写得比较克制{ id: threeD, title: 3D转动图, desc: 当前为图片合成转动动效, badge: 3D, tint: #5C8DFF, phase: 实验 }, { id: depth, title: 单图浅3D, desc: 本地视差合成动效, badge: 浅3D, tint: #FF9B45, phase: 实验 }设备卡里也没有故意夸大Text(当前路线${this.routeLabel()} · 真实3DGS${this.support3DRecon ? 可用 : 预留})导出区提示更直接Text( this.route3D 3dgs ? 提示检测到支持将走真实 3DGS 端侧重建导出 : 提示当前导出走图片合成转动动效视频转真实 3D 需要 3DGS/NeRF 等重建能力。 )这类文案的工程意义很大用户知道当前拿到的是哪种结果。测试知道当前验收口径是什么。未来升级到 API 26 时只需要改路由结果和执行体不用推翻整套交互结构。很多项目的问题不是没有降级而是降级只存在于代码里用户看不到测试也看不到。等到有人拿着页面截图来问“为什么这里没有真 3D 导出”时团队才发现对外口径根本没对齐。把这层解释提前写进页面本质上是在降低沟通成本。它让 3D 路线从“开发自己知道的内部事实”变成“用户和测试都能看到的公开规则”。九、命中结果先把源码定位、命令输出和真实行号钉住为了避免这篇文章继续停留在“概念上说得通”我先把本地命令命中的关键结果列出来。实际定位时主要用了下面这组命令rg -n Model3DView|CapabilityService|Recon3DService|buildFromSynthetic|route3D|真实3DGS|ArkGraphics3D entry/src/main/ets -SGet-ChildItem doc/screenshots_current -File | Where-Object { $_.Name -match 3d|discover_expanded|editor_export_blocked } | Select-Object Name, Length命中的关键结果如下entry/src/main/ets/products/main/Index.ets:22: { id: threeD, title: 3D转动图, desc: 当前为图片合成转动动效, badge: 3D, tint: #5C8DFF, phase: 实验 }, entry/src/main/ets/products/main/Index.ets:1121: Text(当前路线${this.routeLabel()} · 真实3DGS${this.support3DRecon ? 可用 : 预留}) entry/src/main/ets/products/main/Index.ets:1142: Text(this.route3D 3dgs ? 提示检测到支持将走真实 3DGS 端侧重建导出 : 提示当前导出走图片合成转动动效视频转真实 3D 需要 3DGS/NeRF 等重建能力。) entry/src/main/ets/features/threeD/components/Model3DView.ets:34: Scene.load($rawfile(model3d/cube.gltf)) entry/src/main/ets/features/threeD/components/Model3DView.ets:73: Component3D(this.sceneOpt) entry/src/main/ets/features/threeD/services/CapabilityService.ets:26: const deviceSupportsRecon sdk API_3DGS_RECON; entry/src/main/ets/features/threeD/services/CapabilityService.ets:27: const buildSupportsRecon Recon3DService.isBuildSupported(); entry/src/main/ets/features/threeD/services/CapabilityService.ets:31: let route synthetic; entry/src/main/ets/features/threeD/services/CapabilityService.ets:35: route render; entry/src/main/ets/features/threeD/services/Recon3DService.ets:17:export const BUILD_API_SUPPORTS_3DGS false;doc/screenshots_current/gifrubik_3d.jpeg doc/screenshots_current/gifrubik_discover_expanded.jpeg doc/screenshots_current/gifrubik_editor.jpeg doc/screenshots_current/gifrubik_editor_export_blocked.jpeg这些命中结果把第 18 篇真正要讲的四个层级串起来了入口文案已经把 3D 标成实验态。页面能力卡已经展示“路线”和“真实3DGS 是否可用”。预览层已经真实落地Scene.load Component3D。服务层已经把BUILD_API_SUPPORTS_3DGS固定成一个可升级、可回退的接入口。十、截图与证据要证明“实时渲染、能力检测、降级提示”同时存在第 18 篇不能只贴代码因为 3D 路线最大的风险恰恰来自“页面说一套底层做一套”。这次我把截图和源码规则一一对应起来截图需要证明的规则对应源码位置gifrubik_discover_expanded.jpeg发现页把 3D 路线标成实验能力而不是主线已完成功能Index.ets:22-23、1333-1341gifrubik_editor.jpeg编辑器存在统一的 3D 入口说明 3D 路线已经进入实际工作台结构Index.ets:383-404gifrubik_3d.jpeg3D 编辑页同时展示预览、参数和说明证明这不是独立 Demo 页面Index.ets:888-914、1118-1145gifrubik_editor_export_blocked.jpeg导出区提示当前走合成路线说明页面文案遵守实际路由结果Index.ets:1141-114510.1 发现页必须把 3D 标成实验路线而不是完成态这张图对应的是{ id: threeD, title: 3D转动图, desc: 当前为图片合成转动动效, badge: 3D, tint: #5C8DFF, phase: 实验 }它证明项目没有把 3D 功能包装成“当前已完整闭环”而是明确告诉用户当前仍是实验路线。10.2 编辑器主入口必须把 3D 路线纳入统一工作台这张图的意义在于证明 3D 并不是一个游离在工程外的独立样例而是和视频转 GIF、图片拼 GIF 一起进入了同一套编辑页状态机。10.3 3D 编辑页要同时承接预览、能力卡和导出提示这张图至少可以验证四件事3D 模式是独立编辑入口而不是被塞进普通 GIF 模式的隐藏分支。页面上明确区分了 3D 路线、导出参数和能力提示不是只给一个模糊入口。用户看到的不是“已完成 3DGS 重建”而是当前工程下真实可交付的 3D 预览与导出说明。预览区和导出区被放在同一条工作链上说明这不是单独的图形实验页。10.4 导出区文案必须告诉用户“当前为什么走合成”这张图最重要的价值不是“页面看起来可导出”而是它能证明导出提示会跟着当前路由一起变化。当前版本没有把“实时预览可用”偷换成“真实 3DGS 可导出”。降级路线是用户可见、测试可见、验收可见的不是藏在代码注释里。十一、回归命令与验收清单我这次定位和校验第 18 篇主线时主要用了下面几类命令rg -n Model3DView|CapabilityService|Recon3DService|buildFromSynthetic|route3D|真实3DGS|ArkGraphics3D entry doc -SGet-Content entry/src/main/ets/features/threeD/components/Model3DView.ets Get-Content entry/src/main/ets/features/threeD/services/CapabilityService.ets Get-Content entry/src/main/ets/features/threeD/services/Recon3DService.ets Get-Content entry/src/main/ets/features/gif/services/ExportService.etsnode tools/check_csdn_article_quality.js 18本地质检第一轮的结果也值得保留下来因为它正好反向证明第 18 篇应该补哪些证据Article: doc\csdn-series\18-ArkGraphics3D预览能力检测与3DGS降级路线.md Score: 76/100 Pass: NO (target 90)当时主要缺的是工程问题不够具体、截图与源码映射不足、命令与行号证据不够硬。也正因为如此第 18 篇后续才会专门补上“命中结果”和“四张截图映射”这两层。把第一次 76 分的结果放在这里不是为了展示分数而是为了说明这篇稿件是怎么从“概念介绍”被逼回“工程证据”的。这个修稿过程本身就是系列文章里很值得保留的方法论。如果一篇技术拆解连自己补过哪些证据都说不清那它最后就算能发出去也很难在系列里形成稳定复用的方法。这篇的工程验收清单建议按下面的口径看验收项结果证据当前工程已接入 ArkGraphics3D 实时模型预览通过Model3DView.ets中Scene.loadComponent3D3DGS 与 ArkGraphics3D 预览被明确区分通过CapabilityService.ets的route与message设备能力与构建能力未被混写通过deviceSupportsRecon/buildSupportsRecon拆分Recon3DService已有正式接入口通过isBuildSupported()与reconstruct()占位导出服务可按3dgs / render / synthetic分流通过ExportService.buildFromSynthetic()3DGS 不可用时不会拖垮主流程通过catch后自动回退buildSyntheticGifFrames()页面文案未把实验能力夸大为已完成能力通过Index.ets中phase: 实验、真实3DGS预留十二、小结第 18 篇真正想说明的是一个工具类 App 里最重要的不是抢先把“3DGS”三个字写进页面而是把当前可运行的能力、未来待接入的能力和不可用时的降级路线拆成一条清晰的工程链路。“动图魔方”当前这条 3D 路线已经具备三个很关键的特征有真实执行体Model3DView已落地 ArkGraphics3D 模型预览。有正式路由器CapabilityService把设备与构建条件拆开判断。有稳定兜底ExportService在 3DGS 不可用时自动回退到合成导出。这意味着未来即便要升级到 API 26、接入 Spatial Recon 或真实 3DGS 执行体变动的也只是能力执行层而不是整套页面、导出和验收结构。十三、下一篇衔接第 19 篇继续拆《动图魔方技术拆解 19HarmonyOS SDK 配置修正与 Hvigor 构建排查》重点会转向6.1.0(23)这类 HarmonyOS SDK 标识为什么经常在构建配置里写错。build-profile.json5、Hvigor 命令与本地环境变量怎样共同决定构建能否稳定通过。当项目同时预埋高阶能力、又要保证当前版本可交付时构建排查文档为什么必须和功能文档一起维护。如果把第 18 篇看作“能力边界怎么收口”那第 19 篇就是“构建边界怎么收口”。前者解决的是页面和导出不说大话后者解决的是本地和 CI 不因为 SDK 标识、构建脚本或环境变量反复翻车。这里顺带保留一个系列锚点方便统一回看老稿件动图魔方技术拆解 17清除虚拟数据后如何用真实素材验证 GIF 工具。第 17 篇解决真实素材验收第 18 篇解决 3D 路线边界第 19 篇则继续把构建稳定性补齐。