protobufjs

本项目基于 protobufjs 开发。

简介

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

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

下载安装

ohpm install @ohos/protobufjs

OpenHarmony ohpm环境配置等更多内容,请参考 如何安装OpenHarmony ohpm包

约束与限制

兼容性

在下述版本验证通过:

  • DevEco Studio: 6.0.2 Release(6.0.2.642), SDK: API12 Release(5.0.0.71);

权限要求

使用示例

// user.js为protobufjs-cli生成的文件,已经按照使用说明替换相关文件,可参考demo提供的示例文件

import { user } from './user.js';

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button('编码并解码')
        .onClick(() => {
          // 创建消息对象
          let message = user.UserLoginResponse.create({
            sessionId: '215135415351435',
            userPrivilege: 'John123',
            isTokenType: false
          });

          // 执行编码
          let bytes: Uint8Array = user.UserLoginResponse.encode(message).finish();

          // 执行解码并输出结果
          let decoded = user.UserLoginResponse.decode(bytes);
          // 打印结果:`sessionId=215135415351435, userPrivilege=John123`
          console.info(`protobufjs decode result: sessionId=${decoded.sessionId}, userPrivilege=${decoded.userPrivilege}`);
        });
    }
    .width('100%')
    .height('100%');
  }
}

使用说明

1. 定义 proto 文件

在业务目录创建 proto 文件,按照.proto文件格式定义消息体结构,例如 user.proto:

syntax = "proto3";

package user;

message UserLoginResponse {
  string sessionId = 1;
  string userPrivilege = 2;
  bool isTokenType = 3;
  int64 formatTimestamp = 5;
  bytes data = 6;
}

2. 生成 js 与 d.ts 文件

// 全局安装protobufjs
npm install -g protobufjs@7.2.4
// 全局安装protobufjs-cli
npm install -g protobufjs-cli
//在.proto文件目录下执行下列命令
pbjs -t static-module -w es6 -o user.js user.proto
pbts user.js -o user.d.ts

3. 修改生成文件中的导入

将生成的js文件中的 import * as $protobuf from "protobufjs/minimal";修改为:

// user.js
import $protobuf from '@ohos/protobufjs';
import Long from 'long';
$protobuf.util.Long = Long;
$protobuf.configure();

将生成的.d.ts文件中的 import * as $protobuf from "protobufjs";修改为:

// user.d.ts
import $protobuf from '@ohos/protobufjs';

4. 安装依赖并集成到工程

ohpm install long

将生成后的 user.js 与 user.d.ts 复制到应用工程,再按“使用示例”执行 create、encode、decode。

proto编码

import { user } from './user.js';

 let msg = user.UserLoginResponse.create({
     sessionId: "testSynchronouslyLoadProtoFile",
     userPrivilege: "John123",
     isTokenType: false,
     formatTimestamp: 12342222
 });
 
 let bytes: Uint8Array = user.UserLoginResponse.encode(msg).finish();

proto解码

let decoded = user.UserLoginResponse.decode(bytes);

5. BigInt使用

// 在生成的js文件中 将$protobuf.util.Long 设置为undefined
import Long from 'long';
$protobuf.util.Long = undefined;
$protobuf.configure();

let msg = user.UserLoginResponse.create({
  sessionId: "215135415351435",
  userPrivilege: "John123",
  isTokenType: false,
  formatTimestamp: BigInt("9223372036854775807")
});

注意:本demo的user.d.ts代码文件,formatTimestamp属性支持的BigInt类型是当手动添加,并非通过任何命令生成。

6.protobufjs-cli使用说明

在文件格式之间转换并生成静态代码
  -t, --target 指定目标格式,可以接受需要自定义目标的路径。
                   json          JSON
                   json-module   JSON表示为模块
                   proto2        Protocol Buffers, Version 2
                   proto3        Protocol Buffers, Version 3
                   static        无反射的静态代码(本身不起作用)
                   static-module 无反射模块的静态代码
  -p, --path 将某个目录添加到包含路径中
  -o, --out 保存文件而非写入到标准输出
  --sparse 只导出从主文件引用的类型(实验)
  仅限模块目标:
  -w, --wrap       指定要使用的包装器,可接受需要自定义包装器的路径。
                   default   默认包装器支持CommonJSAMD标准
                   commonjs  CommonJS包装器
                   amd       AMD包装器
                   es6       ES6包装器
                   closure   添加到全局protobuf的protobuf.roots上的闭包
  --dependency     指定protobuf版本,可接受有效的模块ID。
  -r, --root       指定备用的protobuf.roots名称
  -l, --lint       Linter配置,默认protbuf.js兼容规则:
                   eslint-disable block-scoped-var, id-length, 
                   no-control-regex, no-magic-numbers, no-prototype-builtins, 
                   no-redeclare, no-shadow, no-var, sort-vars
  --es6            启用ES6语法
  仅限原始源:
  --keep-case      保留字段大小写而非是转换为驼峰大小写
  仅限静态目标:
  --no-create      不生成用于反射兼容性的创建函数.
  --no-encode      不生成编码函数.
  --no-decode      不生成解码函数.
  --no-verify      不生成验证函数.
  --no-convert     不生成转换函数
  --no-delimited   不生成风格的编码/解码函数.
  --no-beautify    不美化生成的代码.
  --no-comments    不输出任何JSDoc注释.
  --force-long     强制对s-/u-/int64和s-/fixed64字段使用Long
  --force-number   强制对s-/u-/int64和s-/fixed64字段使用number
  --force-message  强制使用消息而非普通对象

详细使用方式请参考:https://github.com/protobufjs/protobuf.js/blob/master/cli/README.md

7. 常见问题定位

  • 若提示 Cannot find module 相关错误,先检查工程是否已安装 protobufjs 依赖链中的必需包。
  • 若 int64 字段值异常,优先检查是否已设置 $protobuf.util.Long 并执行 $protobuf.configure()。
  • 若使用分包或 HSP 场景,请确认导出模块路径和依赖包均可被目标模块解析。

接口说明

API

名称 类型 参数 返回值 必填 OpenHarmony平台支持 描述
create() 方法 properties?: Object Object 生成Message对象
encode() 方法 message: Object, writer?: $protobuf.Writer $protobuf.Writer 编码消息
decode() 方法 reader: $protobuf.Reader/Uint8Array, length?: number Object 解码消息
verify() 方法 message: Object string/null 验证消息有效性
fromObject() 方法 object: Object Object 从纯对象创建此类型的新消息。还将值转换为各自的内部类型
toObject() 方法 message: Object, options?: $protobuf.IConversionOptions Object 将一个由键及其各自的值组成的数组转换为对象,省略未定义的值

关于混淆

  • 代码混淆请参考 代码混淆简介
  • 若希望 protobufjs 在混淆后仍可正常调用,请在对应模块的 obfuscation-rules.txt 中添加排除规则:
-keep
./oh_modules/@ohos/protobufjs

常见问题

1. 提示缺少依赖模块

请确认已执行 ohpm install,并在工程中安装 long 与库自身依赖。

2. BigInt/int64 转换异常

请确认生成代码中已按文档设置 Long 或按业务要求将 util.Long 设为 undefined。

3. 生成代码导入失败

请确认 user.js、user.d.ts 中的 protobufjs 导入路径均已改为 @ohos/protobufjs。

目录结构

protobuf
├── AppScope/                     # 应用级配置
├── entry/                        # 示例工程
│   └── src/main/ets/pages/       # 示例页面与生成代码
├── library/                      # 核心库模块
│   └── src/main/ets/             # protobufjs 主体代码与类型声明
├── README.md                     # 英文文档
├── README_zh.md                  # 中文文档
├── CHANGELOG.md                  # 版本变更记录
└── README.OpenSource             # 开源声明

贡献代码

使用过程中发现问题可以提交 Issue,也欢迎提交 PR 共同完善。

开源协议

本项目基于 BSD 3-Clause License 开源。