鸿蒙NEXT开发-端云一体化开发

225 阅读16分钟

端云一体化开发

端云一体化开发基本概念

:::info 为丰富HarmonyOS对云端开发的支持、实现端云联动,DevEco Studio以Cloud Foundation Kit(云开发服务)为底座、在传统的“端开发”基础上新增“云开发”能力,开发者在创建工程时选择合适的云开发工程模板,即可在DevEco Studio内同时完成HarmonyOS应用/元服务的端侧与云侧开发,体验端云一体化协同开发。

:::

传统架构

image.png

端云一体化架构

image.png

端云一体化开发特性

image.png

:::info 特点:

  • DevEco Studio一套开发工具即可支撑端侧与云侧同时开发,无需搭建服务器;
  • 依托AGC中Serverless云服务开放的接口,端侧开发人员能轻松操作云函数以及云数据库中的数据;
  • 直接接入AGC Serverless云服务,实现免运维,无运维成本或资源浪费。

:::

**
**

优势:

image.png

工作原理

:::warning DevEco Studio支持开发者在本地完成云侧服务资源的开发与部署,并可在端侧工程中调用您开发的云侧代码,真正实现端云一体化开发。

  1. 选择合适的云开发模板,根据工程向导创建端云一体化开发工程。
  2. 分别进行云侧工程与端侧工程的代码开发与调试。
    1. 开发云侧工程:在云侧工程开发Cloud Foundation Kit提供的云端服务,目前包括云函数、云对象和云数据库资源开发。
      • 开发云函数:在DevEco Studio中创建并配置函数、开发函数代码、调试函数、部署函数到AGC云端。
      • 开发云对象:在DevEco Studio中创建云对象、开发云对象代码、调试云对象、部署云对象到AGC云端。
      • 开发云数据库:在DevEco Studio中创建对象类型、在对象类型中添加数据条目、部署云数据库到AGC云端。
    2. 部署云侧工程:云侧工程代码全部开发调试完毕后,一键部署云侧工程到AGC云端。
    3. 开发端侧工程:在端侧工程下开发您应用的业务代码。本文档仅描述如何在端侧调用您开发的云侧代码,包括调用云函数、调用云对象、访问云数据库、调用云存储。
  3. 端云两侧工程代码全部开发完成后,将端云一体化工程打包成APP,提交至AGC申请上架。

:::

image.png

:::info 说明

云侧与端侧工程的代码可并行开发,一般无先后顺序。但若需在端侧代码中调用云侧代码,云侧代码必须先部署到AGC云端,因此建议您先完成云侧代码的开发、调试与部署,再进行端侧代码开发与调试。

:::

注意事项

:::danger 仅支持手机,且不支持使用模拟器运行调试。当前仅在中国境内(不包含中国香港、中国澳门、中国台湾)提供服务。当前仅支持手动签名。手动签名的教程:developer.huawei.com/consumer/cn…

:::

开发准备

1、注册华为开发者账号并实名认证

2、安装DevEco Studio NEXT Developer Beta1 及以上版本的开发工具

3、在AppGallery Connect(AGC)平台中创建项目和应用

1、打开AGC网址

developer.huawei.com/consumer/cn…

image.png

2、点击我的项目,进入创建项目阶段

image.png

3、创建项目

image.png

image.png

点击完成即可创建,下面教大家如何创建应用

4、打开下面图片所选中区域

image.png

5、创建APPID(其实就是创建应用)

image.png

其实创建AppId其实就是在创建应用,在创建应用之前记得先创建项目,如果之前已经创建过项目那就忽略;

image.png

image.png

点击确认即可创建完成

6、最后大家点击我的项目里面可以查看到应用

image.png

开发端云工程

:::color4 注意:仅支持手机,且不支持使用模拟器运行调试,必须要手动签名

:::

创建鸿蒙端云一体化应用工程

1、新建工程

在菜单栏选择“File > New > Create Project”来创建一个新工程。

image.png

2、选择模板

在“Application”页签,选择合适的云开发模板,然后点击“Next”

:::color2 说明

当前仅支持通用云开发模板([CloudDev]Empty Ability)。

:::

image.png

3、配置工程信息

image.png

参数说明
Project name工程的名称,由大小写字母、数字和下划线组成。
Bundle name软件包名称,需保证唯一,且需与您在AGC创建的HarmonyOS应用的“应用包名”一致。
Save location工程文件本地存储路径,由大小写字母、数字和下划线等组成,不能包含中文字符。
Compatible SDK兼容的最低API Version。
使用基于Cloud Foundation Kit(云开发服务)的端云一体化开发功能,请选择5.0.0(12)。
Module name模块名称。
Device type该工程模板支持的设备类型,目前仅支持手机设备。
Enable CloudDev是否启用云开发。云开发模板默认启用且无法更改。
4、关联云开发资源

image.png

如您尚未登录DevEco Studio,点击“Sign In”,在弹出的账号登录页面,使用已实名认证的华为开发者账号完成登录。

image.png

这种提示代表着你现在登录得华为账号里面再AGC里面没对应包名得应用,找不到,所以大家包名一定要写对,或者大家去AGC创建一个新的应用对应这个bundle name

修正之后包名

image.png

大家选中对应需要关联得云开发的应用,然后点击finish

5、进入主开发界面

进入主开发界面,DevEco Studio执行工程同步操作,端侧执行“ohpm install”,云侧执行“npm install”,分别下载端侧和云侧依赖。

image.png

端云一体化开发工程目录结构

端云一体化开发工程主要包含端开发工程(Application)与云开发工程(CloudProgram)。

端开发工程(Application)

通用云开发模板的端开发工程目录结构如下图所示,“src/main/ets/pages”下包含了云存储、云数据库和云函数页面。

image.png

云开发工程(CloudProgram)

在云开发工程中,您可为您的应用开发云端代码,包括云函数和云数据库服务代码。通用云开发模板的云开发工程目录结构如下图所示。

image.png

开发云函数

1、创建函数

右击“cloudfunctions”目录,选择“New > Cloud Function”。

image.png

image.png “cloudfunctions”目录下生成新建的“my-function”函数目录,目录下主要包含如下文件

image.png

image.png

其他详细配置参考官方文档:developer.huawei.com/consumer/cn…

云函数和云对象区别:

:::info 云对象是一种特殊的云函数,本质是对云函数的一种封装,客户端可通过导入一个云对象来直接使用这个对象的方法,为您提供在端侧直接调用云侧代码的开发体验。相对普通云函数方式,云对象代码更精简、逻辑更清晰,大多数场景下推荐使用云对象代替传统云函数

:::

2、开发函数

打开函数入口文件myFunction.ts

image.png

:::color3 注意

云函数与云函数之间是相互独立的,部署至云侧时,只会部署所选云函数目录下的文件,不可在一个云函数中通过import '../anotherDirectory/xxx'的方式引入依赖。如果有多个云函数公共的配置,建议存储在云数据库中,通过云数据库Server API类查询出公共配置;也可以将多个云函数整合成一个云对象,将公共配置变成云对象的私有配置。

:::

3、调试函数

本地调用

在DevEco Studio调试本地开发好的函数。支持单个调试和批量调试,并支持Run和Debug两种模式,调试功能丰富,常在函数开发过程或问题定位过程中使用

image.png

在下方通知栏“cloudfunctions”窗口,查看调试日志。如果出现“Cloud Functions loaded successfully”,表示函数成功加载到本地运行的HTTP Server中,并生成对应的Function URI。

image.png

在菜单栏选择“View > Tool Windows > Cloud Functions Requestor”,使用事件模拟器(Cloud Functions Requestor)触发函数调用。

image.png

在弹出的“Cloud Functions Requestor”面板,配置触发事件参数。

image.png 点击“Trigger”, 将会触发执行用户函数代码。执行结果将展示在“Result”框内,“cloudfunctions”窗口同时打印调试日志。

通过远程调用方式调试函数

您还可以将函数部署至AGC云端,然后在DevEco Studio调用云端函数,以测试函数在云端的运行情况、或补充测试因各种因素限制未能在本地调试中发现的问题。

image.png

4、部署函数

完成函数代码开发后,您可将函数部署到AGC云端,支持单个部署和批量部署。

1、单个部署

单个部署,直接右击需部署的函数目录,选择“Deploy '函数名'”即可,后续流程与批量部署相同。

image.png

您可在底部状态栏右侧查看函数打包与部署进度。

请您耐心等待,直至出现“Deploy successfully”消息,表示所有函数均已成功部署。

image.png

在菜单栏选择“Tools > CloudDev”。

image.png

image.png

2、批量部署

鼠标右击

image.png

image.png

其他步骤和单个部署一样

5、在端侧调用云函数

先确保云函数正确开发并部署在AGC上

1、在代码文件中引入Cloud Foundation Kit
import { cloudFunction } from '@kit.CloudFoundationKit';
import { BusinessError } from '@kit.BasicServicesKit';
2、调用您云侧部署的云函数
private getMyFunction() {
  // name是云函数的名字
  cloudFunction.call({ name: 'my-function' }).then((res: cloudFunction.FunctionResult) => {
    this.result = JSON.stringify(res.result)
  }).catch((err: BusinessError) => {
    console.log('err get myFunction:' + err)
  });
}
3、修改EntryAbility文件里面启动页面(方便测试)

注意:切记需要在真机上面测试,而且工程已经进行手动签名

4、打包构建到真机上点击按钮获取结果

image.png

开发云数据库

1、创建对象类型

对象类型(ObjectType)用于定义存储对象的集合,不同的对象类型对应的不同数据结构。每创建一个对象类型,云数据库会在每个存储区实例化一个与之结构相对应的对象类型,用于存储对应的数据。

右击“clouddb/objecttype”目录,选择“New > Cloud DB Object Type”。

image.png

image.png

参数必选(M)/可选(O)说明
fieldNameM字段名称。
输入要求具体如下:
+ 字段的名称长度必须大于或等于1个字符,小于或等于30个字符,只能包含以下3种类型,并且至少包含“字母”类型:
- 字母(A-Z或a-z)
- 数字(0-9)
- 特殊字符:_
+ 字段名称必须以字母开头,以字母或者数字结尾。
+ 字段名称中不区分字母的大小写。
+ 修改对象类型时,支持删除字段。
+ 字段名称不允许使用系统保留字段名称: naturalbase_version、naturalbase_deleted、naturalbase_operationtype、naturalbase_creator、naturalbase_accesstime、naturalbase_operationtime、naturalbase_syncstatus、naturalbase_changedfieldsbitmap、naturalbase_lastmodifier、cmin、cmax、xmin、xmax、ctid、oid、tableoid、xc_node_id、tablebucketid、rowid。
说明
fieldTypeM字段的数据类型。
当前支持的数据类型:String、Boolean、Byte、Short、Integer、Long、Float、Double、ByteArray、Text、Date。
belongPrimaryKeyO设置该字段是否为对象类型的主键,默认值为false。
+ 至少设置一个字段为主键。
+ 支持设置复合主键,由多个字段组合成为主键,一个复合主键包含的字段小于等于5个,复合主键字段顺序与字段的顺序一致。
+ 数据类型为ByteArray、Text、Date、Double、Float和Boolean的字段不支持设置为主键。
+ 主键的值不允许更改。
notNullO设置字段值是否为非空,默认值为false。
+ 数据类型为ByteArray和Date的字段不支持设置为非空。
+ 主键默认非空,且不允许更改。
+ 设置为非空的字段不支持加密和敏感。
isNeedEncryptO设置字段是否需要加密,开启全程加密数据管理功能,默认值为false。
选择加密后,该字段对应的数据会加密存储在存储区中。
+ 主键字段不支持加密。
+ 加密的字段不支持设置为非空。
+ 加密的字段不支持设置为敏感字段。
+ 一个对象类型中包含的加密字段和敏感字段的总数需小于或等于5个。
+ 字段设置为加密后,不支持导出该字段的数据值。
+ 数据类型为ByteArray、Text的字段不支持加密。
+ 对象类型创建成功后,不支持修改加密属性。
isSensitiveO设置字段是否为敏感字段,默认值为false。
选择敏感后,该字段对应的数据会加密存储在存储区中。
+ 敏感字段不支持设置为主键。
+ 敏感字段不支持设置为非空。
+ 敏感字段不支持设置为加密。
+ 敏感字段不支持设置为默认值。
+ 对象类型创建成功后,不支持修改敏感属性。
+ 仅支持数据类型为Byte、Short、Integer、Long、Float、Double、String和Date的字段设置为敏感字段。
+ 敏感字段不支持设置为索引。
+ 一个对象类型中包含的加密字段和敏感字段的总数需小于或等于5个。
defaultValueO字段为非空时,必须设置默认值。
+ 主键不支持设置默认值。
+ 加密字段和敏感字段不支持设置默认值。
+ 数据类型为ByteArray、Date不支持为其设置默认值。
+ 数据类型为Text的字段设置默认值时,默认值的长度小于或等于200个字符。

东林这边先创建一个User对象类型

{
  "objectTypeName": "User",
    "fields": [
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},
    {"fieldName": "sex", "fieldType": "Integer", "notNull": true, "defaultValue": 0},
    {"fieldName": "username", "fieldType": "String"},
    {"fieldName": "password", "fieldType": "String"}
  ],
    "indexes": [
    {"indexName": "id_index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}
  ],
    "permissions": [
    {"role": "World", "rights": ["Read"]},
    {"role": "Authenticated", "rights": ["Read", "Upsert"]},
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}
  ]
}
2、添加数据条目

创建完对象类型后,您可在对象类型内添加数据条目(DataEntry),并配置数据所在的存储区。

支持手动创建和自动生成数据条目文件。

1、手动创建数据条目文件

右击“clouddb/dataentry”目录,选择“New > Cloud DB Data Entry”。

image.png 在“Associated Cloud DB Object Type”栏选择需添加数据条目的对象类型,在“Enter Cloud DB Data Entry Name”栏定义数据条目文件名,完成后点击“OK”。

image.png

image.png

注意:存储区最多就四个

2、自动生成数据条目文件

右击对象类型JSON文件,选择“Generate Data Entry”。

image.png

在弹出的“New Cloud DB Data Entry”框内,为即将生成的数据条目文件定义名称。

image.png

3、部署云数据库

完成数据条目创建后,您可以直接部署该数据条目。您也可以等所有对象类型和数据条目开发完成后,再统一批量部署到AGC云端。

:::color3 说明

  • 部署到AGC云端的存储区数量不得超过4个,否则会导致部署失败,提示“clouddb deploy failed. Reason is the number of CloudDBZone exceeds the limit.”错误。如AGC云端当前已存在4个存储区,请将数据部署到已有的存储区,或者删除已有存储区后再部署新的存储区。需要注意的是,删除存储区,该存储区内的数据也将一并删除,且不可恢复。
  • 对象类型中的fieldType等字段信息,部署到AGC云端后,请勿在本地再做修改。例如,fieldType设置为String,对象类型部署成功后,又在本地修改fieldType为Integer,再次部署将失败,提示“clouddb deploy failed. Reason is existing fields cannot be modified.”错误。如需更改fieldType等字段信息,请先删除云端部署的对象类型。需要注意的是,删除云端对象类型,对象类型内添加的数据也将一并删除,且不可恢复。

:::

右击“clouddb”目录,选择“Deploy Cloud DB”。

image.png

部署成功有提示

image.png

:::color3 说明

云数据库部署成功后,DevEco Studio将自动从云侧下载云数据库的schema文件至“AppScope/resources/rawfile/schema.json”路径,该文件是云数据库端侧API必须引入的配置文件。

:::

image.png

在打开的CloudDev面板中,点击“Serverless > Cloud DB”下的“Go to console”,进入当前项目的云数据库服务页面

image.png

image.png

image.png

4、在端侧访问云数据库

确保云数据库已正确开发并部署

1、生成Client Model

在云侧右击需要调用的对象类型文件(以“User.json”为例),选择“Generate Client Model”。

image.png

image.png

image.png

2、端侧在代码文件中引入Cloud Foundation Kit和“User”类。
import { cloudDatabase } from '@kit.CloudFoundationKit';
import { User } from './User';

3、调用云数据库
import { hilog } from '@kit.PerformanceAnalysisKit';
import { cloudDatabase } from '@kit.CloudFoundationKit';
import { User } from './User';

const TAG = '[CloudDBPage]';


@Entry
  @Component
  struct CloudDb {
    // 数据
    @State allRecords: User[] = [];
    // 查询agc里面云数据库的区域
    agcDataBase: cloudDatabase.DatabaseZone | undefined = undefined;
    // 查询条件
    condition: cloudDatabase.DatabaseQuery<cloudDatabase.DatabaseObject> | undefined = undefined;

    aboutToAppear() {
      // 设置查看区域
      this.agcDataBase = cloudDatabase.zone('default');
    }

    /**
   * 查询所有数据
   */
    async getAllData() {
      try {
        this.condition = new cloudDatabase.DatabaseQuery(User);
        const resultArray = await this.agcDataBase?.query(this.condition)
        this.allRecords = resultArray as User[]
        hilog.info(0x0000, 'CloudDB', 'query success : %{public}s', JSON.stringify(resultArray));
      } catch (err) {
        hilog.error(0x0000, 'CloudDB', 'query err %{public}s', JSON.stringify(err));
      }
    }

    /**
   * 删除数据
   * @param user
   */
    async deleteRecord(user: User) {
      try {
        // 删除数据,大家切记要有权限,创建对象类型的时候有设置权限
        const record = await this.agcDataBase?.delete(user)
        hilog.info(0x0000, 'CloudDB', 'delete success: %{public}d', record);
        // 查询所有数据
        this.getAllData()
      } catch (err) {
        hilog.error(0x0000, 'CloudDB', 'delete error: %{public}d', user);
      }
    }

    /**
   * 添加或者修改数据
   * @param user
   */
    async insertRecord(user: User) {
      try {
        // 添加数据,大家切记要有权限,创建对象类型的时候有设置权限
        await this.agcDataBase?.upsert(user)
        hilog.info(0x0000, 'CloudDB', 'insert success: %{public}d', user);
        // 查询所有数据
        this.getAllData()
      } catch (err) {
        hilog.error(0x0000, 'CloudDB', 'insert error: %{public}d', user);
      }
    }

    build() {
      Column() {
        Button('查询所有数据')
          .onClick(() => {
            this.getAllData()
          })
        List({space:20}) {
          ForEach(this.allRecords, (item: User) => {
            ListItem() {
              Row() {
                Text('id: ' + item.id.toString())
                  .fontSize(10)
                Text('username: ' + item.username)
                  .fontSize(10)
                Text('password: ' + item.password)
                  .fontSize(10)
                Text(item.sex === 0 ? '性别: 男' : '性别: 女')
                  .fontSize(10)
                Text('删除数据').fontColor(Color.Blue)
                  .fontSize(10)
                  .onClick(() => {
                    this.deleteRecord(item)
                  })
                Text('添加或者修改数据')
                  .fontColor(Color.Blue)
                  .fontSize(10)
                  .onClick(() => {
                    item.id = 1
                    item.username = '东林'
                    item.password='123456'
                    item.sex = 1
                    this.insertRecord(item)
                  })
              }.width('100%').justifyContent(FlexAlign.SpaceBetween)
            }
          })
        }

      }.width('100%')
        .height('100%')
    }
  }

注意:对象数据的操作需要权限的,如果报权限问题记得去云侧生成对象类型的时候修改下权限,然后在进行云侧数据库部署到agc

{
  "objectTypeName": "User",
    "fields": [
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},
    {"fieldName": "sex", "fieldType": "Integer", "notNull": true, "defaultValue": 0},
    {"fieldName": "username", "fieldType": "String"},
    {"fieldName": "password", "fieldType": "String"}
  ],
    "indexes": [
    {"indexName": "id_index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}
  ],
    "permissions": [
    {
      "role": "World", "rights": ["Read", "Upsert", "Delete"]
    },
    {
      "role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]
    },
    {
      "role": "Creator", "rights": ["Read", "Upsert", "Delete"]
    },
    {
      "role": "Administrator", "rights": ["Read", "Upsert", "Delete"]
    }
  ]
}
4、修改EntryAbility文件里面启动页面(方便测试)

注意:切记需要在真机上面测试,而且工程已经进行手动签名

image.png

5、打包构建到真机上测试

image.png