最近公司客户端同服务器的交互方式都换成了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连接成功了!