OpenHarmony(数据)通信协议、数据存储—protobuf

526 篇文章 5 订阅
415 篇文章 3 订阅

介绍

ProtoBuf(protocol buffers) 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。,是一种灵活,高效,自动化机制的结构数据序列化方法比XML更小,更快,更为简单。

本项目主要是OpenHarmony系统下以 protobuf.js 5.0.3 为主要依赖开发,主要接口针对OpenHarmony系统进行合理的适配研发。

下载安装

1.安装

ohpm install @ohos/protobufjs

2.在需要使用的页面导入protobuf

import protobuf from '@ohos/protobufjs'

使用说明

protobuf支持的输入格式

1.proto格式字符串

const protoStr = 'syntax = "proto3"; package com.user;message UserLoginResponse{string sessionId = 1;string userPrivilege = 2;bool isTokenType = 3;string formatTimestamp = 4;}';

2.proto文件映射的json字符串

const protoJson = '{
      "package": "com.user",
      "messages": [
        {
          "name": "UserLoginResponse",
          "fields": [
            {
              "rule": "optional",
              "type": "string",
              "name": "sessionId",
              "id": 1
            },
            {
              "rule": "optional",
              "type": "string",
              "name": "userPrivilege",
              "id": 2
            },
            {
              "rule": "optional",
              "type": "bool",
              "name": "isTokenType",
              "id": 3
            },
            {
              "rule": "optional",
              "type": "string",
              "name": "formatTimestamp",
              "id": 4
            }
          ]
        }
      ]
}'

3.proto文件

在resource->rawfile文件夹下按照 .proto文件格式定义消息体结构,如:userproto.proto文件。

syntax = "proto3";

package com.user;
message UserLoginResponse{
   string sessionId = 1;
   string userPrivilege = 2;
   bool isTokenType = 3;
   string formatTimestamp = 4;
}

4.json文件

在resource->rawfile文件夹下存放proto文件映射的json文件,参照第二点。

对象编解码

1.在resource->rawfile文件夹下按照 .proto文件格式定义消息体结构,如:userproto.proto文件。

syntax = "proto3";

package com.user;
message UserLoginResponse{
   string sessionId = 1;
   string userPrivilege = 2;
   bool isTokenType = 3;
   string formatTimestamp = 4;
}

2.读取.proto 文件

let builder = await Protobuf.loadProtoFile("userproto.proto", null, null, getContext(this).resourceManager)

3.对象编码

// 构建消息体
var UserLoginResponse = builder.build("com.user.UserLoginResponse");
let userLoginData = {
    sessionId: "testAsynchronouslyLoadProtoFile",
    userPrivilege: "John123",
    isTokenType: false,
    formatTimestamp: "12342222"
  };

// 对象编码的两种方式
// 方式一:通过消息体静态编码方法进行编码
var arrayBuffer = UserLoginResponse.encode(userLoginData).toArrayBuffer();

// 方式二:通过消息体实例进行编解码
var msg = new UserLoginResponse(userLoginData);
var arrayBuffer = msg.toArrayBuffer();

4.对象解码

let decode = UserLoginResponse.decode(arrayBuffer)

主要接口示例:

1.proto字符串编解码

Button("proto字符串编解码")
  .width('80%')
  .type(ButtonType.Capsule)
  .backgroundColor('#0D9FFB')
  .onClick(async () => {
    try {
      // 1.创建protbuf.Builder对象:用于构造协议消息体。
      var builder = protobuf.newBuilder();
      
      // 2.加载proto字符串:解析协议消息体定义。
      var root = await protobuf.loadProto(protoStr, builder, "user.proto");
      
      // 3.构建协议消息体。
      var UserLoginResponse = root.build("com.user.UserLoginResponse");
      
	  // 设置编解码数据
      const userLogin = {
        sessionId: "loadProto",
        userPrivilege: "John123",
        isTokenType: false,
        formatTimestamp: "12342222"
      };
      
	  // 4.实例Message消息体:通过builder找到协议名后会产生Message,创建符合协议结构的数据对象,作为参数实例协议消息体。
      var msg = new UserLoginResponse(userLogin);
      
      // 5.消息体编码:可用于通信传递或存储
      var arrayBuffer = msg.toArrayBuffer();
      
      // 6.消息体解码:得到原始消息体内容
      var decodeMsg = UserLoginResponse.decode(arrayBuffer);
    } catch (error) {
      console.info('protobuf single file catch error: ' + error)
    }
  });

2.json字符串编解码

Button("json字符串编解码")
  .width('80%')
  .type(ButtonType.Capsule)
  .backgroundColor('#0D9FFB')
  .onClick(async () => {
    try {
      // 1.创建protbuf.Builder对象:用于构造协议消息体。
      var builder = protobuf.newBuilder();
      
      // 2.加载json字符串:解析协议消息体定义。
      var root = await protobuf.loadProto(protoJson, builder, "user.json");
      
      // 3.构建协议消息体。
      var UserLoginResponse = root.build("com.user.UserLoginResponse");
      
	  // 设置编解码数据
      const userLogin = {
        sessionId: "loadJson",
        userPrivilege: "John123",
        isTokenType: false,
        formatTimestamp: "12342222"
      };
      
	  // 4.实例Message消息体:通过builder找到协议名后会产生Message,创建符合协议结构的数据对象,作为参数实例协议消息体。
      var msg = new UserLoginResponse(userLogin);
      
      // 5.消息体编码:可用于通信传递或存储
      var arrayBuffer = msg.toArrayBuffer();
      
      // 6.消息体解码:得到原始消息体内容
      var decodeMsg = UserLoginResponse.decode(arrayBuffer);
    } catch (error) {
      console.info('protobuf single file catch error: ' + error)
    }
  });

3.同步方式进行proto文件编解码

Button("同步方式进行proto文件编解码")
  .width('80%')
  .type(ButtonType.Capsule)
  .backgroundColor('#0D9FFB')
  .onClick(async () => {
    try {
    	// 读取文件需要借助全球化资源子系统中的ResourceManager来进行,支持多种方式获取
    	// 方式一: 通过GlobalContext对象保存ability上下文中的resourceManager对象
    	// 方式二: 通过getContext()方式获取
    	// 在pages页面中获取: getContext(this).resourceManager
    	let context: Context = GlobalContext.getContext().getObject("context") as Context;
        var builder = await protobuf.loadProtoFile('userproto.proto', null, null, context.resourceManager);
        if (!builder) {
          console.error('protobuf codec: builder is null|undefined.');
          return;
        }
        var UserLoginResponse = builder.build("com.user.UserLoginResponse");
        var msg = new UserLoginResponse(this.userLogin);
        var arrayBuffer = msg.toArrayBuffer();
        console.log("protobuf arrayBuffer:" + new Uint8Array(arrayBuffer));

        var decodeMsg = UserLoginResponse.decode(arrayBuffer);
        console.log("protobuf decode:" + JSON.stringify(decodeMsg));
      } catch (error) {
        console.info('protobuf single file catch error: ' + error)
      }
  });

4.异步方式进行proto文件编解码

Button("异步方式进行proto文件编解码")
  .width('80%')
  .type(ButtonType.Capsule)
  .backgroundColor('#0D9FFB')
  .onClick(() => {
    try {
      let context: Context = GlobalContext.getContext().getObject("context") as Context;
      protobuf.loadProtoFile('userproto.proto', (error, builder) => {
        if (error) {
          console.error('protobuf codec catch error: ' + error);
          return;
        }
        if (!builder) {
          console.error('protobuf codec: builder is null|undefined.');
          return;
        }
        var UserLoginResponse = builder.build("com.user.UserLoginResponse");
        var msg = new UserLoginResponse(this.userLogin);
        console.log("protobuf msg:" 
        var arrayBuffer = msg.toArrayBuffer();
        console.log("protobuf arrayBuffer:" + new Uint8Array(arrayBuffer));
        this.bufferData = Array.prototype.toString.call(new Uint8Array(arrayBu
        var decodeMsg = UserLoginResponse.decode(arrayBuffer);
        console.log("protobuf decode:" + JSON.stringify(decodeMsg));
        this.decodeData = JSON.stringify(decodeMsg);
      }, null, context.resourceManager);
    } catch (error) {
      console.info('protobuf single file catch error: ' + error)
    }
  });

接口说明

loadProto

static loadProto(proto:string,builder?:ProtoBuf.Builder|string|{root: string, file: string},filename?:string|{root: string, file: string}) :ProtoBuf.Builder;

加载proto格式字符串,进行内容解析,并返回协议消息体构建器。

参数:

参数名类型必填说明
protostringproto格式的字符串。
builderBuilder |string | {root: string, file: string}指定已有的协议消息体构建器,如果未指定将重新创建一个。
filenamestring | {root: string, file: string}如果知道对应的文件名称,必须为导入文件指定。

返回值:

类型说明
Builder协议消息体构建器。

protoFromString

static protoFromString(proto:string,builder?:ProtoBuf.Builder|string|{root: string, file: string},filename?:string|{root: string, file: string}) :ProtoBuf.Builder;

loadProto方法的别名,加载proto格式字符串,进行内容解析,并返回协议消息体构建器。

参数

参数名类型必填说明
protostringproto格式的字符串。
builderBuilder |string | {root: string, file: string}指定已有的协议消息体构建器,如果未指定将重新创建一个。
filenamestring | {root: string, file: string}如果知道对应的文件名称,必须为导入文件指定。

返回值:

类型说明
Builder协议消息体构建器。

loadProtoFile

static loadProtoFile(filename:string|{root: string, file: string}, callback?=(error?:Error,builder:Protobuf.Builder)=>void,builder?:Protobuf.Builder,resourceManager: @ohos.resourceManager.ResourceManager):ProtoBuf.Builder|undefined;

加载proto文件,进行内容解析,并返回协议消息体构建器。

参数名类型必填说明
filenamestring | {root: string, file: string}原始文件的路径或指定’file’的对象,并为所有导入的文件覆盖’根’路径。
callbackfunction成功时将接收’ null '作为第一个参数,并将Builder作为第二个参数,否则将Error作为第一个参数。如果省略,文件将被同步读取。
builderBuilder指定已有的协议消息体构建器,如果未指定将重新创建一个。
resourceManager@ohos.resourceManager.ResourceManager访问应用资源的能力。

表1 callback的参数说明

参数名类型说明
errorError如果解析成功,此参数返回’null’,如果失败,返回对应Error。
builderBuilder协议消息体构建器。

返回值:

类型说明
Builder | null协议消息体构建器。

protoFromFile

static protoFromFile(filename:string|{root: string, file: string}, callback?=(error?:Error,builder:Protobuf.Builder)=>void,builder?:Protobuf.Builder,resourceManager: @ohos.resourceManager.ResourceManager):ProtoBuf.Builder|undefined;

loadProtoFile方法别名,加载proto文件,进行内容解析,并返回协议消息体构建器。

参数名类型必填说明
filenamestring | {root: string, file: string}原始文件的路径或指定’file’的对象,并为所有导入的文件覆盖’根’路径。
callbackfunction成功时将接收’ null '作为第一个参数,并将Builder作为第二个参数,否则将Error作为第一个参数。如果省略,文件将被同步读取。
builderBuilder指定已有的协议消息体构建器,如果未指定将重新创建一个。
resourceManager@ohos.resourceManager.ResourceManager访问应用资源的能力。

表1 callback的参数说明

参数名类型说明
errorError如果解析成功,此参数返回’null’,如果失败,返回对应Error。
builderBuilder协议消息体构建器。

返回值:

类型说明
Builder | undefined协议消息体构建器。

loadJson

static loadJson(json:string|any, builder?:Protobuf.Builder|string| {root: string, file: string}, filename?: string| {root: string, file: string} ): ProtoBuf.Builder;

参数:

参数名类型必填说明
jsonstring | anyproto格式的json字符串或者proto文件对应的json对象。
builderBuilder |string | {root: string, file: string}指定已有的协议消息体构建器,如果未指定将重新创建一个。
filenamestring | {root: string, file: string}如果知道对应的文件名称,必须为导入文件指定。

返回值:

类型说明
Builder协议消息体构建器。

loadJsonFile

static loadJsonFile(filename:string|{root: string, file: string}, callback?=(error?:Error,builder:Protobuf.Builder)=>void,builder?:Protobuf.Builder,resourceManager: @ohos.resourceManager.ResourceManager):ProtoBuf.Builder|undefined;

加载proto文件,进行内容解析,并返回协议消息体构建器。

参数名类型必填说明
filenamestring | {root: string, file: string}原始文件的路径或指定’file’的对象,并为所有导入的文件覆盖’根’路径。
callbackfunction成功时将接收’ null '作为第一个参数,并将Builder作为第二个参数,否则将Error作为第一个参数。如果省略,文件将被同步读取。
builderBuilder指定已有的协议消息体构建器,如果未指定将重新创建一个。
resourceManager@ohos.resourceManager.ResourceManager访问应用资源的能力。

表1 callback的参数说明

参数名类型说明
errorError如果解析成功,此参数返回’null’,如果失败,返回对应Error。
builderBuilder协议消息体构建器。

返回值:

类型说明
Builder | undefined协议消息体构建器。

newBuilder

static newBuilder():Protobuf.Builder;

返回值:

类型说明
Builder协议消息体构建器。

Util

以下接口在Util对象内,须通过Protobuf.Util方式调用。

fetch

static fetch(path:string, callback?:(content?:string)=> void):string|undefined.

获取文件内容,需要先设置资源文件读取对象ResourceManager。

参数:

参数名类型必填说明
pathstring资源文件路径。
callback(content?:string)=> void回调接收资源的内容。如果省略,资源将被同步获取。如果请求失败,内容将为空。

返回值:

类型说明
string | undefined资源文件内容。

toCamelCase

static toCamelCase(str:string):string;

用于将字符串转换为驼峰格式。

参数:

参数名类型必填说明
strstring将字符串转换为驼峰格式。

返回值:

类型说明
string驼峰格式字符串。

Builder

构建协议消息体的构建器,提供构建协议消息的功能。

isMessage

static isMessage(def:Object):boolean;

用于判断指定对象是否为消息体。

参数:

参数名类型必填说明
defObject判断指定对象是否为消息体。

返回值:

类型说明
boolean指示对象是否为消息体。

isMessageField

static isMessageField(def:Object):boolean;

用于判断指定对象是否为消息体的字段。

参数:

参数名类型必填说明
defObject判断指定对象是否为消息体的字段。

返回值:

类型说明
boolean指示对象是否为消息体的字段。

isEnum

static isEnum(def:Object):boolean;

用于判断指定对象是否为枚举对象。

参数:

参数名类型必填说明
defObject判断指定对象是否为枚举对象。

返回值:

类型说明
boolean指示对象是否为枚举对象。

build

build(path?: string | string[]) : Protobuf.Builder.Message | Object;

用于构建协议,解析所有定义,返回构建的协议消息包。

参数:

参数名类型必填说明
pathstring | string[]协议内包完整路径。

返回值:

类型说明
Protobuf.Builder.Message | Object协议消息包。

lookup

lookup(path?: string, excludeNonNamespace?: boolean) : ProtoBuf.Reflect.T;

用于构建协议消息包。

参数:

参数名类型必填说明
pathstring协议内包完整路径。
excludeNonNamespaceboolean排除非命名空间类型,如fields,默认为false。

返回值:

类型说明
ProtoBuf.Reflect.T反射的描述。

Message

提供协议消息体的编解码方法。

constructor

new Message(values:Object);

构建消息体实例。

参数名类型必填说明
valuesObject符合协议消息体结构的数据对象。

encode

static encode(data: Object, buffer?: ByteBuffer | boolean, noVerify?: boolean):ByteBuffer;

将协议消息体编码为ByteBuffer格式。

参数:

参数名类型必填说明
datastring消息体对应的数据。
bufferboolean指定编解码结果的ByteBuffer对象,如果未指定,将创建一个新的。
noVerifyboolean是否不验证字段值,默认为false。

返回值:

类型说明
ByteBuffer协议消息体数据编码后的ByteBuffer数据。

encode

encode(buffer?: ByteBuffer| boolean, noVerify?: boolean): ByteBuffer;

将消息编码为ByteBuffer格式数据。

参数:

参数名类型必填说明
bufferstring指定编解码结果的ByteBuffer对象,如果未指定,将创建一个新的。
noVerifyboolean是否不验证字段值,默认为false。

返回值:

类型说明
ByteBuffer协议消息体数据编码后的ByteBuffer数据。

encodeAB

encodeAB():ArrayBuffer;

将消息编码为ArrayBuffer格式。

返回值:

类型说明
ArrayBuffer协议消息体数据编码后的ArrayBuffer数据。

toArrayBuffer

toArrayBuffer():ArrayBuffer;

encodeAB方法的别名,用于将消息编码为ArrayBuffer格式。

返回值:

类型说明
ArrayBuffer协议消息体数据编码后的ArrayBuffer数据。

calculate

calculate(): Number;

计算消息体长度。

返回值:

类型说明
Number协议消息体的长度。

encodeDelimited

encodeDelimited(buffer?: ByteBuffer| boolean, noVerify?: boolean): ByteBuffer;

将消息编码为ByteBuffer格式数据。

参数:

参数名类型必填说明
bufferstring指定编解码结果的ByteBuffer对象,如果未指定,将创建一个新的。
noVerifyboolean是否不验证字段值,默认为false。

返回值:

类型说明
ByteBuffer协议消息体数据编码后的ByteBuffer数据。

encode64

encode64(): string;

将消息编码为base64编码的字符串。

返回值:

类型说明
string将消息编码为base64编码的字符串。

toBase64

toBase64(): string;

encode64方法的别名,将消息编码为base64编码的字符串。

返回值:

类型说明
string将消息编码为base64编码的字符串。

encodeHex

encodeHex(): string;

将消息编码为十六进制编码的字符串。

返回值:

类型说明
string将消息编码为十六进制编码的字符串。

toHex

toHex(): string;

encodeHex方法的别名,将消息编码为十六进制编码的字符串。

返回值:

类型说明
string将消息编码为十六机制编码的字符串。

encodeJson

encodeJson(): string;

将消息编码为Json字符串。

返回值:

类型说明
string将消息编码为Json字符串。

toRaw

toRaw(binaryAsBase64?:boolean, longsAsStrings:boolean):Object;

返回消息的原始负载。

参数:

参数名类型必填说明
databinaryAsBase64boolean指示是否包含二进制数据作为base64字符串而不是缓冲区,默认为false。
longsAsStringsboolean指示是否将long编码为字符串。

返回值:

类型说明
Object返回消息的原始负载。

decode

static decode(data: ByteBuffer|ArrayBuffer|Buffer|string, length?: Number| string, enc?: string):Protobuf.Builder.Message;

从指定的缓冲区或字符串解码消息。

参数:

参数名类型必填说明
dataByteBuffer | ArrayBuffer | Buffer | string要解码的数据。
lengthNumber | string消息体长度,默认解码所有数据。
encstring如果缓冲区是字符串,将进行编码,支持hex,base64,utf8(不推荐),默认为base64

返回值:

类型说明
Protobuf.Builder.Message从指定的缓冲区或字符串解码消息。

decode64

static decode64(str:string):Protobuf.Builder.Message;

从指定的base64编码字符串解码消息。

参数:

参数名类型必填说明
strstring要解码的base64编码字符串数据。

返回值:

类型说明
Protobuf.Builder.Message从指定的base64编码字符串解码消息。

decodeHex

static decodeHex(str:string):Protobuf.Builder.Message;

从指定的十六进制编码字符串解码消息。

参数:

参数名类型必填说明
strstring要解码的十六进制编码字符串数据。

返回值:

类型说明
Protobuf.Builder.Message从指定的十六进制编码字符串解码消息。

decodeJson

static decodeJson(str:string):Protobuf.Builder.Message;

从JSON字符串解码消息。

参数:

参数名类型必填说明
strstring从JSON字符串解码消息。

返回值:

类型说明
Protobuf.Builder.Message从JSON字符串解码消息。

decodeDelimited

static decodeDelimited(buffer: ByteBuffer | ArrayBuffer | Buffer | string, enc?: string):Protobuf.Builder.Message;

从指定的缓冲区或字符串解码以长度分隔的varint32消息。

参数:

参数名类型必填说明
bufferByteBuffer | ArrayBuffer | Buffer | string指定的缓冲区或字符串。
encstring如果缓冲区是字符串,将进行编码,支持hex,base64,utf8(不推荐),默认为base64。

返回值:

类型说明
Protobuf.Builder.Message从指定的缓冲区或字符串解码以长度分隔的varint32消息。

约束与限制

在下述版本验证通过:

  • DevEco Studio: 4.0 (4.0.3.512), SDK: API10 (4.0.10.9)
  • DevEco Studio: 4.0 Release(4.0.3.413), SDK: API10 (4.0.10.3)

目录结构

|---- protobuf
|     |---- AppScrope  # 示例代码文件夹
|     |---- entry  # 示例代码文件夹
|     |---- protobufjs  # protobufjs库文件夹
|           |---- src/main  # 模块代码
|                |---- ets/   # 模块代码
|                     |---- dist     # 打包文件
|            |---- index.ets          # 入口文件
|            |---- .ohpmignore        # ohpm发布的忽略文件
|            |---- *.json5      # 配置文件
|     |---- README.md  # 安装使用方法
|     |---- README.OpenSource  # 开源说明
|     |---- CHANGELOG.md  # 更新日志

如果想更深入的学习 OpenHarmony (鸿蒙南向)全栈开发的内容,可以参考以下学习文档:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://gitee.com/MNxiaona/733GH

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值