protobuf-arkts-generator
v0.1.1
Published
HarmonyOS ArkTS Protobuf 代码生成器,纯 ArkTS 运行时与服务客户端
Maintainers
Readme
HarmonyOS ArkTS Protobuf 生成器
为 HarmonyOS ArkTS 项目生成纯 ArkTS 的 Protobuf 代码(消息、枚举、服务存根),内置轻量运行时,不依赖第三方库,开箱即用。
- 强类型:64 位整型可选
bigint|number - JSON 支持:可选生成
toJson/fromJson,内置 WKT(Timestamp/Duration/Any/Struct/Value/ListValue/FieldMask)映射 - 服务客户端:生成
*Client,通过自定义RpcTransport进行 unary 调用 - 路径与索引:自动分包、构建
index.ets聚合导出
环境要求
- Node.js 16+
- HarmonyOS DevEco Studio(或 CLI)用于集成 ArkTS 代码
快速开始
- 克隆并安装依赖:
npm install - 将你的
.proto文件放到一个输入目录,例如./protos(仓库已附带示例)。 - 运行生成:
npx arkpb-gen --in ./protos --out ./packages --int64 bigint --docs on - 生成结果在
./packages下:packages/<pkg>/messages/*.ets、enums/*.ets、services/*.etspackages/<pkg>/index.ets(聚合导出)- 运行时被复制到
packages/protobuf-core/;示例导入:
import { Writer, Reader } from '../protobuf-core'HarmonyOS 集成指南
将生成产物引入你的 HarmonyOS ArkTS 项目,有两种常见方式:
方式 A:直接拷贝源码
- 在应用模块(例如
entry)内创建目录:entry/src/main/ets/protobuf-core/(复制packages/protobuf-core/*)entry/src/main/ets/pb/(复制你生成的包目录,如packages/user/、packages/google/等)
- 在 ArkTS 代码中按相对路径导入并使用:
import { Writer, Reader } from '../protobuf-core'
import { UserLoginResponse } from '../pb'
const w = new Writer()
const buf = UserLoginResponse.encode(UserLoginResponse.create({
sessionId: 'x', userPrivilege: 'y', isTokenType: false, formatTimestamp: 0n
}), w).finish()
const decoded = UserLoginResponse.decode(new Reader(buf))方式 B:单独模块/库
- 将
packages/作为独立模块(或库工程)引入,并在应用模块中通过路径或别名导入。 - 保证
protobuf-core位于生成包的同级(默认目录名可配)。
服务调用(实现 RpcTransport)
生成的 *Client 通过 RpcTransport 发送请求:
import { RpcTransport } from '../protobuf-core'
class HttpTransport implements RpcTransport {
async unary(path: string, req: Uint8Array, md?: Record<string,string>): Promise<Uint8Array> {
// 在此使用 HarmonyOS 的网络能力(例如 HTTP/WebSocket)发送二进制并返回二进制响应
// 伪代码:
// const resBytes: Uint8Array = await httpPostBinary(baseUrl + path, req, md)
// return resBytes
return new Uint8Array(0)
}
}使用客户端:
import { DemoClient } from '../pb'
const t = new HttpTransport()
const cli = new DemoClient(t)
// const res = await cli.UseA(Common.create({ id: 123 }))编码/解码示例
import { Writer, Reader } from '../protobuf-core'
import { UserLoginResponse } from '../pb'
const m = UserLoginResponse.create({ sessionId: 's', userPrivilege: 'p', isTokenType: false, formatTimestamp: 0n })
const b = UserLoginResponse.toBinary(m)
const m2 = UserLoginResponse.fromBinary(b)JSON 往返示例
import { UserLoginResponse } from '../pb'
const m = UserLoginResponse.create({ sessionId: 's', userPrivilege: 'p', isTokenType: true, formatTimestamp: 123n })
const j = UserLoginResponse.toJson(m)
const m2 = UserLoginResponse.fromJson(j)map 字段示例
import { ExampleMapMsg, Demo } from '../pb'
const mp = new Map<string, Demo>()
mp.set('k1', Demo.create({ v: 1 }))
mp.set('k2', Demo.create({ v: 2 }))
const m = ExampleMapMsg.create({ items: mp })oneof 字段示例
import { ExampleOneof } from '../pb'
const m1 = ExampleOneof.create({ content: { kind: 'text', text: 'hello' } })
const m2 = ExampleOneof.create({ content: { kind: 'image', image: new Uint8Array([1,2,3]) } })CLI 选项详解
--in <dir>:输入.proto根目录(支持子目录递归)--out <dir>:输出 ArkTS 目录--int64 bigint|number:64 位整型模式bigint:精度安全,推荐number:可能失精度;使用Reader.int64Number()/uint64Number()
--docs on|off:是否输出注释(消息/字段/oneof/枚举/成员/服务/方法)--omit-defaults on|off:编码时省略默认值(标量/枚举),消息字段不省略--json on|off:生成toJson/fromJson- 标量直映;
bytes→Base64;int64(bigint)→字符串 map:对象映射(键统一字符串化);oneof:按被选键展开- WKT:Timestamp/Duration/Any/Struct/Value/ListValue/FieldMask 支持
- 标量直映;
--json-enum names|numbers|accept-both:枚举 JSON 策略names:序列化为名称;反序列化按名称accept-both:反序列化同时接受名称与数值(序列化仍按当前模式)
--json-strict on|off:fromJson类型严格校验--concurrent sendable|off:为消息/服务添加@Sendable标注--namespace-as-file on|off:按包层级拆分目录并构建分层索引--bundle-runtime on|off:复制运行时至输出并重写导入路径,默认on--runtime-dir <name>:运行时子目录名,默认protobuf-core
编译结果示例
输入:
syntax = "proto3";
package user;
message UserLoginResponse {
string sessionId = 1;
string userPrivilege = 2;
bool isTokenType = 3;
int64 formatTimestamp = 5;
bytes data = 6;
}输出(简化):packages/user/messages/UserLoginResponse.ets
import { Writer, Reader } from '../../protobuf-core'
export class UserLoginResponse {
sessionId: string | undefined
userPrivilege: string | undefined
isTokenType: boolean | undefined
formatTimestamp: bigint | undefined
data: Uint8Array | undefined
// ... encode/decode/verify/toBinary/fromBinary
}高级用法
省略默认值
node ./src/generator/arkpb-gen.js --in ./protos --out ./packages --int64 bigint --omit-defaults on启用 JSON 与 WKT
node ./src/generator/arkpb-gen.js --in ./protos --out ./packages --int64 bigint --json on --json-enum names常见问题(FAQ)
- 枚举十六进制负值:生成器已预处理
= -0x...为十进制负数 - 索引文件为空:已采用“合并写入”避免被后续覆盖清空
int64 number精度:超过Number.MAX_SAFE_INTEGER会失精度,推荐bigint- Base64:
bytes在 JSON 中使用 Base64 字符串,运行时提供encodeBase64/decodeBase64
ArkTS 兼容性注意事项
- 导入路径不带扩展名:不要在
import/export中写.ets后缀 - 保留字字段自动避让:生成的属性名会使用安全标识符(例如
export_),JSON 键保持原字段名 - 不使用
any/unknown与索引签名:verify与fromJson采用显式类型与object - 运行时不依赖
TextEncoder/TextDecoder:使用纯算法 UTF-8 编解码 - 禁止下标访问字符串/字节数组:运行时 Base64 与 UTF-8 使用
DataView.getUint8与string.charAt
目录结构
src/generator/arkpb-gen.js:生成器 CLIruntime/arkpb/*:运行时源码(Writer/Reader/util/RpcTransport)protos/:示例协议(用于本仓库验证)packages/:默认输出目录(执行后生成)
完整命令清单(参考)
# 基本生成(bigint,带注释)
npx arkpb-gen --in ./protos --out ./packages --int64 bigint --docs on
# 生成 JSON API 与 WKT 映射
npx arkpb-gen --in ./protos --out ./packages --int64 bigint --json on --json-enum names
# 打开并发标注与分层目录
npx arkpb-gen --in ./protos --out ./packages --int64 bigint --docs on --json on --concurrent sendable --namespace-as-file on
# 自定义运行时目录名
npx arkpb-gen --in ./protos --out ./packages --int64 bigint --runtime-dir protobuf-core如需将生成过程集成到你的构建流水线,可在工程脚本中调用上述命令并自动拷贝到 ArkTS 项目模块下。若需要进一步的使用示例或问题定位,请在 Issues 中反馈。
