天天看點

grpc in Android

最近公司用戶端同伺服器的互動方式都換成了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

                  運作成功後,可以在終端看到以下資訊:

grpc in Android

                注意,這裡說明了端口号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檔案:

grpc in Android

          在如圖所示的目錄下,建立一個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下看到編譯器自動為我們生成的代碼:

grpc in Android

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連接配接成功了!

grpc in Android