# OhpmProtobuf **Repository Path**: cuijiaojiao1/OhpmProtobuf ## Basic Information - **Project Name**: OhpmProtobuf - **Description**: No description available - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 34 - **Created**: 2023-04-28 - **Last Updated**: 2024-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # protobuf ## 介绍 ProtoBuf(protocol buffers) 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。,是一种灵活,高效,自动化机制的结构数据序列化方法比XML更小,更快,更为简单。 本项目主要是OpenHarmony系统下以[protobufjs](https://github.com/protobufjs/protobuf.js)为主要依赖开发,主要接口针对OpenHarmony系统进行合理的适配研发。 ## 下载安装 1.安装 临时版本:需使用本地依赖 ``` "dependencies": { "@ohos/protobuf": "file:../protobuf", "@ohos/bytebuffer": "file:../bytebuffer" } ``` 2.在需要使用的页面导入protobufjs ``` import protobuf from '@ohos/protobuf' ``` ## 使用说明 ### 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文件 .proto文件如放置工程资源文件夹内,可放置在 【resources->base->media】或【resources->rawfile】; 使用时需要通过文件管理系统(@ohos.fileio/@ohos.fs)写入设备内存中。 ``` syntax = "proto3"; package com.user; message UserLoginResponse{ string sessionId = 1; string userPrivilege = 2; bool isTokenType = 3; string formatTimestamp = 4; } ``` 4. .proto文件映射的json文件 同.proto文件规则一致,.json文件如放置工程资源文件夹内,可放置在 【resources->base->media】或【resources->rawfile】; 使用时需要通过文件管理系统(@ohos.fileio/@ohos.fs)写入设备内存中。 具体格式参照上面第二点。 ### 序列化与反序列化 #### 1. 解析字符串 ``` // 1.创建protbuf.Builder对象:用于构造协议消息体 var builder = protobuf.newBuilder(); // 2.加载proto字符串或json字符串:解析协议消息体定义 var root = protobuf.loadProto(protoStr,builder,"bench.proto"); 或 var root = protobuf.loadJson(protoJson, builder, fileName); // 3.构建协议消息体 // build()方法参数构建规则:proto协议中package+'.'+message名:如:com.user +'.'+UserLoginResponse,如无package字段,则设置为message名 var UserLoginResponse = root.build("com.user.UserLoginResponse"); // 4.实例Message消息体:通过builder找到协议名后会产生Message,创建符合协议结构的数据对象,作为参数实例协议消息体。 const userLogin = { sessionId: "testMethodLoadJson", userPrivilege: "John123", isTokenType: false, formatTimestamp: "12342222" }; var msg = new UserLoginResponse(userLogin); // 5.序列化:可用于通信传递或存储 var arrayBuffer = msg.toArrayBuffer(); // 6.反序列化:得到原始消息体内容 注意:一般情况下,序列化与反序列化不同处一处,实际开发过程中,需要按照 1,2,3步骤获取UserLoginResponse协议体后再进行反序列化 var decodeMsg = UserLoginResponse.decode(arrayBuffer); ``` #### 2.同步解析proto文件 // 注意:文件解析仅支持文件管理系统可读取路径;如Resource文件夹内文件需在解析协议定义前放置在文件管理系统可读取的路径内。 ``` import protobuf from '@ohos/protobuf' import util from '@ohos.util'; // 获取内存路径:需要通过globalThis存储操作对象及文件路径 // entry/src/main/ets/entryability/EntryAbility.ts globalThis.context = this.context; // 获取内存路径 let protoPath = globalThis.context.filesDir + "/userproto.proto"; // 通过resourceManager读取文件内容,通过文件管理系统写入内存 globalThis.context.resourceManager.getRawFileContent('userproto.proto') .then(data => { let textDecoder = util.TextDecoder.create("utf-8", { ignoreBOM: true }); let protoStr = textDecoder.decodeWithStream(data, { stream: false }); let protoPath = globalThis.context.filesDir + "/userproto.proto"; //将proto数据写入内存 FileUtils.getInstance().writeData(protoPath, protoStr); }); ``` // 同步解析proto文件 ``` let path = globalThis.context.filesDir + "/userproto.proto"; // 同步解析 var root = protobuf.loadProtoFile(path); if (!root) { console.error('protobuf readFile: builder is null|undefined.'); return; } var UserLoginResponse = root.build("com.user.UserLoginResponse"); const userLogin = { sessionId: "testMethodLoadJson", userPrivilege: "John123", isTokenType: false, formatTimestamp: "12342222" }; var msg = new UserLoginResponse(userLogin);// 实例协议消息体 var arrayBuffer = msg.toArrayBuffer();// 序列化 var decodeMsg = UserLoginResponse.decode(arrayBuffer);// 反序列化 ``` #### 3.异步解析proto文件 // 注意:文件解析仅支持文件管理系统可读取路径,参考【同步解析proto文件】 ``` let path = globalThis.context.filesDir + "/userproto.proto"; let builder = protobuf.newBuilder(); // 异步解析 var root = protobuf.loadProtoFile(path,(err,root)=>{ if (!root) { console.error('protobuf readFile: builder is null|undefined.'); return; } var UserLoginResponse = root.build("com.user.UserLoginResponse"); const userLogin = { sessionId: "testMethodLoadJson", userPrivilege: "John123", isTokenType: false, formatTimestamp: "12342222" }; var msg = new UserLoginResponse(userLogin);// 实例协议消息体 var arrayBuffer = msg.toArrayBuffer();// 序列化 var decodeMsg = UserLoginResponse.decode(arrayBuffer);// 反序列化 },builder); ``` #### 4.解析含有import字段的proto文件 // 注意:proto文件语法指定为 “proto3” ``` var builder = protobuf.newBuilder(); let path = globalThis.context.filesDir + "/imports.proto"; protobuf.loadProtoFile(path, (err, builder) => { if (err) { console.error('protobuf readFile failed: ' + err.name + " error message: " + err.message); return; } // 构建每个协议消息体 var test1Entity = builder.build('Test1') var test2Entity = builder.build('Test2') var test3Entity = builder.build('My.Test3') const test1 = { a: 150 } const test2 = { b: 'this is test2 666666666666666' } var messageTest1 = new test1Entity(test1); var messageTest2 = new test2Entity(test2); var test1ArrayBuffer = messageTest1.toArrayBuffer(); console.log("protobuf test1Message:" + messageTest1); console.log("protobuf test1ArrayBuffer:" + new Uint8Array(test1ArrayBuffer)); var decodeTest1Msg = test1Entity.decode(test1ArrayBuffer); console.log("protobuf decodeTest1Msg:" + JSON.stringify(decodeTest1Msg)); // 实例主协议消息体时,传入的参数需为实例后的协议消息对象 const test3 = { test1: messageTest1, test2: messageTest2 } var messageTest3 = new test3Entity(test3) console.log("protobuf messageTest3:" + JSON.stringify(messageTest3)); var test3ArrayBuffer = messageTest3.toArrayBuffer(); console.log("protobuf test3ArrayBuffer:" + new Uint8Array(test3ArrayBuffer)); this.bufferData = Array.prototype.toString.call(new Uint8Array(test3ArrayBuffer)); var decodeTest3Msg = test3Entity.decode(test3ArrayBuffer); console.log("protobuf decodeTest3Msg:" + JSON.stringify(decodeTest3Msg)); this.decodeData = JSON.stringify(decodeTest3Msg); }, builder); ``` #### 5.解析内嵌Message协议体的proto文件 ``` let path = globalThis.context.filesDir + "/qiantao.proto"; var builderQiantao = protobuf.loadProtoFile(path); if (!builderQiantao) { console.error('protobuf readFile: builder is null|undefined.'); return; } var QianTao = builderQiantao.build('ResultResponse'); const qiantaoEntity = { results: [ { url: 'url55555555555', title: "title666666666666666", spinner: ["array111", "array2222"] }, { url: 'url55555555555', title: "title666666666666666", spinner: ["array111", "array2222"] }] } var resultMessage = new QianTao(qiantaoEntity); // 实例协议消息体 console.log("protobuf resultMessage:" + JSON.stringify(resultMessage)); var arrayBufferResult = resultMessage.toArrayBuffer();// 序列化 console.log("protobuf qiantaoArrayBuffer:" + new Uint8Array(arrayBufferResult)); this.bufferData = Array.prototype.toString.call(new Uint8Array(arrayBufferResult)); var decodeQianTaoMsg = QianTao.decode(arrayBufferResult);// 反序列化 console.log("protobuf decode:" + JSON.stringify(decodeQianTaoMsg)); this.decodeData = JSON.stringify(decodeQianTaoMsg); ``` ## 接口说明 1, public static newBuilder(): any Constructs a new empty Builder. 2,builder.build(path:string) 构建协议消息体 3, .loadProtoFile(path); 同步解析proto文件的方式 4,.loadProtoFile(path, (err, root) => {} 异步解析proto文件的方式 5,.loadProto(proto, builder, fileName); 解析proto字符串方式 6,.loadJson(json, builder, fileName); 解析json字符串方式 7,.loadJsonFile(path); 同步解析json文件的方式 8,loadJsonFile(path, (err, root) => {} 异步解析json文件的方式 9,.toArrayBuffer(); 将Message序列化 10,.decode(buffer); 将buffer数据反序列化 ## 约束与限制 在下述版本验证通过: DevEco Studio: 3.1 Beta2(3.1.0.400), SDK: API9 (3.2.11.9) ## 目录结构 ``` |-ets | |- pages | |-index.ets #主页 | |-FileUtils.ets #File文件工具类 | |-MyFs.ets #fs适配封装 | |-multi_pb_serialized.ets #嵌套文件序列化与反序列化使用例子 | |-rpc.ets #rpc例子 | |-serialized.ets #序列化例子 | |-websocket.ets #websocket结合使用例子 | |-writer_reader.ets #writer_reader用例子 ``` ## 贡献代码 使用过程中发现任何问题都可以提 [Issue](https://gitee.com/openharmony-tpc/protobuf/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/protobuf/pulls) 。 ## 开源协议 本项目基于 [BSD License](https://gitee.com/openharmony-tpc/protobuf/blob/master/LICENSE) ,请自由地享受和参与开源。