Android
protobuf
ProtocolBuffers
gRPC
More than 1 year has passed since last update.

Google謹製のRPCフレームワークであるgRPCProtocolBuffersをAndroid上で試してみた。

説明にあるコードはこちらで確認すること。(尚、この実装は2017/6/9現在のものである)

https://github.com/kobaken0029/GrpcDemo


gRPCとは?

Googleが開発しているハイパフォーマンスなRPCフレームワークである。後述のprotobufで定義されたサービスや構造体を利用する。

通信はHTTP/2ベースになっており、RPCメソッドを提供するサーバとそれを呼び出すクライアントで分かれている。Apache License 2.0のオープンソース。


protobuf(ProtocolBuffers)とは?

こちらもGoogle謹製。データ通信や永続化のためのシリアライズフォーマットである。

オリジナルがC++、Java、Pythonで実装されており、その他CやC#、Go、Scalaなどの実装も存在する。BSDライセンスのオープンソース。


実装


build.gradleを編集

proto→Javaに必要なpluginとgRPC本体の依存関係を記述する。


プロジェクト直下のbuild.gradle

buildscript {

repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
}
}


app直下のbuild.gradle

apply plugin: "com.google.protobuf"

android {
~ ~

configurations.all {
resolutionStrategy.force "com.google.code.findbugs:jsr305:2.0.1"
}
}

def grpc_version = "1.3.0"

dependencies {
~ ~

compile "io.grpc:grpc-okhttp:$grpc_version"
compile "io.grpc:grpc-protobuf-lite:$grpc_version"
compile "io.grpc:grpc-stub:$grpc_version"
compile "javax.annotation:javax.annotation-api:1.2"
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.1.0"
}
plugins {
javalite {
artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
}
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:$grpc_version"
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
grpc {
option 'lite'
}
}
}
}
}



protoファイルを配置

app/src/main/protoを作成し、対象となるprotoファイルを配置。

今回使用したprotoファイルはこちら


ビルド

ここでビルドするとprotoファイルに定義されたものがJavaで自動生成される。

成果物はapp/build/generated/source/proto内に配置される。


通信部分実装

先程の成果物を使用して通信部分を実装。


MainActivity.java

// Channelを作成

ManagedChannel channel = ManagedChannelBuilder.forAddress("10.0.2.2", 50051)
.usePlaintext(true)
.build();

// UserServiceのStubを作成(今回は簡易のためBlockingを使用)
UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel);

// Requestを作成
CreateRequest createRequest = CreateRequest.newBuilder()
.setAge(23)
.setName("kobaken")
.setSex(Sex.MALE)
.build();

// 実行
String createResultMessage = stub.create(createRequest).getMessage();
Log.d(TAG, "[Create] " + createResultMessage);



通信権限の付与

アプリにネットワーク通信のための権限を付与する。


AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />



サーバを用意

サーバ実装はこちらを参照のこと。cloneして実行環境にあったbin/grpc_*を実行するとサーバが起動する。

ex.) macOSならbin/grpc_darwin


実行結果

06-09 08:37:50.385 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [Create] success

06-09 08:37:50.403 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [Get] kobaken:23:MALE
06-09 08:37:50.412 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [Update] success
06-09 08:37:50.425 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [Get] kobaken:30:FEMALE
06-09 08:37:50.436 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [Delete] success
06-09 08:37:50.461 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [GetAll] Mizuki Sonoko:22:MALE
06-09 08:37:50.461 3675-3675/com.kobaken0029.gprcdemo D/MainActivity: [GetAll] upamune:21:MALE


まとめ

普段RESTで通信していた部分をgRPCを採用することで実装コストを抑えることが出来た。また実際に計測はしていないが、REST(http+json)と比較するとgRPC+protoの方が速い。こちらを参照のこと。

こちらで紹介されている方法で生成したJavaファイルを使用した際、一部依存関係が解決できずコンパイルエラーが発生した為、解決策としてprotobuf-gradle-pluginを採用した。

これ以外でAndroid向けにproto→Java変換できる方法を知っているがいたら教えてください🙇

jsonで通信する時代は終わった。 これからは ProtocolBuffers で決まり💪


補足

今回はBlockingStubを使用したが、通常は別スレッドで通信して結果をコールバックで取得する形になると思う。その場合、RxJava等を利用すると


MainActivity.java

UserServiceGrpc.UserServiceFutureStub stub = UserServiceGrpc.newFutureStub(channel);

GetRequest request = // GetRequestを生成

Single<User> observer = Single.create(e -> e.onSuccess(stub.get(request).getUser()));

observer
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> Log.d(TAG, "[Get] " + user.getName));


こんな感じでいけるはず(動作確認はしていない)


SpecialThanks

@upamune


参照元

http://www.grpc.io/

https://developers.google.com/protocol-buffers/

https://github.com/grpc/grpc-java

https://speakerdeck.com/wasabeef/grpc-for-android

http://techblog.reraku.co.jp/entry/2016/12/22/082556