从端到云:用 ArkTS + Serverless 跑通鸿蒙待办清单的端云协同
本文以「云同步待办清单」为例,梳理 HarmonyOS 端侧 ArkTS 与华为云 Serverless 后端的协作方式,覆盖登录态、数据同步、离线补偿和部署联调几个关键环节,适合已经掌握 ArkUI 基础、准备把应用从“单机”推进到“端云一体”的开发者。
一、为什么要把待办清单做成端云协同
纯端侧待办应用实现成本很低,但一旦换设备,数据就断了。端云协同要解决的核心问题其实只有三个:
- 身份:同一用户在手机、平板、模拟器上看到同一份数据;
- 一致性:新增、修改、删除操作要能可靠落到云端,并在多端之间同步;
- 弱网可用:断网时仍能记录,恢复网络后自动补偿。
把这三件事拆开,端侧负责交互和本地缓存,云侧负责鉴权、持久化和并发控制,职责就清晰了。
二、整体架构
一个够用且不过度设计的架构如下:
ArkTS / ArkUI 端侧
├─ 登录页 → 获取并保存会话 Token
├─ 任务列表页 → 本地缓存 + 云端拉取
└─ 同步模块 → 轮询 / 手动刷新 / 失败重试
华为云 Serverless 云侧
├─ APIG → 统一入口、鉴权、限流
├─ FunctionGraph → 登录、任务增删改查等云函数
└─ RDS MySQL → users / sessions / tasks 三张表
端侧不直接连数据库,所有请求都经过 APIG;云函数保持无状态,会话信息落库,便于水平扩容。
三、端侧:先把登录态管好
端云协同里最容易返工的地方不是接口,而是登录态。建议在应用启动时做一次会话恢复:
// SessionManager.ets
import preferences from '@ohos.data.preferences';
export class SessionManager {
private static store: preferences.Preferences | null = null;
static async init(context: Context): Promise<void> {
this.store = await preferences.getPreferences(context, 'session');
}
static async saveToken(token: string, expireAt: number): Promise<void> {
await this.store?.put('token', token);
await this.store?.put('expireAt', expireAt);
await this.store?.flush();
}
static async getValidToken(): Promise<string | null> {
const token = await this.store?.get('token', '') as string;
const expireAt = await this.store?.get('expireAt', 0) as number;
if (!token || Date.now() >= expireAt) {
return null;
}
return token;
}
}
几个实践建议:
- Token 不要只放内存,进程被杀后会丢失;
- 过期时间留出 5 分钟余量,避免请求发出时刚好过期;
- 收到 401 时统一清理本地会话并跳转登录页,不要在多个页面各写一套。
四、端侧:列表与同步
任务列表采用“本地缓存优先、云端增量覆盖”的策略。首屏先读本地数据,保证秒开;随后异步拉取云端最新数据。
interface TodoItem {
id: string;
title: string;
priority: number;
dueAt: number;
updatedAt: number;
deleted: boolean;
}
async function pullTasks(since: number): Promise<TodoItem[]> {
const token = await SessionManager.getValidToken();
if (!token) {
throw new Error('SESSION_EXPIRED');
}
const resp = await http.createHttp().request(
`${BASE_URL}/tasks?since=${since}`,
{
method: http.RequestMethod.GET,
header: { Authorization: `Bearer ${token}` }
}
);
return JSON.parse(resp.result as string).items as TodoItem[];
}
同步策略可以分阶段演进:
- 第一版:进入前台时全量拉取,实现简单;
- 第二版:用
updatedAt做增量拉取,减少流量; - 第三版:本地维护待同步队列,弱网时先写本地、联网后按顺序补传。
删除建议使用软删除(deleted 标记),否则多端并发时很容易出现“A 端删了、B 端又把它推回来”的问题。
五、云侧:三张表撑起最小闭环
最小可用的数据模型:
CREATE TABLE users (
id VARCHAR(32) PRIMARY KEY,
phone VARCHAR(20) UNIQUE NOT NULL,
created_at BIGINT NOT NULL
);
CREATE TABLE sessions (
token VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
expire_at BIGINT NOT NULL,
INDEX idx_user (user_id)
);
CREATE TABLE tasks (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
title VARCHAR(200) NOT NULL,
priority TINYINT DEFAULT 0,
due_at BIGINT DEFAULT 0,
updated_at BIGINT NOT NULL,
deleted TINYINT DEFAULT 0,
INDEX idx_user_updated (user_id, updated_at)
);
云函数侧要注意两件事:
- 所有查询必须带
user_id条件,不要只按task_id查询后再在代码里判断归属; - 写操作使用
updated_at做乐观并发控制,更新时带上旧版本号,避免后写覆盖先写。
六、部署与联调清单
在华为云上部署时,建议按下面的顺序验收,能少走很多弯路:
- RDS 白名单确认已放通 FunctionGraph 所在网段;
- APIG 的路由、超时时间和 CORS 配置逐项核对;
- 云函数环境变量中的数据库连接串不要硬编码在代码里;
- 用 curl 先跑通登录、创建、查询、删除四条链路,再接端侧;
- 端侧真机与模拟器分别验证一次弱网和断网恢复。
七、几个容易踩的坑
- 时间戳统一用毫秒:端侧 Date.now() 与数据库字段类型要对齐,避免秒/毫秒混用;
- 轮询不是越多越好:30 秒轮询适合演示,正式产品建议结合页面生命周期,退到后台就停止;
- 错误码要可区分:网络失败、会话过期、业务校验失败要分开处理,否则用户只会看到“加载失败”;
- 不要在前端存数据库凭证:端侧只持有短期 Token,数据库账号只存在于云函数环境变量中。
八、小结
端云协同的难点从来不是“把接口调通”,而是登录态、数据一致性和弱网补偿这三件事能不能形成闭环。先把会话和软删除做扎实,再逐步引入增量同步和离线队列,应用的可维护性会好很多。
如果你的目标是快速验证,建议先从一张 tasks 表、四个接口(登录、列表、创建、删除)开始,跑通之后再扩展优先级、截止时间和多端同步。小闭环跑顺了,后面的功能才有稳定的地基。
【标签】
- 点赞
- 收藏
- 关注作者
评论(0)