使用Protobuf
大约 2 分钟
使用Protobuf
Protobuf是一种语言无关、平台无关、可扩展的序列化结构化数据协议,常用于高效传输和存储结构化数据。
在本章节,我们将学习如何在Kuikly跨端层处理Protobuf数据。
在Kuikly中使用Protobuf,主要包括数据类生成、编解码、二进制数据传输几个步骤。
数据类生成
我们使用Square Wire的Kotlin Multiplatform版本来实现Protobuf的数据类生成以及后续的编解码。
先看一个简单的例子,我们定义了以下Protobuf数据结构:
syntax = "proto3";
// 用户性别枚举定义
enum Gender {
NOT_SPECIFIED = 0;
MALE = 1;
FEMALE = 2;
}
// 用户信息
message User {
int64 id = 1;
string name = 2;
int32 age = 3;
Gender gender = 4;
}
根据项目的kotlin版本,下载对应的Wire Compiler: https://search.maven.org/remote_content?g=com.squareup.wire&a=wire-compiler&c=jar-with-dependencies&v=LATEST
提示
- 把
LATEST
替换为项目匹配的版本号
命令行执行:
java -jar wire-compiler-VERSION-jar-with-dependencies.jar \
--proto_path=SRC_PATH \
--kotlin_out=DST_PATH
生成的数据类在DST_PATH
// Code generated by Wire protocol buffer compiler, do not edit.
// Source: User in sample.proto
@file:Suppress("DEPRECATION")
...
/**
* 用户信息
*/
public class User(
@field:WireField(...)
public val id: Long = 0L,
@field:WireField(...)
public val name: String = "",
@field:WireField(...)
public val age: Int = 0,
@field:WireField(...)
public val gender: Gender = Gender.NOT_SPECIFIED,
unknownFields: ByteString = ByteString.EMPTY,
) : Message<User, Nothing>(ADAPTER, unknownFields) {
...
public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<User> = object : ProtoAdapter<User>(...) {...}
}
}
提示
wire-compiler
版本需要跟编解码的wire-runtime
版本保持一致- 可以把数据类生成步骤配置成
JavaExec
类型的Gradle Task,在编译时动态生成,以便同时适配多个Kotlin版本
编码 / 解码
在项目的build.gradle.kts中,配置wire-runtime
依赖:
dependencies {
implementation("com.squareup.wire:wire-runtime:$WIRE_VERSION")
}
编写业务逻辑:
// 编码
val user = User(
id = id,
name = name,
age = age,
gender = gender
)
val bytes: ByteArray = user.encode()
// 解码
val user = User.ADAPTER.decode(bytes)
提示
更多用法请参考Wire官方API文档
二进制数据传输
配合自定义Module的ByteArray数据接口,以实现Protobuf的二进制数据传输/发送。
Module接口示例:
internal class BridgeModule : Module() {
override fun moduleName(): String {
return MODULE_NAME
}
fun sendProtobuf(data: ByteArray, callback: ((ByteArray) -> Unit)?) {
// 异步调用Native方法(native侧在主线程执行),传输基本类型数组,回调基本类型
asyncToNativeMethod(METHOD_SEND_PB, arrayOf(data)) {
callback?.invoke(it as? ByteArray ?: byteArrayOf())
}
}
...
}