ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

HarmonyOS 端云一体化开发(一)

HarmonyOS 端云一体化开发(一) 1. 学习目标完成本章学习后你应当能够解释端云一体化开发的基本思想和价值。在 AGC 平台创建项目并规划认证服务、云数据库等资源。使用 DevEco Studio 云开发模板创建与云端资源关联的工程。理解云端对象类型、字段类型、主键和数据约束。在云数据库控制台设计农业设备数据表。根据云端对象类型生成或维护端侧数据模型类。使用 ArkUI 声明式组件构建设备数据卡片。使用状态变量实现 UI 与云端数据的动态绑定。编写端侧 Cloud DB 查询完成条件过滤和排序。监听云端数据变化实现查询结果的同步和刷新。处理认证失败、查询失败、权限不足和数据格式异常。通过实践验证端云设计方案的可行性和有效性。形成从需求、建模、实现、联调到验证的系统化开发思维。在云数据安全、权限配置、隐私保护和工程协作方面承担责任。2.端云一体化开发基础2.1 什么是端云一体化端云一体化是把端侧应用与云端资源作为一个整体进行设计和开发端侧手机、平板、元服务卡片 │ │ API / SDK / 数据订阅 ▼ 云侧认证、数据库、存储、函数和管理控制台端侧负责• 展示界面• 接收用户输入• 发起查询和操作• 管理页面状态• 提供卡片和交互入口。云侧负责• 用户认证• 数据存储• 数据访问控制• 多端共享• 数据备份和管理• 向端侧提供可访问的服务能力。2.2 为什么要采用端云一体化传统单机应用可以把数据保存在本地但在多设备、多用户和实时协作场景中会遇到• 数据无法跨设备共享• 更换设备后数据丢失• 多人协作难以同步• 需要自行搭建后端接口• 权限和数据安全难以统一管理。端云一体化可以帮助开发者• 快速创建云端资源• 使用统一数据模型• 减少重复编写基础后端代码• 实现多端数据共享• 让 UI 与云端数据保持同步• 集中管理认证和访问权限。2.3 端云数据流农业设备列表的典型数据流用户打开元服务卡片 ↓ 端侧初始化 Cloud DB SDK ↓ 检查认证状态 ↓ 查询云端设备对象 ↓ 过滤、排序和转换数据 ↓ 更新 State ↓ 卡片显示最新设备信息 ↓ 云端数据发生变化 ↓ 订阅事件触发 ↓ 重新查询或局部更新 UI2.4 端云一体化不等于“所有逻辑都放云端”应合理划分职责端侧的按钮隐藏不能代替云端权限控制。任何重要数据和高风险操作都必须在云侧再次验证。3.AGC 项目环境初始化3.1 AGC 项目平台的作用AGCAppGallery Connect平台通常用于管理应用和云端服务资源。课程要求在平台完成• 创建项目• 关联应用• 配置认证服务• 创建或配置云数据库• 管理应用标识和服务开关• 查看云端数据• 配置访问规则• 获取开发所需的项目配置。平台界面会随版本调整但核心思路保持不变先建立云端项目和资源再让端侧工程与其关联。3.2 创建 AGC 项目通用步骤登录 AGC 平台。创建一个新的项目。填写项目名称。添加与 HarmonyOS 应用对应的应用条目。确认包名、应用标识和项目归属。开启课程需要的认证服务和 Cloud DB。记录项目环境信息。下载或生成端侧工程需要的配置。在 DevEco Studio 工程中完成关联。使用最小查询验证连接是否成功。项目命名建议AgriCloudDemo GreenhouseCloudLab EquipmentCloudService建议• 名称具有业务含义• 不使用临时测试词作为正式项目名称• 开发、测试和生产项目分开• 团队统一命名规则• 不把密钥或敏感信息写入项目名称和代码。3.3 认证服务认证服务用于确认“当前用户是谁”并为数据访问规则提供身份依据。常见认证流程用户打开应用 ↓ 检查是否已认证 ├── 已认证 → 访问 Cloud DB └── 未认证 → 登录/匿名认证/提示用户认证信息可以影响• 当前用户能查看哪些设备• 当前用户能否修改设备• 用户创建的数据归属• 设备和组织之间的关系• 访问日志和审计记录。认证设计原则• 认证状态要明确• 登录过期要能恢复• 未认证时不要直接展示敏感数据• 不在日志中输出令牌• 不把用户身份只交给端侧传参决定• 云端规则应根据可靠身份信息判断权限。3.4 云数据库服务Cloud DB 用于保存结构化业务数据。农业场景可以存储• 大棚信息• 设备信息• 传感器数据• 告警记录• 设备操作日志• 用户与设备的关联关系。初始化时要规划项目 ├── 认证 ├── 数据库 │ ├── greenhouse │ ├── equipment │ └── alarm └── 应用关联和权限规则3.5 环境区分建议区分开发环境学生个人测试数据测试环境团队联调和验收生产环境真实业务和真实用户不要让课堂测试代码直接访问生产数据库。环境配置应明确• 项目 ID• 应用标识• 数据库资源• 认证方式• 日志级别• 数据权限• 发布渠道。4.端云一体化工程创建4.1 使用云开发模板在 DevEco Studio 中可以使用与云开发相关的工程模板创建项目。模板的价值在于• 生成基本项目结构• 配置端云关联所需文件• 提供 Cloud DB 初始化示例• 创建基础页面和模型• 减少手动配置错误。通用步骤打开 DevEco Studio。选择创建新工程。选择云开发或端云一体化相关模板。填写项目名称、包名和保存路径。选择 SDK 和设备类型。选择或关联 AGC 项目。确认云端资源配置。等待工程同步和依赖解析。检查生成的配置文件和入口页面。执行一次最小编译和运行。4.2 工程中的重要部分项目根目录├── AppScope/ ├── entry/ │ └── src/main/ │ ├── ets/ │ │ ├── pages/ │ │ ├── components/ │ │ ├── model/ │ │ └── service/ │ ├── resources/ │ └── module.json5 ├── 云端关联配置 ├── 构建配置 └── 依赖配置建议按职责组织端侧代码ets/ ├── pages/ # 页面 ├── components/ # 可复用 UI ├── model/ # 端侧对象类型 ├── service/ # Cloud DB 和认证服务 ├── mapper/ # 云端数据到 UI 模型的转换 └── utils/ # 格式化和校验工具4.3 初始化 Cloud DB SDK概念流程async function initializeCloud(): Promisevoid { // 1. 初始化应用上下文 // 2. 初始化认证服务 // 3. 初始化 Cloud DB // 4. 检查登录或认证状态 }实际初始化 API 和配置方式需遵循当前 SDK 版本。初始化失败时应明确区分• 配置文件缺失• 项目关联错误• SDK 未安装• 网络不可用• 认证失败• 权限不足。4.4 初始化验收• [ ] 云开发模板工程可以打开。• [ ] AGC 项目与应用包名匹配。• [ ] 认证服务配置正确。• [ ] Cloud DB 服务已开启。• [ ] 端侧依赖可解析。• [ ] SDK 初始化没有异常日志。• [ ] 可以执行一个最小查询或连接检查。• [ ] 开发环境与生产环境没有混淆。5.云端对象类型设计5.1 什么是对象类型对象类型是对云端数据结构的描述。它决定• 对象有哪些字段• 每个字段是什么类型• 哪些字段必填• 哪些字段可以为空• 哪些字段作为主键• 数据能否被查询、排序和订阅。一个农业设备对象可以表示为interface Equipment { id: string; name: string; category: string; status: string; greenhouseId: string; battery: number; updatedAt: string; }云端控制台中的对象类型应与端侧模型保持一致。5.2 字段设计原则字段名称清晰推荐greenhouseId updatedAt batteryPercent不推荐a temp1 data2类型稳定如果 battery 表示百分比应统一使用数字不要有时返回数字、有时返回字符串正确battery 82 不一致battery 82时间统一统一选择• 时间戳• ISO 8601 字符串• 云数据库支持的日期类型。不要在不同表中混用多种无法转换的时间格式。状态受约束online offline maintenance状态值应由统一类型或枚举约束避免出现onlie Online 在线中5.3 大棚对象类型interface Greenhouse { id: string; name: string; location: string; area: number; status: normal | warning | offline; updatedAt: string; }5.4 设备与大棚的关系设备通常属于某个大棚Greenhouse 1 ──── * Equipment设备表中可以保存greenhouseId查询某个大棚的设备WHERE greenhouseId GH-001如果还需要设备历史数据可以拆分equipment equipment_reading equipment_alarm不要把所有历史数据不断追加到设备对象的一个大字段中这会降低查询和维护效率。5.5 主键与索引主键主键应• 唯一• 稳定• 不随名称变化• 便于路由和查询• 能在多端共享。索引适合建立索引的字段可能包括• greenhouseId• status• updatedAt• category。索引不是越多越好。应根据真实查询场景规划避免增加无用写入成本。5.6 数据约束示例约束id必填、唯一name必填、长度限制battery0100 的整数status限定为三种状态greenhouseId必须关联有效大棚updatedAt必须是合法时间客户端可以做第一层校验云端还必须做最终校验。6.端侧对象模型生成6.1 为什么需要端侧模型如果端侧直接操作原始对象会出现• 字段名称拼写错误• 云端字段更新后端侧未同步• 状态值不统一• 查询结果无法获得编辑器提示• UI 与数据结构耦合过深。端侧模型可以提供• 类型检查• 自动补全• 统一字段• 数据转换入口• 与云端对象类型的对应关系。6.2 自动生成与手工维护理想流程云端对象类型 ↓ 模型生成工具 ↓ 端侧数据模型类 ↓ 页面和服务层使用如果当前工具支持自动生成应在云端模型变更后重新生成并检查差异。若必须手工维护应建立字段变更记录。6.3 端侧模型示例export type EquipmentStatus | online | offline | maintenance; export class EquipmentModel { id: string ; name: string ; category: string ; status: EquipmentStatus offline; greenhouseId: string ; battery: number 0; updatedAt: string ; }实际生成模型的构造函数、装饰器和字段定义需要以当前 Cloud DB SDK 模板为准。6.4 云端模型与 UI 模型分离云端模型interface EquipmentRecord { id: string; name: string; status: EquipmentStatus; updatedAt: string; }UI 模型interface EquipmentCardModel { title: string; statusText: string; statusColor: string; updatedAtText: string; }转换函数function toCardModel( record: EquipmentRecord ): EquipmentCardModel { return { title: record.name, statusText: getStatusText(record.status), statusColor: getStatusColor(record.status), updatedAtText: formatTime(record.updatedAt) }; }分离的好处• 数据层和界面层解耦• UI 不需要知道数据库字段细节• 更容易适配不同卡片尺寸• 后端字段变化影响范围更小。6.5 模型同步检查云端字段变更后检查云端对象类型 ↓ 端侧模型 ↓ 查询字段 ↓ 转换函数 ↓ UI 绑定 ↓ 测试数据和卡片配置不要只修改云端表而忘记端侧代码。7.ArkUI 声明式卡片开发7.1 页面与卡片结构端侧卡片可以拆成GreenhouseCardPage ├── CardHeader ├── EnvironmentMetrics ├── DeviceSummary ├── AlarmSummary └── CardFooter 每个组件只负责一类 UI 任务。 ## 7.2 卡片示例 arkts Component struct GreenhouseDataCard { Prop name: string; Prop temperature: number; Prop humidity: number; Prop alarmCount: number; build() { Column({ space: 8 }) { Text(this.name) .fontSize(18) .fontWeight(FontWeight.Bold) Row({ space: 16 }) { Column() { Text(${this.temperature.toFixed(1)}℃) .fontSize(22) Text(温度) .fontSize(12) } Column() { Text(${this.humidity.toFixed(0)}%) .fontSize(22) Text(湿度) .fontSize(12) } } .width(100%) .justifyContent(FlexAlign.SpaceAround) Text(this.alarmCount 0 ? 告警${this.alarmCount} 条 : 当前无告警) .fontSize(12) } .padding(16) .backgroundColor(#FFFFFF) .borderRadius(16) } }7.3 数据绑定Component struct GreenhousePage { State data: GreenhouseData | null null; build() { Column() { if (this.data null) { Text(暂无大棚数据) } else { GreenhouseDataCard({ name: this.data.name, temperature: this.data.temperature, humidity: this.data.humidity, alarmCount: this.data.alarmCount }) } } } }当执行this.data latestData;绑定 data 的界面会重新构建。7.4 加载和错误状态type LoadStateT | { kind: loading } | { kind: success; data: T } | { kind: empty } | { kind: error; message: string };使用状态驱动State state: LoadStateGreenhouseData { kind: loading };这样可以清晰区分• 正在加载• 获取成功• 成功但无数据• 请求失败。不要用一个空对象同时表示“未加载”“加载失败”和“真实数据全为零”。8.云数据库查询操作8.1 查询流程确定对象类型 ↓ 创建查询对象 ↓ 添加过滤条件 ↓ 设置排序 ↓ 设置分页 ↓ 执行查询 ↓ 转换结果 ↓ 更新 State8.2 查询全部设备概念示例async function queryAllEquipments(): PromiseEquipment[] { const query createEquipmentQuery(); const records await query.execute(); return records.map(toEquipmentModel); }实际查询对象、执行函数和返回类型需按照当前 Cloud DB SDK 的 API 编写。8.3 条件过滤查询某个大棚的在线设备async function queryOnlineEquipments( greenhouseId: string ): PromiseEquipment[] { const query createEquipmentQuery() .where(greenhouseId, , greenhouseId) .where(status, , online); const records await query.execute(); return records.map(toEquipmentModel); }注意• 过滤字段名称要与云端模型一致• 参数应进行类型校验• 多条件组合要确认逻辑是 AND 还是 OR• 过滤条件应尽量在云端执行减少端侧数据量。8.4 排序按更新时间倒序const query createEquipmentQuery() .orderBy(updatedAt, desc);按电量从低到高const query createEquipmentQuery() .orderBy(battery, asc);排序前要确认字段类型统一否则字符串排序和数字排序可能产生不同结果。8.5 分页interface PageResultT { records: T[]; page: number; pageSize: number; total?: number; hasMore: boolean; }分页的价值• 降低首次请求数据量• 减少页面渲染压力• 改善大棚设备数量较多时的体验• 控制网络和内存消耗。8.6 查询错误处理async function safeQuery(): PromiseEquipment[] { try { return await queryAllEquipments(); } catch (error: unknown) { if (error instanceof Error) { console.error(查询失败${error.message}); } throw new Error(设备数据暂时无法获取); } }应区分• 认证失败• 权限不足• 网络异常• 查询条件错误• 云服务异常• 数据格式错误。不要把所有错误都显示成“暂无数据”。9.数据订阅与更新9.1 为什么需要订阅如果多个用户或设备都能修改云端数据仅在页面首次进入时查询一次是不够的云端状态已改变 ↓ 页面仍显示旧状态 ↓ 用户做出错误判断数据订阅可以在云端对象变化时通知端侧云端数据变化 ↓ 订阅回调触发 ↓ 接收变化事件 ↓ 重新查询或更新本地状态 ↓ UI 自动刷新9.2 订阅方式具体 API 取决于当前 Cloud DB SDK常见思路包括• 订阅查询结果• 监听对象变化• 接收新增、修改和删除事件• 通过回调更新页面• 使用事件后重新查询。概念示例private unsubscribe?: () void; onPageShow(): void { this.unsubscribe subscribeEquipmentChanges( (change: EquipmentChange) { this.handleChange(change); } ); } onPageHide(): void { this.unsubscribe?.(); this.unsubscribe undefined; }9.3 重新查询与局部更新重新查询收到变化事件 ↓ 重新查询当前条件下的数据 ↓ 整体更新 State 优点逻辑简单一致性较好。 缺点可能增加请求量。 2. 局部更新 收到修改事件 ↓ 找到对应设备 ↓ 只更新该项 优点响应快、数据量小。 缺点需要正确处理新增、修改、删除、排序和筛选。 初学阶段可先实现重新查询再根据性能需求进行局部优化。 ## 9.4 订阅生命周期 页面显示 → 建立订阅 页面隐藏 → 取消订阅 页面重新显示 → 恢复订阅 页面销毁 → 确保全部释放 如果忘记取消订阅可能出现 • 重复回调 • 页面离开后仍更新状态 • 内存泄漏 • 同一个事件触发多次查询 • 卡片和页面数据互相覆盖。 ## 9.5 事件顺序和重复事件 订阅事件可能存在 • 重复投递 • 网络恢复后的批量事件 • 事件乱序 • 事件与手动刷新同时到达。 建议 • 使用事件 ID 或版本号去重 • 关键修改后重新查询 • 记录数据更新时间 • 不盲目相信事件到达顺序 • 对删除对象进行存在性检查。
返回列表