1

任何人都可以帮助我了解如何在 Kotlin 中生成 protobuf?我听说过gRPC, wire, KotlinPoet, 但我不明白有什么区别,我应该使用哪个样本,任何简单的文件请填写免费与我分享?任何人都可以提供一个示例链接,该链接显示如何为 Kotlin 生成 Protobuf 示例?

4

1 回答 1

2

我已经使用square/wireio.grpc库与 gRPC 服务进行通信。的问题wire是它还不支持 proto3 版本。

https://github.com/square/wire/issues/279

在这里,我将为您提供一个如何从io.grpc.

假设有一个 gRPC 服务可以汇总您发送给它的数字流。它的原型文件会是这样的:

累加器.proto

syntax = "proto3";

package accumulator;

service Accumulator {
    rpc NumberStream (stream NumberRequest) returns (stream AccumulateReply) {
    }
}

message NumberRequest {
    int32 number = 1;
}

message AccumulateReply {
    int64 sumUp = 1;
}

你应该把这个文件放在/src/main/proto/项目的目录下。

现在是时候将所需的依赖项添加到build.gradle文件中了。请注意,它用于kapt生成代码。


App Level 的 build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.protobuf'
apply plugin: 'kotlin-kapt'

android {
    
    ... others

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8
    }
}

protobuf {
    protoc { artifact = 'com.google.protobuf:protoc:3.10.0' }

    plugins {
        javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" }
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION
        }
    }

    generateProtoTasks {
        all().each { task ->
            task.plugins {
                javalite {}
                grpc { // Options added to --grpc_out
                    option 'lite'
                }
            }
        }
    }
}

dependencies {
    ... other dependencies

    // ------- GRPC
    def grpc_version = '1.25.0'
    implementation "io.grpc:grpc-android:$grpc_version"
    implementation "io.grpc:grpc-okhttp:$grpc_version"
    implementation "io.grpc:grpc-protobuf-lite:$grpc_version"
    implementation "io.grpc:grpc-stub:$grpc_version"

    // ------- Annotation
    def javax_annotation_version = '1.3.2'
    implementation "javax.annotation:javax.annotation-api:$javax_annotation_version"
}

项目级别的 build.gradle

buildscript {

    repositories {
        google()
        jcenter()
    }

    dependencies {
        ... others

        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
    }
}

这是一个用服务器封装流活动的类。它通过回调返回接收到的值:

累加器处理程序.kt

import android.content.Context
import io.grpc.ManagedChannel
import io.grpc.android.AndroidChannelBuilder
import io.grpc.stub.ClientCallStreamObserver
import io.grpc.stub.StreamObserver
import accumulator.AccumulatorOuterClass
import java.util.concurrent.Executors


/**
 * @author aminography
 */
class AccumulatorHandler constructor(
    private val context: Context,
    private val endPoint: String
) {

    var callback: AccumulatorCallback? = null

    private var managedChannel: ManagedChannel? = null

    private var requestObserver: StreamObserver<AccumulatorOuterClass.NumberRequest>? = null

    private val responseObserver: StreamObserver<AccumulatorOuterClass.AccumulateReply> =
        object : StreamObserver<AccumulatorOuterClass.AccumulateReply> {

            override fun onNext(value: AccumulatorOuterClass.AccumulateReply?) {
                callback?.onReceived(value.sumUp)
            }

            override fun onError(t: Throwable?) {
                callback?.onError(t)
            }

            override fun onCompleted() {
                callback?.onCompleted()
            }
        }

    fun offer(number: Int) {
        initChannelIfNeeded()
        requestObserver?.onNext(
            AccumulatorOuterClass.NumberRequest.newBuilder()
                .setNumber(number)
                .build()
        )
    }

    fun offeringFinished() {
        requestObserver?.onCompleted()
    }

    private fun initChannelIfNeeded() {
        if (managedChannel == null) {
            managedChannel = AndroidChannelBuilder.forTarget(endPoint)
                .context(context)
                .usePlaintext()
                .executor(Executors.newSingleThreadExecutor())
                .build()
        }
        if (requestObserver == null) {
            requestObserver = AccumulatorGrpc.newStub(managedChannel)
                .withExecutor(Executors.newSingleThreadExecutor())
                .numberStream(responseObserver)
        }
    }

    fun release() {
        (requestObserver as? ClientCallStreamObserver<*>)?.cancel("Cancelled by client.", null)
        requestObserver = null

        managedChannel?.shutdown()
        managedChannel = null

        callback = null
    }

    interface AccumulatorCallback {
        fun onReceived(sum: Long)
        fun onError(t: Throwable?)
        fun onCompleted()
    }

}

为了测试它,我编写了一个活动类来以简单的方式显示它的用法:

我的活动.kt

/**
 * @author aminography
 */
class MyActivity: AppCompatActivity, AccumulatorHandler.AccumulatorCallback {

    private var accumulatorHandler: AccumulatorHandler? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        accumulatorHandler = AccumulatorHandler(applicationContext, "http://...")
        accumulatorHandler.callback = this

        for (number in 1..10){
            accumulatorHandler.offer(number)
        }
        accumulatorHandler.offeringFinished()
    }

    override fun onReceived(sum: Long) {
        Toast.makeText(this, "onReceived: $sum", Toast.LENGTH_SHORT).show()
    }

    override fun onError(t: Throwable?) {
        Toast.makeText(this, "onError: $t", Toast.LENGTH_SHORT).show()
        accumulatorHandler.release()
    }

    override fun onCompleted() {
        Toast.makeText(this, "onCompleted", Toast.LENGTH_SHORT).show()
        accumulatorHandler.release()
    }
}
于 2020-06-28T07:30:29.280 回答