AGC 审核打回定位实战:审核附件、版本绑定与本地最小修复

发布时间:2026/7/8 1:34:35
AGC 审核打回定位实战:审核附件、版本绑定与本地最小修复 AGC 审核打回定位实战审核附件、版本绑定与本地最小修复Project028 进入 AGC 审核阶段后最容易浪费时间的不是代码怎么改而是先判断审核平台到底看到了哪一个包。页面本地已经修好、DevEco 能跑、HAP 能装并不等于 AGC 版本页已经绑定了这个新包。只要平台仍然审核旧包本地修多少次都不会改变审核结果。这一章按真实交付链路展开先看 AGC 审核报告和附件再核对版本绑定、包上传时间、审核问题对应页面最后把问题压回本地最小修复和同一套验证矩阵。这里的重点不是泛泛而谈“审核失败”而是把每条审核意见变成能执行、能复现、能关闭的工程动作。审核打回先看版本绑定AGC 审核结果里看到问题后第一步不是打开代码而是确认平台当前绑定的包。Project028 之前就遇到过这种情况本地已经修过提醒问题但 AGC 报告仍然来自旧版本包。如果这个状态没有拆清楚后面会把旧包问题误判成本地修复无效。可以把状态拆成六层local source fixed - local HAP/APP built - AGC package uploaded - AGC version bound to package - AGC version submitted for review - AGC reviewer tested this bound package每层都要有证据。只看到本地构建成功只能说明第一层到第二层成立看到 AGC 上传记录说明第三层成立看到版本详情页绑定的是新包才说明第四层成立。审核仍然打回时再看附件和问题路径。本地已修复 ! AGC 已审核新包 AGC 已上传 ! AGC 当前版本已绑定 已提交审核 ! 已通过审核Project028 的发布记录会同时保留本地构建时间、上传包名、版本页状态和审核提交状态。这样后续复盘时不会只凭一句“我已经改了”来判断。审核附件要落到页面动作审核报告通常会给文字描述、截图或录屏。文字描述只能提供方向附件里的点击路径更重要。Project028 这类工具型应用审核问题大多会落到页面动作点击无反应、保存后没有系统行为、提示文案和真实结果不一致、返回后状态没有刷新。审核附件要拆成下面这种表附件画面 - 页面 - 用户动作 - 实际反馈 - 期望反馈 - 涉及文件例如备份说明项无反馈 - BackupPage - 点击信息行 - 无弹窗、无提示、无跳转 - 给出说明反馈 - entry/src/main/ets/pages/BackupPage.ets再例如提醒保存成功但没有到点提醒 - ReminderPage - 开启提醒并保存 - 页面提示保存成功系统提醒未触发 - 保存状态必须与系统调度结果一致 - ReminderSchedulerService.ets这一步的价值是让问题从“审核说不行”变成“哪个页面、哪个动作、哪个状态不一致”。只有路径明确后面的最小修复才不会发散。把审核意见拆成可复现路径Project028 的审核问题会先落到一条可复现路径而不是直接改 UI。可复现路径最好包含设备条件、入口、点击顺序、预期、实际、日志观察点。入口首页 - 我的 - 备份与恢复 动作点击备份说明信息行 预期出现明确说明或跳转到说明内容 实际点击后没有任何反馈 观察无 toast、无 dialog、无页面跳转提醒能力的问题也要写成路径入口首页 - 我的 - 提醒设置 动作开启提醒设置时间保存 预期系统代理提醒创建成功到点通知 实际页面保存成功但系统调度失败或到点无提醒 观察ReminderSchedulerService 返回 failed / permissionDenied有了路径修复范围就能压住。备份页点击无反馈不需要重做备份服务提醒不触发也不应该先改页面文案而要检查系统提醒发布链路。备份页 InfoRow 案例Project028 的备份页不是单纯显示数据它还承担“解释备份内容、备份位置、自动备份频率”的责任。审核点击到说明项时如果没有反馈就会被认为入口不可用。页面里把信息项动作抽成了稳定类型type BackupInfoAction content | location | frequency;这样做比直接在点击事件里写字符串更稳。后续如果要改文案或增加动作只要扩展联合类型和处理分支不会在多个 UI 节点里散落裸字符串。页面状态保持轻量State showBackupInfo: boolean false; State backupInfoTitle: string ; State backupInfoMessage: string ;这里没有把备份业务塞进页面。页面只保存弹窗展示所需的短生命周期状态备份导出、恢复、快照统计仍然在服务层。最小修复是让信息项具备真实反馈这个问题的最小修复不是重做备份页面也不是新增复杂帮助中心而是让已有信息项的点击动作给出清晰反馈。处理函数集中映射说明内容private showBackupInfo(action: BackupInfoAction): void { const messageMap: RecordBackupInfoAction, string { content: 备份包含卡片、模板选择、主题偏好和提醒设置。, location: 本地快照保存在应用沙箱内系统备份由 BackupExtensionAbility 接管。, frequency: 自动备份会在关键数据变化后刷新最近一次快照。 }; this.backupInfoMessage messageMap[action]; this.showBackupInfo true; }信息行只负责转发动作不承担业务判断InfoRow(备份内容, this.backupContentLabel, content) InfoRow(备份位置, this.backupLocationLabel, location) InfoRow(自动备份, this.backupFrequencyLabel, frequency)组件内部绑定点击.onClick(() { this.showBackupInfo(actionKey); })修完后审核点击路径有明确反馈用户也能理解这几个信息项的含义。这个修复的边界很小不会影响备份导出、恢复和系统 BackupExtensionAbility。提醒问题不能只看页面保存另一个审核问题是提醒。提醒页点击保存后如果页面显示成功但系统代理提醒没有真正发布审核仍然会认为功能不可用。Project028 在这里必须区分两个状态本地提醒设置保存成功 系统代理提醒发布成功只有第一层成功不能给用户一个完整成功的反馈。服务层返回值要能区分scheduled disabled permissionDenied failed页面根据服务层结果显示不同反馈。这样审核附件里如果出现“保存成功但未提醒”可以马上追到是系统调度失败还是页面把失败吞掉了。从错误文案反查服务层Project028 的代理提醒由ReminderSchedulerService负责。页面不直接调用reminderAgentManager.publishReminder()因为这里涉及通知授权、旧提醒清理、提醒数量上限、系统返回 id 和持久化回写。核心入口可以拆成这样async schedule(settings: ReminderSettingsModel): PromiseReminderScheduleResult { if (!settings.enabled) { await this.cancelProjectReminders(settings.systemReminderId); return { status: disabled }; } try { await this.ensureNotificationEnabled(); await this.cancelProjectReminders(settings.systemReminderId); const request this.buildAlarmRequest(settings); const reminderId await reminderAgentManager.publishReminder(request); return { status: scheduled, systemReminderId: reminderId }; } catch (error) { return this.mapScheduleError(error); } }这里的边界很清楚页面只提交设置服务层负责和系统能力交互持久化层只保存最终状态。任何一个环节失败都要转成明确结果。提醒数量上限要先清理再重试审核附件里如果出现类似“提醒数量达到上限”的错误不能只在页面提示用户也不能简单地重复发布。正确处理是先清理本应用旧提醒再尝试重新发布。Project028 会根据当前保存的systemReminderId和系统中仍然有效的提醒一起清理private async cancelProjectReminders(systemReminderId?: number): Promisevoid { const reminderIds: number[] []; if (typeof systemReminderId number systemReminderId 0) { reminderIds.push(systemReminderId); } const reminders await reminderAgentManager.getAllValidReminders(); reminders.forEach((item) { if (this.isProjectReminder(item.reminderRequest)) { reminderIds.push(item.reminderId); } }); for (const reminderId of Array.from(new Set(reminderIds))) { await reminderAgentManager.cancelReminder(reminderId); } }判断是不是本应用提醒也不能只看 id。历史版本、恢复数据、失败重试都可能造成 id 不一致。Project028 同时看groupId、notificationId和标题特征private isProjectReminder(request: reminderAgentManager.ReminderRequest): boolean { return request.groupId REMINDER_GROUP_ID || request.notificationId REMINDER_NOTIFICATION_ID || request.title REMINDER_TITLE; }这种处理方式能覆盖更多审核设备上的历史残留状态。本地验证矩阵修复完成后本地验证不能只跑构建。对审核问题来说至少要覆盖页面动作、系统能力和包构建。备份页 - 信息行可点击 - 点击后有说明反馈 - 备份导出仍可用 - 恢复入口仍可用 提醒页 - 未授权时给出授权反馈 - 开启提醒后返回 systemReminderId - 关闭提醒后取消旧提醒 - 旧提醒残留时能清理后重试构建命令保持和项目交付一致.\hvigorw.bat assembleHap --mode module -p moduleentrydefault提交 AGC 的包还要跑.\hvigorw.bat assembleApp真机验证前先确认设备连接和临时目录可写hdc list targets -v hdc shell echo write_ok /data/local/tmp/codex_write_test cat /data/local/tmp/codex_write_test rm /data/local/tmp/codex_write_test这些命令的作用不一样。assembleHap更适合开发验证assembleApp才是 AGC 上传链路要看的包。AGC 上传后的验证矩阵本地验证结束后还要看 AGC 上的状态。Project028 的发布记录会把下面几个点写清楚packageName: Project028-default-signed.app uploadTime: AGC 包上传时间 versionId: 当前版本 id packageId: 当前绑定包 id reviewStatus: 预审 / 审核中 / 打回只要版本页没有绑定新包就不能说“线上已修复”。只要没有重新提交审核也不能说“审核已恢复”。这些状态必须分开写。 清单如下 本地修复完成可以说 source fixed 新包构建完成可以说 package built AGC 上传完成可以说 package uploaded AGC 绑定完成可以说 version bound 提交预审完成可以说 submitted这种记录方式能防止团队在沟通时把不同阶段混在一起。版本时间线和包哈希审核打回排查里时间线很关键。推荐把时间线写成一行一条而不是散在聊天记录里。 清单如下 2026-06-28 17:52:49 AGC 产生审核报告 2026-06-29 本地定位提醒问题 2026-06-29 构建新的 release app 2026-06-29 AGC 上传并重新绑定版本 2026-06-29 提交预审如果团队里有多人同时处理还可以附上包体大小或哈希Get-FileHash .\build\outputs\default\Project028-default-signed.app -Algorithm SHA256文章里不需要公开真实证书、密码和 Profile 路径但本地交付记录里要保留能追溯到包的证据。不要把本地已修复说成平台已修复审核类问题最常见的误判是语言不严谨。Project028 的交付记录会刻意区分下面几句话 清单如下 代码已修复只代表源码层完成 本地包已构建只代表构建产物完成 AGC 已上传只代表包已进入平台素材库 版本已绑定新包代表当前审核版本指向新包 已提交审核代表平台开始处理新版本 审核通过代表平台结论已更新这些说法看起来啰嗦但能避免复盘时把平台旧状态当成本地问题。回归用例要覆盖旧状态只验证全新安装是不够的。审核设备可能存在旧版本状态、旧提醒、旧备份记录。Project028 的回归用例会覆盖至少三类状态 清单如下 fresh install: 全新安装 upgraded data: 旧版本升级 dirty state: 有残留提醒和旧快照对备份页来说要验证旧快照为空和已有快照两种情况 清单如下 lastBackupTime lastBackupTime 2026-06-29 17:12 lastRestoreTime localSnapshotSize 0对提醒页来说要验证关闭、开启、重新开启、取消后再开启 清单如下 disabled - enabled enabled - disabled enabled - enabled with new time stale systemReminderId - schedule again这样才能覆盖审核机上更真实的状态。常见误判第一类误判是只看页面。页面保存成功不代表系统提醒成功页面显示备份信息也不代表点击入口可用。第二类误判是只看构建。构建通过不代表 AGC 绑定了这个包。第三类误判是只看权限声明。module.json5写了权限不代表 Profile 已经包含对应开放能力。第四类误判是重复上传。上传新包后没有绑定到当前版本审核仍然可能跑旧包。 清单如下 不看附件 - 改错路径 不看版本绑定 - 修了旧问题却等不到新结论 不看系统能力结果 - 页面反馈和实际能力脱节 不看旧状态 - 审核设备复现但本机不复现这些误判都不是技术难点但会明显拖慢交付。交接清单Project028 在审核修复交接时会把清单写成可以逐项勾选的形式 清单如下 - 审核报告时间已记录 - 附件路径已拆成页面动作 - 本地问题已定位到文件 - 修复范围没有扩大 - HAP 验证通过 - APP 构建通过 - AGC 新包已上传 - 版本页已绑定新包 - 已提交审核 - 仍需等待平台结论对外沟通时也按这个清单说状态。这样用户、开发、审核处理人看到的是同一条链路。把审核报告转成任务单审核报告不能只截图保存。Project028 的处理方式是把每一条审核意见转成任务单字段任务单字段要能直接指导开发、验证和重新提交。 清单如下 issueId: 审核问题编号或报告段落 source: AGC 审核报告 / 附件截图 / 录屏 page: 受影响页面 action: 审核员执行的动作 actual: 当前实际结果 expected: 应该达到的结果 owner: 代码归属模块 validation: 关闭问题需要跑的验证例如备份页可以写成 清单如下 page: BackupPage action: tap info row actual: no visible response expected: dialog or clear feedback owner: entry/src/main/ets/pages/BackupPage.ets validation: tap all InfoRow entries, verify dialog content代理提醒可以写成 清单如下 page: ReminderPage action: save enabled reminder actual: local success but system schedule failed expected: service returns scheduled with systemReminderId owner: ReminderSchedulerService.ets validation: permission, publish, cancel, retry after stale id任务单这样写后续不会在“审核说有问题”这种模糊描述里反复沟通。修复范围为什么要尽量小审核修复阶段最怕扩大改动。Project028 的策略是先关闭审核路径再评估是否需要更大重构。备份页点击无反馈只需要补充现有信息项反馈代理提醒调度失败只需要修系统提醒调度链路和失败回写不应该顺手改整个设置页。最小修复可以用三个问题约束 清单如下 这次审核附件点到的是哪个入口 当前最小用户可见缺口是什么 哪个文件能在不破坏其它链路的情况下关闭缺口对备份页来说答案很明确 清单如下 入口备份与恢复页的信息行 缺口点击没有反馈 文件BackupPage.ets对代理提醒来说答案也很明确 清单如下 入口提醒设置页保存动作 缺口页面成功状态和系统调度状态不一致 文件ReminderSchedulerService.ets 页面结果提示这个判断能防止把修复扩大到导航、主题、数据模型等无关模块。修复后要回看用户文案审核问题经常不是单纯的代码错误也可能是文案把状态说错了。比如系统提醒调度失败时如果页面仍然提示“保存成功”审核员和用户都会认为功能结果不可信。更稳的文案应该贴着状态走 清单如下 scheduled: 提醒已开启 disabled: 提醒已关闭 permissionDenied: 请开启通知权限后再试 failed: 系统提醒调度失败请稍后重试如果错误来自提醒数量上限可以更具体 清单如下 系统提醒数量已达到上限已尝试清理本应用旧提醒请重新保存。文案不需要很长但必须避免把失败包装成成功。审核附件里最容易被截到的就是这种状态不一致。关闭问题要有验收证据Project028 的.agent会话记录会把审核修复写成证据而不是只写“已处理”。一条合格记录至少包含 清单如下 Summary: 修复了什么审核路径 Root Cause: 为什么会失败 Files Changed: 改了哪些文件 Validation: 跑了哪些命令和手工路径 Runtime Impact: 用户能看到什么变化 Risks: 哪些状态还依赖平台复核对提醒问题验证结果可以写成 清单如下 hdc preflight: passed assembleHap: passed reminder permission declared: passed publishReminder returns id: passed AGC package bound: pending / passed对备份页点击问题验证结果可以写成 清单如下 BackupPage info row content: passed BackupPage info row location: passed BackupPage info row frequency: passed Manual backup action: unchanged Restore action: unchanged这种记录能给下一次审核复核留下可追踪依据。审核修复不要覆盖用户已有状态审核打回修复时还要特别注意不要为了关闭一个入口问题而破坏用户已有数据。Project028 的备份、提醒、主题和卡片状态都来自本地持久化修复页面反馈时不能顺手清空这些状态。页面修复应该保持下面这些数据不变 清单如下 cards templates theme reminder settings backup snapshots activity logs对备份页 InfoRow 的修复只新增说明反馈不改变备份数据结构 清单如下 before: render info row after: render info row click feedback data schema: unchanged backup export: unchanged restore import: unchanged对提醒链路的修复也不能简单把失败状态清掉。更稳的方式是保留用户设置同时标出系统调度状态 清单如下 enabled: 用户是否希望开启提醒 time: 用户设置的提醒时间 systemReminderId: 系统成功发布后返回的 id lastScheduleError: 最近一次系统调度失败摘要这样即使系统能力暂时失败用户的意图仍然保留下一次授权或清理旧提醒后可以重新调度。回到代码层要看边界有没有变审核问题关闭后还要回看代码边界有没有被破坏。Project028 一直保持页面、服务、持久化分层审核修复也不能把这个边界打乱。合格的边界应该是 清单如下 Page: 处理点击、展示状态、展示反馈 Service: 处理系统能力、业务规则、错误归一化 Repository / persistence helper: 处理数据读写不合格的修复通常是 清单如下 Page 里直接调用系统提醒 API Page 里直接清理所有系统提醒 Page 里散写备份 JSON 拼接 多个页面重复维护同一个状态计数这些写法短期可能关闭一个审核附件长期会让后续审核和维护更难。小结AGC 审核打回不是简单的“改代码再传包”。Project028 的经验是先把问题拆成平台绑定状态、审核附件路径、本地最小修复、包构建、版本绑定和重新提交六个环节。每个环节都有证据才能避免在旧包、旧状态和旧结论里反复打转。对工具型 HarmonyOS 应用来说审核问题往往出在真实交互闭环点击有没有反馈、保存是否等于系统能力成功、旧状态是否能被清理、版本页是否真的指向新包。把这些边界守住审核修复才是可复现、可验证、可交接的工程动作。