gRPC in Android

1,688 阅读2分钟
原文链接: blog.csdn.net

最近公司客户端同服务器的交互方式都换成了grpc,什么是grpc呢?我们在以后再去了解,此篇的目的就是带大家了解在android中如何去使用grpc.

  1. grpc-java的github地址:https://github.com/grpc/grpc-java。大家可以去浏览一下里面的文档说明,不用动手。
  2. 对于Android程序员,我们需要重点关注的是:https://grpc.io/docs/quickstart/android/。按照文档的指示,我们需要:

    • clone代码:git clone -b v1.20.0 https://github.com/grpc/grpc-java
    • 克隆完毕后,进入到grpc-java/examples目录
    • 编译服务端代码:./gradlew installDist 这一步可能需要翻墙
    • 运行服务端代码:./build/install/examples/bin/hello-world-server

                  运行成功后,可以在终端看到以下信息:

                注意,这里说明了端口号50051,我们在稍后编写客户端代码的时候需要使用它。

 3. 新建Android Studio工程,然后: 

  • 在工程的build.gradle文件中添加:
buildscript {

    repositories {
        google()
        jcenter()
    }

    dependencies {

       classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.8"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        mavenLocal()
    }
}   
  • 在module的build.gradle文件中添加:
apply plugin: 'com.google.protobuf'
android{
    ...
}

// 和android以及dependencies平级
protobuf {
    protoc { artifact = 'com.google.protobuf:protoc:3.7.1' }
    plugins {
        javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" }
        grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.20.0' // CURRENT_GRPC_VERSION
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.plugins {
                javalite {}
                grpc { // Options added to --grpc_out
                    option 'lite' }
            }
        }
    }
}

dependencies{
    implementation 'io.grpc:grpc-okhttp:1.20.0'
    implementation 'io.grpc:grpc-protobuf-lite:1.20.0'
    implementation 'io.grpc:grpc-stub:1.20.0'
    implementation 'javax.annotation:javax.annotation-api:1.2'
}
  • 同步工程,这里也可能需要翻墙

4. 编写proto文件:

          在如图所示的目录下,新建一个proto目录,然后在此目录下新建一个test.proto文件,copy如下代码:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.autoforce.mcc4s.proto";
option java_outer_classname = "TestProto";
option optimize_for = CODE_SIZE;

package helloworld;

service Greeter{
    rpc SayHello(HelloRequest) returns (HelloReply){}
}

message HelloRequest{
    string name = 1;
}

message HelloReply{
    string message = 1;
}

        这里面的指令表达的含义暂时可以不需要关心,然后rebuild project,结束之后我们可以在module的   build/generated/source/proto/debug下看到编译器自动为我们生成的代码:

         

5. 编写Android测试代码:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        doConnect()
    }

    private fun doConnect() {
        /*
         这里的三个参数所要的含义是:
         1. host,我这里是通过wifi连接手机和pc,所以这里指定的就是pc的ip地址,
            因为我们的服务端是运行在pc上
         2. 任意字符串
         3. 端口号,根据我们前面运行的服务端所得

        */  
        GrpcTask()
            .execute(
                "192.168.3.190",
                "orange",
                "50051"
            )

    }       

    class GrpcTask() : AsyncTask<String, Void, String>() {

        private var channel: ManagedChannel? = null

        override fun doInBackground(vararg params: String): String {
            val host = params[0]
            val message = params[1]
            val portStr = params[2]
            val port = if (TextUtils.isEmpty(portStr)) 0 else Integer.valueOf(portStr)
            try {
                channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()
                val stub = GreeterGrpc.newBlockingStub(channel)
                val request = HelloRequest.newBuilder().setName(message).build()
                val reply = stub.sayHello(request)
                return reply.message
            } catch (e: Exception) {
                val sw = StringWriter()
                val pw = PrintWriter(sw)
                e.printStackTrace(pw)
                pw.flush()
                return String.format("Failed... : %n%s", sw)
            }

        }

        override fun onPostExecute(result: String) {
            try {
                channel?.shutdown()?.awaitTermination(1, TimeUnit.SECONDS)
            } catch (e: InterruptedException) {
                Thread.currentThread().interrupt()
            }

            Log.e("grpc", " result -> $result")
        }
    }
}

使用AsyncTask构建请求,然后会涉及到四个对象:Channel、Stub、Request以及Reply。 最后别忘记添加网络权限,运行到手机上,我们如果看到如下日志信息,说明我们使用grpc连接成功了!