最近公司用戶端同伺服器的互動方式都換成了grpc,什麼是grpc呢?我們在以後再去了解,此篇的目的就是帶大家了解在android中如何去使用grpc.
- grpc-java的github位址:https://github.com/grpc/grpc-java。大家可以去浏覽一下裡面的文檔說明,不用動手。
- 對于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連接配接成功了!