做上架前体验复核时,入口能点进去只是最浅的一层。更容易漏掉的是用户在一次可选功能提示中点了“暂不授权”之后,页面有没有正常退出、主功能还能不能使用,以及之前已经出现的按钮会不会被错误地一起禁用。这样的遗漏不需要复杂的新系统接口才能暴露,往往是业务状态机自己把“拒绝一个可选功能”和“拒绝整个应用”写成了同一个状态。本文采用 ChoicePath 小样例,演示批次 PATH-208。场景是一款可以不登录、不上传图片也能浏览商品的应用:浏览、收藏清单、帮助中心是三条可达路径;“添加相册图片”是可选入口,只有用户完成实际授权后才允许进入。示例初始状态 DECLINED,于是得到 3 条可达路径、1 条受限入口,内部检查标签 REVIEW_NAV_OK。这是产品侧预先定义的业务合同,既不是系统权限的真实授予结果,也不是华为应用市场的审核通过结论。## 一、拒绝之后不应该产生什么副作用先画四个入口,再讨论权限。浏览商品不依赖相册,收藏清单在此 Demo 中只保存文字条目,帮助中心是本地说明页面;只有添加相册图片需要另行访问媒体能力。因此可选授权被拒绝后的正确状态不是“全部禁止”,而是三条基础路径仍可导航,图片添加按钮提示“需要用户授权”。如果 UI 还停留在不可关闭的授权弹层,或者返回时把浏览页面的状态清空,这都是本例需要暴露的缺陷。这里刻意不用隐私合规口号替代技术检查。某个业务功能是不是可以无需授权、实际权限何时申请、拒绝以后能否再次发起系统授权,必须结合真实业务、适用规则和目标 SDK 的权限 API 分别决定。本文按钮中所谓“暂不授权”只改变演示业务决策,没有请求系统相册权限;若把演示中的 GRANTED 状态直接当成操作系统的授权凭证,就会引入新的错误。UI 上也要区分 NOT_ASKED、DECLINED、GRANTED:前者尚未做选择,第二种已经明确表示暂不使用可选功能,第三种才意味着适配层确认具有所需的合法条件。三种状态不能简化成“false = 无法使用应用”。在真实工程里,还要加入权限被系统回收、用户改设置、返回前台重新查询等状态,但为了让示例精确,本文限定为一个业务复核场景。## 二、先写纯函数,再把状态交给 ArkUI问题: 页面里每个按钮都写一套 if 判断,会让页面间的授权边界不一致。先把四条路由是否可用变成一个清晰的纯函数。它不调用系统,不持有页面,也不决定系统授权,只根据传入的、已由上层验证的业务决策给出入口合同。arktstype AccessDecision = 'NOT_ASKED' | 'DECLINED' | 'GRANTED';interface RouteFlags { browse: boolean; saved: boolean; help: boolean; photoAdd: boolean;}function deriveRoutes(decision: AccessDecision): RouteFlags { return { browse: true, saved: true, help: true, photoAdd: decision === 'GRANTED' };}对于 DECLINED,前三个字段是 true,photoAdd 是 false,因此“3/4”是规则预期,不是运行性能数据。真正应用里要按业务检查 saved 是否需要登录、help 是否依赖网络,再分别增加自己的条件,不要机械复制示例。这里将“拒绝可选相册功能”与“允许基础页面导航”分离,目的正是避免过大的权限开关挟持无关页面。另外,RouteFlags 只表达是否可进入,不能表达该页面内所有操作必然成功。例如进入帮助中心以后,如果网络不可用,需要显示离线提示;浏览页面有缓存数据,也不代表订单一定可提交。路由可达性是上架前体验检查的一层,不能替代异常网络、异常登录或系统权限回收测试。## 三、记录一次操作决定,而不是记录用户信息问题: 调试时容易把“拒绝可选功能”的一瞬间变成一条空泛日志。更好的方式是只记录决策、批次与四条路径的布尔值,不打印照片 URI、账号、设备标识等无关数据。下面的函数生成只读快照,既方便前端显示,也方便把演示用例交给后续手动复核。arktsinterface RouteSnapshot { caseId: string; decision: AccessDecision; accessible: number; blocked: number; label: string;}function makeSnapshot(caseId: string, decision: AccessDecision): RouteSnapshot { const gates = deriveRoutes(decision); const states: boolean[] = [gates.browse, gates.saved, gates.help, gates.photoAdd]; const accessible = states.filter((item: boolean) => item).length; return { caseId, decision, accessible, blocked: states.length - accessible, label: accessible >= 3 ? 'REVIEW_NAV_OK' : 'NEED_REVIEW' };}````REVIEW_NAV_OK` 是这个 Demo 自定义的标签,只代表预设的三条基础路径没有因为可选授权被拒而一起关闭。它既不保证页面内交互完美,也不等于任何监管机构或平台的正式认可。对于其他应用,三条路由可能远远不够,校验名单必须来自真实用户任务和发布前测试方案。`caseId` 只用来串联演示记录,避免用手机号之类的个人信息当任务编号。示例快照为 `PATH-208 / DECLINED / accessible=3 / blocked=1 / REVIEW_NAV_OK`。如果在真机测试时看到四个入口都能点击,需要再分辨第四个按钮是否只是引导用户授权,还是绕过权限直接访问受保护资源。不能以“可点”为“可用”,也不能以“不可点”为“已充分告知”。这样的语义差异应写在用例里,而不是留给审查人员猜。![](https://i-blog.csdnimg.cn/direct/d056258a01104a2a8c55b081847c3586.png)## 四、界面恢复要由同一份状态驱动下面只演示 ArkUI 的 `@State`、`Button`、`.onClick()` 和 `.enabled()` 如何将业务决策应用到页面。示例采用一个可见的“暂不授权”按钮来模拟用户决策,**没有实际调用系统权限请求或图库选择接口**。实际开发必须在权限适配层核实授权结果后才传给 `deriveRoutes`,不能通过普通按钮点击把 `decision` 伪造成系统已授权。arkts@Entry@Componentstruct ChoicePathPage { @State decision: AccessDecision = ‘DECLINED’; private canBrowse(): boolean { return deriveRoutes(this.decision).browse; } private canPhotoAdd(): boolean { return deriveRoutes(this.decision).photoAdd; } build() { Column({ space: 16 }) { Text(‘PATH-208 · 上架前路径复核’).fontSize(20) Text(可选授权状态:${this.decision}) Button(‘暂不授权(业务演示)’) .onClick(() => { this.decision = ‘DECLINED’; }) Button(‘继续浏览’).enabled(this.canBrowse()) Button(‘添加相册图片’).enabled(this.canPhotoAdd()) Text(‘基础路径可达 3 / 可选入口受限 1’) }.padding(24) }}```代码只列出两个有代表性的按钮,收藏和帮助路径根据同一个 RouteFlags 规则在实际页面添加。需要注意,.enabled(false) 只是禁用一个界面入口,不是安全边界;真正访问媒体数据前,还必须执行目标 API 要求的权限验证。若外部跳转、快捷入口或其他 Ability 绕开了当前按钮,仍不能获得未经许可的资源。返回时不应该强制把 DECLINED 重置成 NOT_ASKED,除非业务明确要求重新展示可选说明。否则用户每次进入都被重复打断,即使主路径 technically 可以访问,体验也没有通过。与之相对,系统实际授权若在应用后台被收回,业务层必须同步重新判定,而不能只依赖上一次的 @State。页面生命周期、权限回调和导航状态分别属于不同责任范围。## 五、让四条路径都留下可复核的去向图片演示的是 PATH-208 的拒绝场景。三条基础路径仍显示“可进入”;“添加相册图片”被标记为“需用户授权”,底部保留“继续浏览”,状态标签为 REVIEW_NAV_OK。这张图片是按业务合同绘制的示意稿,不是应用市场真实截图,也不是用户已经在设备上完成授权测试的证据。把它转成正式发布前复核时,建议将“初次进入 → 点击暂不授权 → 返回主页面 → 分别进入浏览、收藏和帮助 → 再打开图片入口”写成单独路径,并加入后台返回、系统权限撤销、冷启动与语言切换等补充用例。运行记录应写清应用包版本、目标 SDK、设备形态以及实际页面状态,不能把这篇文章里的示例时间当成测试结果。官方 AppGallery Connect 提供发布前测试与检测手段,但并没有赋予这个 Demo 的 REVIEW_NAV_OK 任何审核资格。还有一个常被忽略的边界:授权拒绝提示本身也要可退出。用“先同意才能关掉”的浮层保证了表面转化,却破坏了可选功能的语义。技术上应让返回路径和可选功能禁用各司其职;设计上则要说明为什么图片功能暂时不可用,以及如何由用户主动重新尝试。至于哪些功能必须授权才能提供服务,应依据真实业务和最新平台要求另外评估,而不是拿这个四路由示例当作标准答案。这篇文章的结果并不复杂:拒绝一个可选入口,不应把无关的三个主路径一起拒绝。把状态枚举、路由合同和演示页面三者对应起来,才能把上架前复核从“点一遍看看”变成可重复检查的业务行为。这里没有虚构真实审核反馈或运行截图;交付后仍需在正式 SDK、系统权限能力和不同设备形态上逐项验证。官方参考: ArkUI Button 开发文档;ArkUI @Watch 与 @State 状态示例;AppGallery Connect 简介与发布前服务。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐