【鸿蒙心迹】端云协同开发实战:让数据在端和云之间无缝流动

摘要:本文系统讲解鸿蒙端云协同开发。先建立整体认知,说明 Cloud DB、Cloud Function、Cloud Storage 三件套的分工与适用边界;再拆解 Cloud DB 的"端云双写+自动同步"机制、数据模型配置要点与四种冲突解决策略;最后以端云协同笔记应用为例,完整走通 AGC 数据模型配置、端侧初始化、读写数据、同步策略与离线处理流程,并总结 schema 路径、字段类型、冲突覆盖、权限配置等常见坑的排查方法。

"端云协同"这个词在华为的文档里出现频率极高,但到底协同什么、怎么协同,文档里讲得云里雾里。我第一次做端云协同开发时,以为就是普通的"前端+后端"模式,后来才发现鸿蒙的端云协同是一套完整的体系——Cloud DB、Cloud Function、Cloud Storage,三个组件各有分工,配合端侧SDK实现数据的自动同步和离线可用。最让人头疼的是Cloud DB的数据模型配置,配错一个字段类型同步就报错,而且错误信息极其模糊。

如果你有鸿蒙应用开发基础,想让你的应用支持云端数据同步和离线可用,但对端云协同体系不熟悉,这篇正好适合你。读完后你会知道:端云协同的三件套各自的作用、Cloud DB的数据同步机制、完整的端云协同开发流程。

本文分三层来讲:第一层建立对端云协同的整体认知;第二层拆解Cloud DB的同步原理和配置方法;第三层是完整的实战落地和踩坑排错。

入门认知:端云协同到底"协"了什么

一句话定义

端云协同是鸿蒙提供的端云一体化开发能力——应用在端侧通过SDK直接读写云端数据,系统自动处理同步、冲突解决和离线缓存,开发者不需要自己搭建后端服务和同步逻辑。

打个比方:传统开发就像自己开快递公司——建仓库、雇快递员、规划路线、处理丢件;端云协同就像用顺丰——你只管把包裹交给顺丰,运输、仓储、配送全由他们处理,你只关心寄什么和收什么。

端云协同 vs 传统前后端

对比维度传统前后端端云协同
后端搭建自己搭服务器+数据库无需搭建,云端即服务
数据同步自己写同步逻辑SDK自动同步
离线支持自己实现本地缓存Cloud DB自动缓存
冲突解决自己写冲突处理系统自动解决
扩展性自己扩容云端自动扩容

表1:传统前后端与端云协同对比

全景图示

端云协同

Cloud DB

Cloud Function

Cloud Storage

端侧SDK

云端数据库

自动同步

云端函数

业务逻辑

文件存储

端侧上传/下载

图2:端云协同三件套架构

三件套各自分工

组件作用类比典型场景
Cloud DB结构化数据存储与同步数据库用户数据、配置、记录
Cloud Function云端业务逻辑执行服务器API数据校验、聚合计算
Cloud Storage文件存储文件服务器图片、视频、文档

表2:端云协同三件套分工

适用边界

端云协同适合:需要多端数据同步的应用、需要离线可用的应用、不想自建后端的轻量应用。不适合:需要高度定制化后端逻辑的复杂应用、对数据存储位置有严格合规要求的场景。

下面用一张决策图帮你快速判断自己的项目是否适合端云协同:

是

否

是

否

是

否

是

否

项目需求

需要多端数据同步?

需要离线可用?

传统本地存储即可

需要高度定制后端逻辑?

端云协同可选

自建后端更合适

有严格数据合规要求?

推荐端云协同

图1:端云协同适用性判断

进阶原理:Cloud DB的同步机制

Cloud DB的数据同步模型

Cloud DB的核心是"端云双写+自动同步":

CloudDBLocalDBAppCloudDBLocalDBApp离线时数据存在本地双向同步+冲突解决写入数据(端侧)立即返回成功自动同步(网络恢复后)下发云端变更

图3:Cloud DB端云同步时序

数据模型配置

Cloud DB的数据模型在AGC(AppGallery Connect)控制台中配置,定义后导出schema文件供端侧使用:

配置项说明常见坑
对象类型名数据表名必须和端侧代码一致
字段名属性名大小写敏感
字段类型数据类型端侧类型必须匹配
主键唯一标识必须有一个主键
索引查询优化字段常用查询字段建索引
权限读写权限控制默认只有创建者可读写

表3:Cloud DB数据模型配置项

[注意] 字段类型一旦配置并发布,就不能修改!如果需要改字段类型,只能创建新的对象类型。这是最大的坑之一。

同步冲突解决策略

当端侧和云端同时修改同一条数据时,冲突如何解决?

策略含义适用场景
云端优先云端数据覆盖端侧需要服务端权威的场景
端侧优先端侧数据覆盖云端离线编辑优先的场景
时间戳优先最后修改的为准大多数通用场景
自定义开发者自定义逻辑需要业务逻辑判断

表4:冲突解决策略

冲突解决的整体判断流程如下:

是

否

云端优先

端侧优先

时间戳优先

端侧与云端同时修改

是否配置自定义策略?

执行自定义冲突逻辑

采用哪种内置策略?

云端数据覆盖端侧

端侧数据覆盖云端

比较修改时间,保留最新

同步完成

图4:同步冲突解决流程

常见误区

误区1:把Cloud DB当普通数据库用

Cloud DB不是关系型数据库,不支持JOIN、复杂查询。它是面向移动端的轻量级同步数据库,查询能力有限。复杂查询应该用Cloud Function在云端处理。

误区2:不配置权限就用

默认权限是"只有创建者可读写",意味着用户A的数据用户B完全看不到。如果需要数据共享(比如团队协作),必须在AGC控制台配置权限规则。

高级应用:从零实现一个端云协同笔记应用

实战步骤

第一步:在AGC控制台配置数据模型

在AppGallery Connect中创建Cloud DB数据模型:

{
  "objectTypeName": "Note",
  "fields": [
    { "fieldName": "id", "fieldType": "String", "isPrimaryKey": true },
    { "fieldName": "title", "fieldType": "String", "isNullable": false },
    { "fieldName": "content", "fieldType": "String", "isNullable": true },
    { "fieldName": "createTime", "fieldType": "Date", "isNullable": false },
    { "fieldName": "updateTime", "fieldType": "Date", "isNullable": false },
    { "fieldName": "userId", "fieldType": "String", "isNullable": false }
  ],
  "indexes": [
    { "indexName": "userId_index", "indexList": ["userId"] }
  ],
  "permissions": [
    { "role": "Creator", "read": true, "write": true },
    { "role": "AllUsers", "read": false, "write": false }
  ]
}

导出schema文件后放到端侧项目的 resources/rawfile 目录下。

第二步:端侧初始化Cloud DB

import { cloudDatabase } from '@kit.CloudFoundationKit'

let cloudDB: cloudDatabase.CloudDB
let noteZone: cloudDatabase.CloudDBZone

async function initCloudDB(): Promise<void> {
  // 1. 初始化Cloud DB
  let config = new cloudDatabase.CloudDBZoneConfig({
    zoneName: 'NoteZone',
    schemaUrl: 'resources/rawfile/NoteSchema.json'
  })
  // 2. 打开Zone
  cloudDB = await cloudDatabase.openCloudDBZone(config)
  // 3. 注册同步监听
  cloudDB.on('dataChange', (change) => {
    // 云端数据变更通知
    if (change.type === cloudDatabase.ChangeType.UPSERT) {
      this.onNoteUpserted(change.data)
    } else if (change.type === cloudDatabase.ChangeType.DELETE) {
      this.onNoteDeleted(change.data)
    }
  })
}

第三步:端侧读写数据

// 插入笔记
async function addNote(title: string, content: string): Promise<void> {
  let note: Note = {
    id: generateUUID(),
    title: title,
    content: content,
    createTime: new Date(),
    updateTime: new Date(),
    userId: getCurrentUserId()
  }
  await cloudDB.upsert(note)
  // upsert会自动触发同步到云端
}

// 查询笔记
async function queryNotes(): Promise<Note[]> {
  let condition = new cloudDatabase.CloudDBZoneQuery(Note)
    .equalTo('userId', getCurrentUserId())
    .orderByDesc('updateTime')
  let result = await cloudDB.query(condition)
  return result.snapshotObjects
}

// 更新笔记
async function updateNote(note: Note): Promise<void> {
  note.updateTime = new Date()
  await cloudDB.upsert(note)
  // 自动同步更新到云端
}

// 删除笔记
async function deleteNote(noteId: string): Promise<void> {
  let condition = new cloudDatabase.CloudDBZoneQuery(Note)
    .equalTo('id', noteId)
  await cloudDB.delete(condition)
}

第四步:配置同步策略

// 设置同步策略
let syncConfig: cloudDatabase.SyncConfig = {
  mode: cloudDatabase.SyncMode.CLOUD_SYNC_MODE_AUTO,
  conflictPolicy: cloudDatabase.ConflictPolicy.CLOUD_DB_CONFLICT_POLICY_TIMESTAMP
}
cloudDB.setSyncConfig(syncConfig)

同步模式说明:

  • AUTO:自动同步,网络可用时实时同步
  • MANUAL:手动同步,需要显式调用sync方法
  • LOCAL_ONLY:只本地存储,不同步到云端

第五步:离线处理

// 网络状态监听
import { connection } from '@kit.NetworkKit'

connection.createNetConnection().on('netAvailable', () => {
  // 网络恢复,触发同步
  cloudDB.sync(cloudDatabase.SyncMode.CLOUD_SYNC_MODE_AUTO)
})

connection.createNetConnection().on('netLost', () => {
  // 网络断开,切换为离线模式
  // Cloud DB自动使用本地缓存,读写不受影响
})

整个笔记应用的端云协同数据流如下:

AGC 云端

端侧应用

自动同步

调用

上传/下载

离线读写

UI 层

Cloud DB SDK

本地缓存

Cloud DB 数据库

Cloud Function

Cloud Storage

图5:笔记应用端云协同数据流

踩坑排错

坑1:schema文件路径不对

现象:初始化Cloud DB时报 “schema not found” 错误。

原因:schema文件路径配置错误。schemaUrl 是相对于项目根目录的路径,不是相对于代码文件的路径。

解决:把schema文件放到 resources/rawfile/ 目录下,路径写 resources/rawfile/NoteSchema.json。

坑2:字段类型不匹配

现象:upsert数据时报 “type mismatch” 错误。

原因:端侧代码中的字段类型和AGC控制台配置的类型不一致。比如控制台配的是 Integer,端侧代码用了 number(JavaScript的number是浮点型)。

解决:严格对照schema配置端侧字段类型。Date类型在端侧必须用 Date 对象,不能传时间戳数字。

坑3:同步冲突导致数据丢失

现象:两台设备同时编辑同一条笔记,后同步的覆盖了先同步的修改。

原因:默认冲突策略是"云端优先",后同步到云端的数据会覆盖先同步的。

解决:改为"时间戳优先"策略,以最后修改时间为准:

let syncConfig: cloudDatabase.SyncConfig = {
  mode: cloudDatabase.SyncMode.CLOUD_SYNC_MODE_AUTO,
  conflictPolicy: cloudDatabase.ConflictPolicy.CLOUD_DB_CONFLICT_POLICY_TIMESTAMP
}

坑4:权限配置导致数据不可见

现象:用户A创建的笔记,用户B登录后查不到。

原因:默认权限是"只有创建者可读写",其他用户看不到。

解决:在AGC控制台修改权限规则,或者用Cloud Function做数据分发。

最佳实践

  • schema文件放rawfile:路径固定为 resources/rawfile/,避免找不到文件
  • 字段类型严格匹配:端侧类型必须和云端配置完全一致
  • 冲突策略选时间戳:大多数场景用时间戳优先最合理
  • 离线模式要测试:断网后读写、恢复后同步,必须完整测试
  • 权限规则提前规划:默认只有创建者可读写,团队协作需要提前改权限

遇到问题时,可以按下面的排查路径逐项定位:

是

否

是

否

是

否

是

否

同步异常

报 schema not found?

检查 schemaUrl 路径是否指向 rawfile

报 type mismatch?

对照 schema 校验端侧字段类型

数据被覆盖丢失?

切换为时间戳优先冲突策略

他人数据查不到?

在 AGC 调整权限规则

检查网络与同步模式配置

图6:常见问题排查路径

总结

核心要点:

  1. 端云协同三件套:Cloud DB(数据同步)、Cloud Function(云端逻辑)、Cloud Storage(文件存储)
  2. Cloud DB的核心是"端云双写+自动同步",端侧写入立即返回,后台自动同步到云端
  3. 数据模型在AGC控制台配置,字段类型一旦发布不可修改
  4. 冲突解决策略有四种,大多数场景用时间戳优先最合理

最佳实践清单:

  • schema文件放 resources/rawfile/ 目录,路径不要写错
  • 端侧字段类型必须和云端配置严格一致
  • 冲突策略选时间戳优先,避免数据被意外覆盖
  • 离线模式必须完整测试:断网读写→恢复同步→冲突处理
  • 权限规则提前规划,默认只有创建者可读写

你在端云协同开发中遇到过什么坑?评论区聊聊。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐