HarmonyOS ArkTS Protobuf 生成器

为 HarmonyOS (ArkTS) 项目量身定制的 Protobuf 代码生成器。生成纯 ArkTS 代码,无需依赖任何第三方库(如 protobufjs 运行时),直接在鸿蒙系统上运行,支持 API 12+Sendable 并发模型。

✨ 核心特性

  • 纯 ArkTS 实现:零外部依赖,生成的代码直接包含轻量级运行时 (Writer/Reader)。
  • 完全合规:遵循 ArkTS 语法规范(无 any,静态类型,严格属性访问),支持 API 12+
  • 强类型支持
    • int64/uint64 可选映射为 bigint(推荐)或 number
    • 完整支持 oneofmaprepeated 等复杂类型。
  • 双重序列化
    • Binary:基于 Visitor 模式的高性能 Protobuf 二进制编解码。
    • JSON:可选生成标准 toJson/fromJson,支持 Google WKT (Timestamp, Duration, Any 等)。
  • 鸿蒙优化
    • 支持 @Sendable 装饰器,生成的对象可在 Actor 间传递。
    • 采用按需导出 (Named Exports) 优化编译速度与 Tree-shaking,显著降低多模块引用时的编译耗时。
  • 服务桩代码:自动生成 Client 类,支持自定义 RpcTransport 对接任意网络库(HTTP/WebSocket)。

🛠️ 环境要求

  • Node.js: >= 16.0.0
  • DevEco Studio: >= 5.0 (支持 ArkTS)

⚡️ 性能优化建议

为了获得最佳的编译性能,建议在生成的模块所在的 hvigor-config.json5 中添加以下配置:

{
  "properties": {
    "ohos.compile.lib.entryfile": true,    // 启用入口文件编译优化
    "ohos.arkCompile.singleFileEmit": true // 加速文件写入
  }
}

🚀 快速开始

1. 安装与配置

本工具通常作为项目内的开发依赖或独立构建工具使用。

# 克隆仓库
git clone https://gitcode.com/xiaofenger_705/protobuf-arkts-generator.git
cd protobuf-arkts-generator

# 安装依赖
npm install

2. 准备 Proto 文件

将你的 .proto 文件放置在项目的某个目录下,例如 protos/

// protos/user.proto
syntax = "proto3";
package user;

message UserInfo {
  string name = 1;
  int32 age = 2;
  bool is_active = 3;
}

3. 执行生成

使用 CLI 脚本生成代码到指定目录(例如 entry/src/main/ets/generated)。

# 基本用法
node src/generator/arkpb-gen.js \
  --in ./protos \
  --out ./entry/src/main/ets/generated \
  --int64 bigint \
  --docs on

4. 在项目中集成

生成的目录结构如下:

generated/
  ├── protobuf-core/    # 自动复制的运行时库 (Writer, Reader, etc.)
  ├── user/             # 包名对应的目录
  │   ├── messages/     # 消息类
  │   ├── enums/        # 枚举
  │   └── index.ets     # 模块导出
  └── index.ets         # 根导出

📖 使用指南

消息对象的创建与序列化

import { UserInfo } from '../generated/user';
import { Writer, Reader } from '../generated/protobuf-core';

// 1. 创建消息对象 (使用 create 静态方法或 new)
const user = UserInfo.create({
  name: "ArkTS Developer",
  age: 25,
  isActive: true
});

// 2. 序列化为二进制 (Uint8Array)
const bytes = UserInfo.encode(user).finish();
// 或者使用便捷方法:
// const bytes = UserInfo.toBinary(user);

// 3. 反序列化
const decodedUser = UserInfo.decode(new Reader(bytes));
// 或者:
// const decodedUser = UserInfo.fromBinary(bytes);

console.info(`Name: ${decodedUser.name}`);

JSON 转换

如果在生成时开启了 --json on

node src/generator/arkpb-gen.js ... --json on --json-enum names
// 转换为 JSON 对象
const jsonParams = UserInfo.toJson(user);
// { "name": "...", "age": 25, "is_active": true }

// 从 JSON 对象解析
const userFromJson = UserInfo.fromJson(jsonParams);

服务调用 (RPC)

生成的 Client 类需要注入一个 RpcTransport 实现来处理实际的网络请求。

import { RpcTransport } from '../generated/protobuf-core';
import { UserServiceClient } from '../generated/user';

// 实现传输层 (适配鸿蒙网络栈)
class MyHttpTransport implements RpcTransport {
  async unary(method: string, data: Uint8Array, headers?: Record<string, string>): Promise<Uint8Array> {
    // 示例:使用 http 模块发送 POST 请求
    // const resp = await http.request(...)
    // return new Uint8Array(resp.result);
    return new Uint8Array(); // 占位
  }
}

// 使用生成的客户端
const client = new UserServiceClient(new MyHttpTransport());
const response = await client.GetUser(UserInfo.create({ name: "Alice" }));

⚙️ CLI 选项说明

选项 说明 默认值 示例
--in .proto 文件所在的输入目录 必填 ./protos
--out 生成代码的输出目录 必填 ./src/main/ets/pb
--int64 64位整数处理模式 (bigint | number) number bigint (推荐)
--json 是否生成 JSON 转换方法 (on | off) off on
--json-enum 枚举的 JSON 序列化策略 number names
--docs 是否生成 JSDoc 注释 off on
--omit-defaults 二进制编码时是否省略默认值 off on
--concurrent 是否添加 @Sendable 装饰器 off sendable
--bundle-runtime 是否自动复制运行时库 on off

🤝 贡献与反馈

欢迎提交 Issue 或 Pull Request 来改进本项目。

  • Bug 反馈: 请附带复现用的 .proto 文件和错误日志。
  • 代码规范: 请确保修改后的代码通过 npm run arkts:check (如有)。

📄 License

MIT License