离线能力篇
定义应用在无网络环境下的行为规范
概述
钱包应用 MUST 具备离线能力,确保用户在网络不可用时仍能:
- 查看缓存的资产信息
- 准备交易(离线签名)
- 访问关键设置
离线状态检测
网络状态定义
| 状态 | 说明 | 检测方式 |
|---|---|---|
| online | 网络正常可用 | navigator.onLine + 心跳检测 |
| offline | 完全无网络 | navigator.onLine = false |
| degraded | 网络不稳定 | 请求超时率 > 50% |
| limited | 部分服务可用 | 特定 API 可达 |
检测规范
- MUST 监听
online/offline事件 - MUST 实现心跳检测(每 30s 检测一次)
- SHOULD 区分"无网络"和"服务不可用"
- SHOULD 检测网络质量(延迟、丢包)
状态机
online
│
┌──────┴──────┐
│ │
▼ ▼
degraded ───► offline
│ │
└──────┬──────┘
│
▼
online离线数据缓存
缓存层级
| 层级 | 数据类型 | 存储位置 | 有效期 |
|---|---|---|---|
| L1 | 钱包数据、密钥 | 加密存储 | 永久 |
| L2 | 用户设置、偏好 | 本地存储 | 永久 |
| L3 | 资产余额 | 本地存储 | 缓存+时间戳 |
| L4 | 交易历史 | 本地存储 | 最近 100 条 |
| L5 | 链配置、代币元数据 | 本地存储 | 24 小时 |
缓存规范
L1 关键数据(永久存储)
| 数据 | 离线可用 | 说明 |
|---|---|---|
| 加密助记词 | ✓ | 可离线签名 |
| 钱包列表 | ✓ | 可查看所有钱包 |
| 地址列表 | ✓ | 可查看/复制地址 |
L3 资产数据(带时间戳缓存)
CachedBalance {
address: string
chainId: string
balance: string
timestamp: number // 缓存时间
expiresAt: number // 过期时间
isStale: boolean // 是否过期
}显示规范:
- MUST 显示缓存时间("5 分钟前")
- MUST 过期数据标记为"可能已过期"
- SHOULD 使用不同视觉样式区分新旧数据
离线功能矩阵
功能可用性
| 功能 | 在线 | 离线 | 降级模式 |
|---|---|---|---|
| 查看钱包列表 | ✓ | ✓ | - |
| 查看地址 | ✓ | ✓ | - |
| 复制地址 | ✓ | ✓ | - |
| 查看余额 | ✓ | 缓存 | 显示缓存时间 |
| 查看交易历史 | ✓ | 缓存 | 显示缓存条数 |
| 发起转账 | ✓ | 准备 | 离线签名,待上线广播 |
| 扫描二维码 | ✓ | ✓ | 解析但不验证 |
| 修改设置 | ✓ | ✓ | 本地保存 |
| 查看助记词 | ✓ | ✓ | 本地解密 |
| 创建钱包 | ✓ | ✓ | 本地生成 |
完全不可用功能
| 功能 | 原因 | 离线提示 |
|---|---|---|
| 实时余额 | 需要链上查询 | "显示缓存数据" |
| 广播交易 | 需要节点连接 | "交易已签名,恢复网络后发送" |
| 交易确认状态 | 需要链上查询 | "无法获取最新状态" |
| 质押操作 | 需要链上交互 | "需要网络连接" |
离线签名
流程规范
用户发起转账(离线)
│
▼
验证本地缓存的 nonce
│
├── 有缓存 ──► 使用缓存 nonce + 1
│
└── 无缓存 ──► 提示"需要网络获取 nonce"
或允许用户手动输入
│
▼
构建交易对象(本地)
│
▼
解密私钥,签名交易
│
▼
存储签名交易到待发送队列
│
▼
显示"交易已准备,恢复网络后自动发送"待发送队列
PendingTransaction {
id: string
signedTx: string // 签名后的交易
chainId: string
createdAt: number
expiresAt: number // 过期时间(建议 24h)
status: 'pending' | 'broadcasting' | 'sent' | 'failed' | 'expired'
retryCount: number
error?: string
}队列管理规范
- MUST 网络恢复后自动尝试广播
- MUST 显示队列中的待发送交易
- MUST 交易过期后提示用户(nonce 可能已失效)
- SHOULD 支持取消待发送交易
- SHOULD 广播失败后自动重试(最多 3 次)
离线 UI 规范
全局提示
┌─────────────────────────────────────┐
│ ⚠️ 当前离线 - 部分功能受限 │
│ [点击查看详情] │
└─────────────────────────────────────┘规范要求:
- MUST 离线时显示全局提示条
- MUST 提示条不遮挡核心内容
- SHOULD 提供"查看离线功能"入口
- SHOULD 网络恢复后自动消失
数据新鲜度指示
| 状态 | 视觉表现 | 说明 |
|---|---|---|
| 实时 | 正常显示 | < 1 分钟 |
| 较新 | 灰色时间戳 | 1-10 分钟 |
| 过期 | 黄色警告 + 时间戳 | > 10 分钟 |
| 很旧 | 红色警告 | > 1 小时 |
功能禁用状态
不可用功能 MUST 明确标识:
┌─────────────────────────────────────┐
│ [发送] (需要网络) │
│ └─ 灰色禁用 + 提示文字 │
└─────────────────────────────────────┘数据同步
恢复在线后的同步
网络恢复
│
├─► 刷新余额(优先级: 高)
│
├─► 广播待发送交易(优先级: 高)
│
├─► 同步交易历史(优先级: 中)
│
└─► 更新链配置(优先级: 低)冲突处理
| 冲突类型 | 处理策略 |
|---|---|
| 设置冲突 | 本地优先(用户最近修改) |
| 交易 nonce 冲突 | 提示用户重新发起 |
| 余额不一致 | 服务端优先(以链上为准) |
同步状态
SyncStatus {
lastSyncTime: number
isSyncing: boolean
pendingChanges: number
syncErrors: SyncError[]
}存储管理
存储配额
| 数据类型 | 建议配额 |
|---|---|
| 钱包数据 | 无限制 |
| 交易历史 | 最近 100 条/地址 |
| 缓存数据 | 最大 50MB |
清理策略
- SHOULD 超过配额时清理最旧的缓存
- MUST NOT 自动清理钱包数据
- SHOULD 提供手动清理缓存入口
测试要求
离线测试场景
| 场景 | 验证点 |
|---|---|
| 启动时离线 | 能正常进入应用,显示缓存 |
| 使用中断网 | 立即显示离线提示 |
| 离线发起转账 | 能完成签名,进入待发送 |
| 恢复网络 | 自动同步,广播待发送 |
| 长时间离线 | 缓存过期正确标识 |
本章小结
- 钱包必须具备离线核心功能
- 缓存数据需要时间戳和过期标识
- 离线签名 + 待发送队列支持延迟广播
- 网络恢复后自动同步和广播
- UI 需要清晰的离线状态指示