【问题标题】:How can I generate protobuf in Kotlin for Android applications?如何在 Kotlin 中为 Android 应用程序生成 protobuf?
【发布时间】:2020-06-16 21:41:32
【问题描述】:

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

【问题讨论】:

    标签: android kotlin kotlinpoet square-wire


    【解决方案1】:

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

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

    在这里,我将提供一个示例,说明如何以io.grpc 开头。

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

    accumulator.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'
        }
    }
    

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

    AccumulatorHandler.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()
        }
    
    }
    

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

    MyActivity.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()
        }
    }
    

    【讨论】:

    • 嘿,谢谢你的回答,我没看到你在哪里添加依赖线?
    • 我看到你在 Kotlin 中使用,但想知道为 accumulator.proto 生成的类是 java 还是 Kotlin?
    • 不客气。我在回答中提到,这是一个使用io.grpc的实现。
    • 注:从3.3.0版本开始,wire正式支持Proto 3! github.com/square/wire/blob/master/CHANGELOG.md#version-330
    • @shoheikawano:太好了!感谢您在这里宣布。
    猜你喜欢
    • 2020-06-06
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多