HarmonyOS 7+ArkTS:上架前离线关键页面状态合同与空态复核【鸿蒙心迹】
应用能够打开首页,不等于提审版本的所有关键入口在异常网络下都可理解。对用户来说,空白页和“暂时没有数据”几乎一样;对工程团队来说,前者可能是请求失败后没有渲染任何分支,后者才是明确的业务空态。把两者都截图成“无内容”,到了测试环节很难追溯究竟是哪条代码路径走错了。这次做一个小型 ReviewOffline 演示,专门给上架前的内部回归记录使用。样本编号 AUDIT-071,共有 6 条关键页面路径,预期 4 条通过、2 条待复核,总状态 REVIEW_REQUIRED。它不是应用市场审核平台的正式结果,更不能声称符合了全部审核政策;这里只讨论开发者怎样把离线与弱网情况下的入口行为描述清楚。
## 一、先把“离线成功”从“页面正常”里拆出来正常网络下,“订单”页可能显示二十条数据,“搜索”页能返回推荐词,“帮助”页加载远端图文。断网后,这三个页面不一定要有完全相同的降级形式:订单可保留上次缓存并标注更新时间;搜索没有本地索引时应说明暂不可搜索;帮助至少应保留有效的离线联系方式或重试入口。如果全用一个全屏转圈,用户既不知道网络问题,也不知道还能做什么。我更关心的是状态分支有没有被明确写出来,而不是强求每个页面都能离线完成核心服务。产品不提供离线搜索也可以,但必须把按钮的可用性、提示语、重试动作和失败原因安排一致。否则“搜索”页面左上角提示未连接,右下角却保留一个可点的“立即搜索”,两种状态在 UI 里互相否定。这里的六条路径是首页、订单、搜索、收藏、设置、帮助。演示中首页、订单、收藏、设置均有降级内容和明确操作;搜索缺少不可用说明,帮助页的“重试”虽然可见却被禁用。示例统计因此是 PASS=4、REVIEW=2,而不是“通过率 67% 说明审核一定不通过”。平台是否通过审核仍由实际审查、政策与应用整体表现决定。## 二、用同一份页面合同判断状态我把可观察到的页面状态整理成 RouteSnapshot,其中 hasFallback 表示存在用户能理解的离线内容,retryVisible 表示有明确的恢复入口,actionEnabled 则是该入口当前是否可操作。它们不是 HarmonyOS 系统提供的三个字段,而是 Demo 为业务质检定义的数据合同。下面这个纯 ArkTS 函数不去抓取真实设备节点树,也不伪造任何自动化截图 API。它负责处理已经由页面测试层采集或人工复核后的快照。函数输出的是内部诊断结论,因此命名为 PASS 和 REVIEW,不使用“审核通过”这种容易误导的词。tstype AuditFlag = 'PASS' | 'REVIEW';interface RouteSnapshot { id: string; title: string; networkRequired: boolean; hasFallback: boolean; retryVisible: boolean; actionEnabled: boolean;}interface RouteDecision { id: string; flag: AuditFlag; reason: string }function checkOfflineRoute(row: RouteSnapshot): RouteDecision { if (!row.hasFallback) { return { id: row.id, flag: 'REVIEW', reason: 'MISSING_FALLBACK' }; } if (row.networkRequired && (!row.retryVisible || !row.actionEnabled)) { return { id: row.id, flag: 'REVIEW', reason: 'RECOVERY_ACTION_INVALID' }; } return { id: row.id, flag: 'PASS', reason: 'EXPLAINED_STATE' };}判断的先后次序有含义:先确定用户能不能看到可信的失败说明,再判断能不能恢复。当离线内容本身缺失时,只显示一个“重试”按钮仍然不够;用户需要知道为什么要重试。networkRequired 为 false 的页面不必为了得到 PASS 强行添加重试按钮,例如本地设置页就可以独立显示。这个规则并不能识别按钮是否真的发出了请求,也不能保证恢复后数据没有重复写入。它只检查“页面声明的合同是否自洽”。如果实际产品是支付、医疗或敏感数据流程,还要增加权限、数据安全和异常恢复的专门测试,不能拿这里的六条规则替代完整验收。## 三、批量检查不能把未知状态算成通过示例数据固定在一份只读数组中,不从真机抓值;这样正文和配图可以使用完全一致的数字。搜索条目没有备用状态,帮助条目的恢复按钮处于禁用状态,刚好对应两个不同的问题。页面数量、输入字段与结论都能复算。tsconst routes: RouteSnapshot[] = [ { id: 'HOME', title: '首页', networkRequired: true, hasFallback: true, retryVisible: true, actionEnabled: true }, { id: 'ORDER', title: '订单', networkRequired: true, hasFallback: true, retryVisible: true, actionEnabled: true }, { id: 'SEARCH', title: '搜索', networkRequired: true, hasFallback: false, retryVisible: true, actionEnabled: true }, { id: 'FAVORITE', title: '收藏', networkRequired: false, hasFallback: true, retryVisible: false, actionEnabled: false }, { id: 'SETTINGS', title: '设置', networkRequired: false, hasFallback: true, retryVisible: false, actionEnabled: false }, { id: 'HELP', title: '帮助', networkRequired: true, hasFallback: true, retryVisible: true, actionEnabled: false }];const result: RouteDecision[] = routes.map((row: RouteSnapshot) => checkOfflineRoute(row));const passCount: number = result.filter((r: RouteDecision) => r.flag === 'PASS').length;const reviewCount: number = result.length - passCount; // PASS=4 / REVIEW=2同样的数据,每次运行都应该得到 6/4/2,但这只能验证业务函数的确定性,不能作为页面实际可用性的实测数据。团队应把构造数据的用途写进日志与图片说明,例如 source=DEMO,避免测试同事在资料包里误把“通过”当成设备自动巡检结果。真正的验收还要把每条路径绑定到实际测试设备、构建产物和可复现步骤。页面“搜索”失败时的修复动作可能是添加离线提示文案;“帮助”失败时的修复动作则可能是让重试按钮能够触发网络检查。二者都属于 REVIEW,但绝不应该用统一的“网络异常,稍后重试”把全部差异抹掉。备注字段必须告诉开发人员在哪个状态出现什么矛盾。## 四、把复核状态放回页面,但不冒充审核结论如果检测结果只存在终端打印中,产品和测试人员很难从页面找到对应路径。我倾向于把 RouteDecision 显示成一页明确的内部工作台,支持按问题逐条复核。它不是上线后面向普通用户的功能,而是测试开关控制的演示区域;开关是否随 release 产物关闭,应有单独的构建检查。下面的 UI 代码演示如何把结果映射成可读状态,并把“继续提交”按钮设为禁用。这里 .enabled 是 ArkUI 的普通交互属性;它只能禁用当前控件,不会替代开发者实施发布权限管理或后端审核操作。ts@Entry@Componentstruct OfflineAuditPage { @State private list: RouteDecision[] = routes.map((r: RouteSnapshot) => checkOfflineRoute(r)); @State private title: string = 'AUDIT-071 · REVIEW_REQUIRED'; @State private pending: number = 2; // 与本例固定快照相符;重新检查时需重新计算 build() { Column({ space: 16 }) { Text(this.title).fontSize(22).fontWeight(FontWeight.Bold) ForEach(this.list, (row: RouteDecision) => { Row() { Text(row.id).width(110) Text(row.flag + ' · ' + row.reason) .fontColor(row.flag === 'PASS' ? Color.Green : Color.Orange) }.width('100%').padding(12) }, (row: RouteDecision) => row.id) Button('继续提交').enabled(this.pending === 0) Text('来源:DEMO · 待人工复核') }.width('100%').padding(20) }}这段示例默认六个路径是同一快照。如果未来增加多个分发地区、登录与游客两种身份、不同系统字体大小,测试矩阵必须把这些维度作为数据输入;不能只增加一列显示标签,却依旧复用相同的 hasFallback。尤其是要让 PASS 有证据指向:哪个构建、哪种网络条件、哪张截图、哪个测试账号能重现。
## 五、截图与日志如何互相证明,而不是互相替代本轮的 DevEco 示意图中,左侧树只保留 OfflineAuditPage.ets、RouteRules.ets、SnapshotCases.ets,代码区域展示 checkOfflineRoute,底部示例日志固定写为 AUDIT-071 routes=6 pass=4 review=2 source=DEMO。右侧模拟器显示两个待复核入口。图片的用途是说明排查链路,不是要让读者相信这些日志真的由设备吐出。正式回归时,我会让每一条 REVIEW 都有“复现路径”和“修复后复验”两组证据。比如搜索页:网络断开后从首页进入搜索,预期看到“当前无法搜索”的明确说明与可执行动作;如果界面只有白板,就记录 MISSING_FALLBACK。帮助页:离线说明已经出现,但恢复入口无法点,则记录 RECOVERY_ACTION_INVALID。它们对应不同修复负责人与回归步骤。从截图里看见一个按钮不等于按钮可点击,从 HiLog 里看见 PASS 也不等于当前构建已经通过人工复核。正因为两种证据各有局限,才要把记录写成“截图说明哪一个状态,代码解释如何判定,测试步骤说明怎样复现”。图片做得再像 IDE,也不能冒充实际构建成功。
## 六、交付前还要收紧三处边界首先,内部状态不代表市场审核状态。华为应用市场有独立的发布流程和审核指南,本文无法替代政策核对,也不能根据一个演示分数判断是否会被通过。团队应当在准备提交版本时查阅最新官方政策和 AppGallery Connect 控制台说明,确认资料、权限和功能可达性等更广的要求。其次,业务快照不等于真实抓取。上面的输入数组是人工构造,适合作为单元测试与界面说明;正式自动化应从真实测试环境采集有来源、有时间、有构建哈希的状态,再调用相同的纯函数。如果无法证明按钮是否可用,应将结果记作待确认,而不是默认通过。最后,离线可解释不等于离线功能完整。某些服务没有网络就无法执行,允许中断,但页面要明确告诉用户发生了什么、还能做什么、何时可以恢复。把降级边界说清楚,比用一个大而空的“成功率”更有工程价值。对于 AUDIT-071,目前应保持 REVIEW_REQUIRED:搜索与帮助两条路径的合同没有满足,内部“继续提交”按钮禁用。这是示例规则的推导结论,不是审查结果。技术资料: 华为应用市场发布与审核入口;AppGallery Connect 简介;HarmonyOS 官方文档中心。本文未进行真机网络切换、官方审核或完整 SDK 构建。
更多推荐




所有评论(0)