羽毛球学习 HarmonyOS 方案续篇(26):登录状态与受保护操作提示封装

发布时间:2026/7/25 14:55:48

羽毛球学习 HarmonyOS 方案续篇(26):登录状态与受保护操作提示封装 一、基线不是空白但统一守卫仍未实现应用已经把登录状态、昵称、用户标识和头像镜像到全局状态并通过 Preferences 恢复登录后收藏、关注、历史记录会切换到账号命名空间。登录页也会在用户未同意协议时阻止账号按钮继续执行。这些是可以确认的现有边界。缺少的是“受保护操作”的统一入口收藏是否允许游客使用、下载是否必须登录、某项系统能力被拒绝后怎样提示、登录完成后是否恢复原动作目前没有一个可复用合同。本文只设计这层守卫不把已有登录页扩大描述为完整权限框架也不声称下载能力已经实现。当前能力待补能力明确不做登录态持久化、账号空间切换统一能力判定与提示自建账号后端协议勾选、账号登录回调登录后恢复原操作绕过系统授权游客数据空间并发请求合并把密码写入本地二、会话快照必须一次读完页面不应分别读取isLoggedIn、userId 和昵称后自行推断因为状态切换期间可能组合出矛盾视图。会话仓库对外提供一个不可变快照包含阶段、账号信息和更新时间。启动恢复未完成时是restoring不能误判为游客退出过程中是signingOut新的受保护动作暂缓。export type SessionPhase | restoring | guest | authenticated | signingOut export interface SessionSnapshot { phase: SessionPhase userId?: string nickname?: string avatarUri?: string updatedAt: number } export interface SessionRepository { current(): SessionSnapshot subscribe(listener: (value: SessionSnapshot) void): () void restore(): PromiseSessionSnapshot }页面只订阅快照。登录写入、账号空间重载和快照发布要形成顺序先持久化身份再加载对应空间最后发布authenticated避免 UI 已显示登录成功但收藏仍来自游客空间。三、能力判定与系统权限请求必须分离“是否需要登录”是业务能力规则“能否访问相册或通知”是系统权限状态两者不能混在一个布尔值里。判定器先给出缺失条件执行器再决定是否展示登录提示或调用系统授权。这样单元测试无需真的拉起系统弹窗。export type ProtectedAction | favorite | follow | offline_download | push_reminder | export_image export interface ActionRequirement { loginRequired: boolean systemPermissions: string[] guestFallback?: local_only | read_only } export const REQUIREMENTS: RecordProtectedAction, ActionRequirement { favorite: { loginRequired: false, systemPermissions: [], guestFallback: local_only }, follow: { loginRequired: true, systemPermissions: [] }, offline_download: { loginRequired: true, systemPermissions: [] }, push_reminder: { loginRequired: true, systemPermissions: [notification] }, export_image: { loginRequired: false, systemPermissions: [photo_write] } }结果含义页面可执行动作allowed条件齐全执行业务动作login_required缺登录态登录、取消或游客降级permission_required系统权限未申请解释用途后申请denied_permanently用户拒绝且不再询问打开设置或取消restoring会话尚未稳定等待恢复不弹重复提示四、守卫返回结构化结果不直接导航若守卫内部直接跳登录页调用方无法区分用户取消、登录失败或权限拒绝。更稳妥的设计是返回结构化结果由页面根据当前交互环境选择对话框、底部面板或行内提示。export type GuardResult | { kind: allowed } | { kind: login_required; resumeToken: string } | { kind: permission_required; permissions: string[] } | { kind: denied_permanently; permission: string } | { kind: temporarily_unavailable; reason: string } export interface ActionGuard { check(action: ProtectedAction, contextId: string): PromiseGuardResult resume(token: string): PromiseGuardResult cancel(token: string): void }resumeToken只包含动作类型和业务对象 id不包含密码、授权码或其他敏感信息并设置短有效期。登录完成后重新执行判定而不是无条件执行原动作因为等待期间对象可能已经失效。五、提示模型要说清原因和下一步同一个业务结果可以在手机上用底部弹层在平板上用侧边提示但文案合同应一致说明为什么需要登录或权限、继续会发生什么、取消后是否仍可使用游客能力。系统权限申请之前先展示业务用途用户拒绝后不循环拉起。export interface GuardPrompt { title: string message: string primaryAction: login | request_permission | open_settings secondaryAction: cancel | use_guest_mode destructive: boolean } export function promptFor(result: GuardResult): GuardPrompt | undefined { if (result.kind login_required) { return { title: 登录后继续, message: 该操作会写入账号空间登录完成后可返回继续。, primaryAction: login, secondaryAction: cancel, destructive: false } } return undefined }六、并发点击只保留一个提示和一个待恢复动作用户快速点击两次下载或多个卡片同时请求同一权限时不能叠出多个弹窗。协调器以action contextId作为键合并进行中的守卫全局同一时刻只展示一个阻断提示。新的不同动作进入队列前一个动作取消后再决定是否继续。待恢复动作要具备幂等性。收藏等切换操作应在恢复时重新读取当前状态下载任务则按资源 id 去重。登录页返回但用户未登录时结果是取消不显示“失败”。七、失败与降级路径会话恢复失败时进入游客空间并给出一次非阻断提示账号空间加载失败时不能发布已登录完成状态系统权限接口异常时返回暂不可用不猜测用户已拒绝永久拒绝后提供设置入口应用切到后台时取消尚未展示的提示但保留可安全恢复的 token。故障默认降级禁止行为Preferences 读取失败游客只读或本地空间伪造已登录登录成功但账号数据加载失败停留登录中并允许重试混用游客与账号数据权限请求接口异常暂不可用当作永久拒绝恢复 token 过期回到原页面自动执行旧动作八、实施与验收证据第一步建立会话快照并替换页面中的多字段推断第二步实现纯函数能力表和 GuardResult第三步接入统一提示组件第四步支持登录返回后的安全恢复第五步再连接真实系统权限并记录授权结果。验收条件包括启动恢复期间不闪现游客提示同一动作连点只出现一个提示未登录收藏按既定游客策略工作受保护下载只进入登录引导且不会创建任务登录完成后只恢复一次且重新校验对象永久拒绝后不重复拉起系统授权退出登录时账号数据不会泄漏到游客空间。后续证据需要覆盖冷启动、登录/退出、快速连点、拒绝授权、后台返回和账号切换录屏与日志。参考HarmonyOS 应用权限开发指导。九、总结登录状态封装的价值不在少写几个if而在让身份恢复、业务条件、系统权限和用户提示各自有明确职责。守卫只返回结果页面决定呈现登录或授权完成后重新判定才能避免重复弹窗、旧动作误执行和账号空间混用。

相关新闻