
Project028 收官问题复盘从桌面 Form、代理提醒到 AGC 发布阻塞Project028 这个系列最后一章不再写泛泛的项目方法而是把这个项目里真正遇到的问题摊开讲。前面十九章已经拆过架构、持久化、底部导航、模板市场、详情编辑、桌面 Form、备份恢复、统计图、资源图、真机预检、构建环境、代理提醒、Profile 签名、AGC 审核、备份页点击反馈、窄屏布局和升级包发布。最后一章更适合做一次问题复盘每个问题在哪里出现、根因是什么、修复边界是什么、应该怎样验证。这类复盘比空泛总结更有价值。Project028 不是一个只停留在页面截图里的项目它经历过页面交互、系统能力、真机安装、发布签名、平台审核和 AGC 升级草稿。很多问题不是“代码写错”这么简单而是页面、服务层、Profile、版本草稿、设备状态和平台回读之间没有对齐。问题一底部导航不能写成一个本地 currentTab 容器Project028 早期容易被误解成“首页里放多个 Tab 分支然后用currentTab切换”。这种写法适合简单 Demo但不适合这个项目后续维护。因为首页、分类、统计、管理、设置都逐渐变成独立页面每个页面都有自己的刷新逻辑、滚动状态和入口参数。项目最终更适合的做法是一级入口之间使用router.replaceUrl()切换各页面独立维护自己的页面状态底部只复用同一个BottomNavBar组件。这样首页刷新、分类筛选、详情页跳转和设置页返回不会全部挤进一个Index.ets里。这个问题的修复边界很清楚不要把所有页面塞回首页不要为了省路由而牺牲维护性。验证重点是底部五个入口是否能正常切换、返回栈是否合理、首页刷新是否不会影响分类页滚动。问题二模板市场不能只靠静态卡片堆页面Project028 模板市场有 64 款内置卡片。问题不在卡片数量而在分类、排序、搜索和 fallback 之间的关系。如果模板只有数组没有分类元信息分类页会变成纯展示如果分类统计没有兜底某些分类为空时页面会显得像坏了。项目里需要把模板条目、分类 key、展示标题、摘要、标签和搜索字段整理成稳定结构。分类页展示分类概览时如果某个分类没有足够模板也要有可解释的空状态或兜底内容而不是直接留白。验证时不能只看首页模板。要分别检查全部分类、常用分类、搜索关键词、空搜索结果和templateId跳转。只有这些路径都能通模板市场才算可用。问题三详情页同时接收 cardId 和 templateId 时容易乱Project028 的详情页既可能查看已创建卡片也可能从模板市场进入模板预览。这里最容易混淆cardId和templateId。cardId指向用户已经保存的实例templateId指向内置模板。如果页面只按一个参数读取就会出现空白详情、编辑页数据丢失或保存后覆盖错误对象。正确处理方式是先明确入口语义有cardId就读取本地实例有templateId就走模板转实例或模板预览两个都没有时进入空白 fallback。页面不应该在参数不明时硬渲染一个半成品卡片。验证重点是三条路径从管理页进入已有卡片详情、从模板市场进入模板详情、直接异常进入详情页。异常路径也要给出空状态和返回入口。问题四保存后不刷新用户会以为没保存编辑页保存成功后如果仍停留在旧详情页或首页旧列表用户会怀疑保存失败。Project028 的处理重点是保存后要回到正确页面并让页面读取最新数据。这里用router.replaceUrl()比简单back()更稳因为它能明确目标页面和参数。保存动作本身应交给服务层处理页面只负责收集输入和展示结果。保存成功后详情页应重新按cardId读取首页和管理页则应在进入时刷新列表或使用统一数据源。验证时要看新增、编辑、删除三条路径。尤其是从模板创建卡片后返回详情页时要显示新实例而不是继续显示模板。问题五Preferences 初始化不能只写默认值Project028 使用 Preferences 保存轻量状态和本地配置。这里容易出现的问题是第一次安装、旧版本升级、空数据、脏数据恢复都混成一套逻辑。如果只在页面里写默认数组后续备份恢复、统计和桌面 Form 都会遇到数据不一致。更稳的做法是让AppDataService统一负责读取、默认值初始化、schema version 判断和快照导入导出。页面不直接散写 Preferences key也不在build()里做持久化。验证要覆盖首次启动、已有数据启动、导入空快照、导入旧格式快照。只看当前设备已有数据正常不足以说明初始化逻辑可靠。问题六备份页说明行点击无反馈备份页不是核心首页但很容易在审核里暴露问题。Project028 备份页里有“备份内容”“存储位置”“建议频率”等说明行它们有图标、箭头和卡片样式用户自然会点击。如果点击没有反馈就会被看作交互不完整。这个问题不需要重写备份服务。修复点是给说明行补充稳定动作 key例如content、location、frequency点击后给出 Toast 说明。业务备份仍然由AppDataService处理说明行只负责解释。验证很简单分别点击三条说明行确认都有不同反馈再检查手动备份、恢复最近备份和自动备份开关没有被影响。问题七恢复备份必须处理空状态如果用户从未备份过点击恢复不能静默失败。Project028 的备份恢复需要明确区分“没有快照”“快照解析失败”“恢复成功”“恢复后刷新页面”几种状态。空状态要告诉用户先执行一次备份而不是只弹一个含糊错误。服务层要返回可理解的结果页面再映射成提示。页面不应该直接解析快照也不应该自己拼接存储结构。验证时要先清空备份记录再点恢复再执行一次备份后恢复最后用异常快照验证失败提示。这样才能说明恢复链路不是只在理想状态下可用。问题八桌面 Form 不是页面截图Project028 接入桌面 Form 时容易误以为它只是把应用页面缩小展示。实际 Form 有自己的配置、生命周期、尺寸、数据注入和刷新方式。module.json5、form_config.json、Form 页面和服务层都要对齐。如果只写 ArkUI 页面而不检查 Form 配置桌面添加入口可能找不到如果只配置 Form 而不处理数据源桌面卡片显示就会停在默认内容。验证不只看应用内详情页。要在真机桌面添加卡片、长按管理、切换主题后刷新、移除后再添加。桌面 Form 必须按系统入口验证。问题九formId 不清理会导致刷新假成功桌面卡片刷新依赖formId。Project028 如果把旧formId永久保存用户移除桌面卡片后应用侧仍然可能尝试刷新一个已经无效的目标。结果看起来调用了刷新实际桌面没有变化。处理方式是保存有效formId在删除或刷新失败时清理失效记录。服务层不能只记录最后一次添加还要能识别失效和重复。验证时要添加卡片、应用内切换主题、桌面观察刷新再删除桌面卡片后触发刷新确认不会留下无效状态或错误提示。问题十themeImageKey 不同步会让桌面卡片显示旧图Project028 的桌面卡片支持主题图。页面里选择主题后如果只更新应用内展示没有把themeImageKey传到桌面 Form 刷新链路桌面卡片仍会显示旧图。这个问题用户很容易感知因为应用内和桌面不一致。修复重点是让主题选择、持久化状态和updateForm使用同一个 key。不要在页面和 Form 里各写一套资源映射。验证时要选不同主题、回到桌面观察图像变化、杀进程后再看桌面卡片是否仍能读取正确主题。问题十一代理提醒不是普通开关Project028 的提醒功能不是简单定时器。使用系统代理提醒时要同时考虑PUBLISH_AGENT_REMINDER权限、开放能力、通知授权、提醒请求参数、系统返回 id 和旧提醒清理。只在页面上放一个开关不代表系统提醒能工作。页面只适合收集提醒时间和开关状态。真正创建、取消和替换提醒应由提醒服务处理。服务层需要保存systemReminderId避免重复创建或无法取消。验证要看授权前、授权后、创建成功、修改时间、关闭提醒、重新开启。只看开关颜色变化不算提醒功能通过。问题十二通知授权拒绝后要有可用路径提醒功能需要通知能力。用户拒绝授权后页面不能一直表现为可用也不能静默失败。Project028 应该给出明确提示当前无法发布系统提醒可以先保存本地提醒设置授权后再启用系统提醒。这类能力相关功能要有降级路径。拒绝授权不是崩溃也不是无限 loading。页面要告诉用户当前状态并允许用户继续使用不依赖系统能力的部分。验证时要在未授权状态下点击开启提醒确认提示明确授权后再次开启确认系统提醒创建成功。问题十三systemReminderId 不清理会重复提醒提醒修改最容易出现重复。用户把时间从 9 点改成 10 点如果旧提醒没有取消新提醒又创建成功就会出现两个系统提醒。Project028 必须在创建新提醒前处理旧systemReminderId。更稳的顺序是读取旧 id取消旧提醒创建新提醒保存新 id如果创建失败不要把本地状态写成成功。验证要连续修改提醒时间再观察系统通知或日志。重复提醒是用户感知很强的问题不能只看页面保存按钮。问题十四Profile 缺能力会让代码看起来没问题但包不可用Project028 处理过代理提醒开放能力。代码里声明权限只说明源码有这个需求Profile 是否包含对应能力是另一回事。开放能力审批通过后需要重新生成 Profile并用新 Profile 重新签名。如果仍用旧 Profile构建可能通过页面也可能能打开但审核环境或真机能力调用会失败。这类问题不能靠改 ArkUI 页面解决。验证重点是 release Profile、包内 Profile、开放能力和 AGC 状态是否一致。不要只看源码里有没有权限声明。问题十五debug 和 release Profile 不能混用结论debug HAP 真机能跑不代表 release APP 能过 AGC。debug Profile 通常服务本地调试可能包含设备release Profile 服务正式发布关注应用身份、签名和开放能力。Project028 既要做真机验证也要做 AGC 上传因此必须分清两类包。交付时要明确当前验证的是 debug HAP、release APP还是 AGC 版本绑定包。三者不能互相替代。验证命令也要对应目标。本地调试优先assembleHap正式上传优先assembleApp平台发布还要看 AGC 包管理和版本草稿。问题十六hdc 失败先查设备不要先改业务代码真机安装失败时很多人第一反应是改应用代码。Project028 的经验是先查设备链路hdc list targets -v能否看到设备/data/local/tmp能否写入安装包路径是否正确签名是否适配当前设备。如果设备都没连上改页面没有意义。如果临时目录不能写安装失败也不是业务逻辑问题。验证前置应固定先看 target再做临时目录写入探针再安装 HAP最后启动 Ability 和截图。这样能把设备问题和应用问题拆开。问题十七hvigor 环境问题不能从最后一屏猜Project028 构建排障时DevEco JBR、Node、SDK、hvigor daemon 都可能影响结果。构建失败不能只看最后一屏也不能看到一堆红字就开始改页面。要找第一条真实错误。如果是环境继承问题可以用--no-daemon减少旧 daemon 影响如果是签名问题就查 signing 和 Profile如果是 ArkTS 类型错误再回到源码。验证时要记录执行命令、失败摘要和修复后同一命令的结果。换命令跑通过不能证明原问题已经解决。问题十八HAP 和 APP 的意义不同Project028 同时需要本地运行和 AGC 发布。HAP 更适合本地安装、交互验证和真机截图APP 更适合提交 AGC。两者输出目标不同签名和 Profile 也可能不同。如果用户问“本地能不能跑”优先看 HAP 和真机。如果用户问“能不能上架”就必须看 APP、release 签名、包合法性、版本绑定和审核状态。不要拿旧 APP 包判断当前页面修复也不要拿 debug HAP 证明 AGC 正在审核最新代码。问题十九AGC 上传包不等于版本草稿绑定包Project028 在 AGC 发布里最典型的问题是本地构建了新.app包管理也上传成功但版本页仍需要手动选择最新包并保存。只上传包不代表审核使用新包。平台状态至少分四层本地已构建、包管理已上传、版本草稿已绑定、已提交审核。每一层都要有证据。验证时要看软件包上传时间和版本草稿软件版本区是否一致。只有时间、版本和文件名都对上才能说草稿绑定了最新包。问题二十versionCode 相同会挡住真实升级Project028 的升级草稿出现过同版本提示当前包1.0.0 (1000000)与已上架版本versionCode相同已安装相同版本号的用户无法升级。这不是普通弹窗而是分发阻塞。如果目标是让已安装用户拿到代码优化就必须提升versionCode通常也同步提升versionName。继续提交同版本包即使平台允许走下去也不能达到真正升级的目的。验证重点是线上版本码、本地版本码、草稿绑定包版本码三者一致可比而且新包版本码大于线上。问题二十一新版本特性不能保留模板占位Project028 的 AGC 草稿曾因新版本特性仍是模板占位而被拦。这里不是代码问题而是资料问题。xxx、请补充这类内容不能进入正式提交。更合适的写法是围绕真实变化优化桌面卡片刷新、优化提醒设置、修复备份页点击反馈、完善窄屏布局。文案不需要夸张但必须对应实际包。验证时要保存后回读不要只看编辑框里临时出现过。问题二十二宣传图上传后必须保存并回读Project028 替换过 5 张竖版应用介绍图。上传图片只是第一步保存草稿并回读才算完成。平台页面复杂网络中断或表单校验失败都可能让图片没有真正落库。宣传图还要检查方向、尺寸、顺序和内容是否对应当前应用。AGC 宣传图、应用内资源图、真机问题截图不能混用。验证时要重新打开草稿看图片是否仍是目标批次而不是只看上传弹窗。问题二十三审核打回先读附件不要凭感觉大改AGC 审核打回时Project028 的正确路径是先读审核附件、录屏或问题描述再判断它指向页面、包、Profile、权限、资料还是版本绑定。不能一上来就重构页面。如果审核点的是备份页说明行那就修点击反馈如果审核看到的是旧包那就查版本绑定如果能力调用失败那就查 Profile 和开放能力。验证要对应审核路径。审核点哪里就复现哪里不要用无关页面通过来证明问题修复。问题二十四窄屏问题通常是 Row 没有收缩规则Project028 窄屏布局修复里PageHeader、ShowcaseCard、ChipTabs都暴露过文本挤压风险。根因不是屏幕太小而是横向布局里没有规定谁固定、谁收缩、谁截断。页面头部左右按钮固定中间标题用layoutWeight(1)和minWidth: 0文本设置maxLines和textOverflow。共享组件内部要兜底不能把压力都丢给调用方。验证要看长标题、小屏、字体放大、右侧操作按钮和暗色模式。只看默认截图不够。问题二十五ShowcaseCard 是共享组件不能只按首页调ShowcaseCard用在首页、分类页、管理页和统计页。它接收标题、摘要、数值、徽标、图片 key、路由等字段。只按首页调好换到分类页可能就溢出。共享组件要先保证内部稳定图片区域有固定比例文本列能收缩徽标不会挤掉标题长副标题能截断。调用方只负责传数据不负责补布局漏洞。验证要跨页面看同一个组件而不是只看一个入口。问题二十六ChipTabs 要处理长分类名分类页和样式页都有标签切换。标签名一长ChipTabs就可能挤压、换行或遮挡。Project028 这类组件应使用横向滚动、稳定高度和选中态不要让标签长度影响页面主体布局。状态 key 也要稳定。显示文案可以改但分类 key 不应该跟着改否则筛选、统计和跳转都会受影响。验证时要看全部分类、长分类名、选中态、滚动后点击和返回后状态。问题二十七图片资源要有统一映射Project028 有模板图、分类图、样式页 banner、桌面卡片主题图和 AGC 宣传图。如果资源散在页面里后续替换会非常痛苦。CardImages这类统一映射能减少页面对资源细节的依赖。图片 key 要稳定资源缺失要有 fallback。否则某个模板缺图就会导致卡片空白或布局跳动。验证时要扫首页、分类页、样式页和详情页确认图片都能显示缺图时也有兜底。问题二十八统计页要基于活动日志不要手工凑数字Project028 统计页如果只在页面里临时计算很容易和真实数据不一致。更稳的方式是把创建、编辑、删除、备份、恢复等动作写入活动记录再按周期桶聚合。这样统计页展示的是行为结果而不是页面临时拼出来的数字。后续如果接入更多统计维度也能从活动日志扩展。验证要看不同周期、无数据、单条数据、多条数据和删除后的趋势变化。问题二十九Service 层边界不能被页面吞掉Project028 页面很多如果每个页面都直接读写本地状态后续一定乱。服务层应负责数据读写、校验、快照、提醒、桌面卡片刷新页面负责输入、展示和轻量交互。比如备份恢复交给AppDataService桌面刷新交给DesktopFormService提醒调度交给提醒服务。页面不要直接散写复杂持久化逻辑。验证代码时要看业务规则是否落在服务层而不是看页面里能不能暂时跑通。问题三十修复不能顺手扩大Project028 后期很多问题都有明确边界。备份页点击无反馈就修说明行反馈同版本码阻塞就改版本元数据并重构建窄屏挤压就修共享组件约束Profile 缺能力就重新生成 Profile。如果每次都顺手重构就会扩大回归范围。发布阶段尤其要控制变量因为审核和平台状态本来就复杂。验证时也要对应边界。修了什么就验证什么没动的模块不要写成已优化。问题三十一AGC 资料不是上传成功就算保存成功Project028 替换 AGC 应用介绍图时上传完成不等于草稿保存完成。平台页面里图片进入上传区域只说明浏览器侧拿到了素材只有保存草稿并重新进入页面回读才能确认图片真正落库。这个问题和软件包绑定很像。包管理里有新包不代表版本草稿绑定新包上传区里出现新图也不代表草稿保存了新图。Project028 的 5 张竖版宣传图必须在保存后再次检查顺序、尺寸和内容。验证时要重新打开 AGC 草稿确认应用介绍图仍是目标批次并且新版本特性、软件版本区和提交前提示都没有回退。问题三十二AGC 草稿阻塞不要用本地通过掩盖Project028 的升级草稿已经绑定过新包也保存过宣传图但最终仍因为同versionCode被拦。这时不能用“本地构建通过”来掩盖平台阻塞。构建通过只是本地产物状态AGC 提交前提示才是升级分发状态。处理这类问题要把状态拆开本地已构建、包管理已上传、草稿已绑定、资料已保存、最终提交被阻塞。只有这样下一步才不会误走成重新上传同一个包。后续最小动作就是提升versionCode重新构建 release APP上传后在原草稿里重新选择新版本码包再检查宣传图和新版本特性是否仍然保留。问题三十三问题清单要直接指向项目文件和平台状态Project028 后续维护不能只写“优化体验”。每个问题都应该能指向具体文件、页面、服务或平台状态。例如底部导航看Index.ets、CategoryPage.ets和BottomNavBar桌面卡片看form_config.json、Form 页面和DesktopFormService提醒能力看权限、Profile 和提醒服务升级发布看AppScope/app.json5、release APP 和 AGC 草稿。这样整理问题清单后续才知道从哪里改、用什么验证、哪些状态不能互相替代。抽象描述不能指导修复具体入口才能缩小排查范围。这也是本章重写的原因最后一篇必须收束到 Project028 本身。Project028 后续最该先做什么如果继续维护这个项目优先级不是随便加新功能而是先把已知阻塞清掉升级包先提升versionCode重新构建 release APP。用新包重新上传 AGC并在升级草稿中重新绑定。复查代理提醒 Profile 是否仍包含开放能力。真机复核桌面 Form 刷新、提醒创建和备份页反馈。AGC 草稿继续保持新宣传图、新版本特性和新版本码包一致。这些动作都和 Project028 当前状态直接相关不是抽象建议。这一章的结论Project028 最大的经验不是某一个组件怎么写而是要把真实问题分层看页面问题回到 ArkUI 和组件约束数据问题回到服务层和持久化系统能力问题回到权限和 Profile发布问题回到包、版本、草稿绑定和平台回读。最后一章只保留项目相关内容和项目真实问题。这样整个系列才像一个完整的 HarmonyOS ArkTS 项目复盘而不是泛泛的经验总结。后续继续做 Project028也能沿着这些问题清单逐项推进。