Wire gRPC¶
Wire 编译器会为您的 protobuf schema 中定义的服务 RPC 生成接口;前提是目标语言设置为 Kotlin。
入门指南¶
您可以通过 Gradle 插件 配置如何生成您的服务。
wire {
// Kotlin target will generate code for services.
kotlin {
// `client` to generate interfaces best suited to sending outbound calls.
// `server` to generate interfaces best suited to receiving inbound calls.
rpcRole = 'server'
// Server only
// `suspending` to generate coroutines APIs that require a Kotlin coroutines context.
// `blocking` to generate blocking APIs callable by Java and Kotlin.
rpcCallStyle = 'suspending'
// Server only
// True for emitted services to generate one interface per RPC.
singleMethodServices = false
}
}
生成代码会根据您的 RPC 角色(即客户端或服务器)而有所不同。我们将使用以下 schema 来演示它们的区别。
syntax = "proto2";
package routeguide;
service RouteGuide {
// A simple RPC.
rpc GetFeature(Point) returns (Feature) {}
// A server-to-client streaming RPC.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
// A client-to-server streaming RPC.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
// A Bidirectional streaming RPC.
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
面向客户端的 gRPC¶
对于 schema RouteGuide
,当 rpcRole
是 client
时,Wire 编译器将生成以下接口。
interface RouteGuideClient : Service {
fun GetFeature(): GrpcCall<Point, Feature>
fun ListFeatures(): GrpcStreamingCall<Rectangle, Feature>
fun RecordRoute(): GrpcStreamingCall<Point, RouteSummary>
fun RouteChat(): GrpcStreamingCall<RouteNote, RouteNote>
}
对于流式 API,我们返回一个 GrpcStreamingCall,否则返回一个 GrpcCall。使用这些对象,调用方可以与服务器通信。我们提供了阻塞 API 和协程 API。
Wire 运行时¶
为了帮助您实例化服务,我们提供了一个小型运行时,即 GrpcClient。
val grpcClient = GrpcClient.Builder()
.client(OkHttpClient.Builder().protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)).build())
.baseUrl(serverUrl)
.build()
val routeGuideClient = grpcClient.create(RouteGuideClient::class)
面向服务器的 gRPC¶
阻塞 API¶
遵循此配置
wire {
kotlin {
rpcRole = 'server'
rpcCallStyle = 'blocking'
}
}
interface RouteGuideBlockingServer : Service {
fun GetFeature(request: Point): Feature
fun ListFeatures(request: Rectangle, response: MessageSink<Feature>)
fun RecordRoute(request: MessageSource<Point>): RouteSummary
fun RouteChat(request: MessageSource<RouteNote>, response: MessageSink<RouteNote>)
}
协程 API¶
遵循此配置
wire {
kotlin {
rpcRole = 'server'
rpcCallStyle = 'suspending'
}
}
interface RouteGuideServer : Service {
suspend fun GetFeature(request: Point): Feature
fun ListFeatures(request: Rectangle, response: SendChannel<Feature>)
fun RecordRoute(request: ReceiveChannel<Point>): RouteSummary
fun RouteChat(request: ReceiveChannel<RouteNote>, response: SendChannel<RouteNote>)
}
实现客户端接口¶
Wire 提供了辅助函数,使实现其客户端接口更加容易。这对于测试尤其有用。它在 Kotlin 中支持流式和非流式 API。
class FakeRouteGuideClient : RouteGuideClient {
override fun GetFeature(): GrpcCall<Point, Feature> {
return GrpcCall { request: Point ->
return@GrpcCall Feature(name = "test", location = request)
}
}
override fun RouteChat(): GrpcStreamingCall<RouteNote, RouteNote> {
return GrpcStreamingCall { requests: ReceiveChannel<RouteNote>, responses: SendChannel<RouteNote> ->
try {
requests.consumeEach { routeNote: RouteNote ->
responses.send(RouteNote(message = "ACK: ${routeNote.message}"))
}
} finally {
responses.close()
}
}
}
...
}
GrpcCall
和 GrpcStreamingCall
函数非常适合表达式函数。
class FakeRouteGuideClient : RouteGuideClient {
override fun GetFeature() =
GrpcCall<Point, Feature> { request ->
return@GrpcCall Feature(name = "test", location = request)
}
override fun RouteChat() =
GrpcStreamingCall<RouteNote, RouteNote> { requests, responses ->
try {
requests.consumeEach { routeNote ->
responses.send(RouteNote(message = "ACK: ${routeNote.message}"))
}
} finally {
responses.close()
}
}
...
}
客户端接口也可以用 Java 实现。Wire 只提供非流式辅助函数。上面的 GrpcStreamingCall
使用了仅限 Kotlin 的协程。
public class FakeRouteGuideClient implements RouteGuideClient {
@Override public GrpcCall<Point, Feature> GetFeature() {
return GrpcCalls.grpcCall(new Function1<Point, Feature>() {
@Override public Feature invoke(Point request) {
return new Feature.Builder()
.name("test")
.location(request)
.build();
}
});
}
...
}
它们同样能很好地与 Java lambda 交互。
示例¶
查看我们的示例项目,演示 Android 应用程序和服务器之间的双向通信。
获取¶
使用 Wire 运行时 Gradle 坐标
implementation("com.squareup.wire:wire-runtime:LATEST_VERSION")
此外,要为客户端使用 Wire gRPC,请使用这些新的 Gradle 坐标
implementation("com.squareup.wire:wire-grpc-client:LATEST_VERSION")
wire-grpc-server¶
模块 wire-grpc-server
和 wire-grpc-server-generator
已从 Wire 5 中提取出来。它们现在位于独立的仓库中:square/wire-grpc-server/。
以下是顺利迁移的步骤
Maven 坐标¶
更新 com.squareup.wire:wire-grpc-server
的坐标。
-com.squareup.wire:wire-grpc-server:<wire-version>
+com.squareup.wiregrpcserver:server:<new-repo-version>
在 Wire 将运行的 classpath 上添加一个新的依赖项。
classpath("com.squareup.wiregrpcserver:server-generator:<new-repo-version>")
配置¶
之前
wire {
kotlin {
rpcRole = "server"
grpcServerCompatible = true
singleMethodServices = false
rpcCallStyle = "suspending"
}
}
grpcServerCompatible
已不再存在。您需要在自定义块中将新的 GrpcServerSchemaHandler
传递给 Wire。
之后
wire {
custom {
// Be sure that `server-generator` is on the classpath for Gradle to resolve
// `GrpcServerSchemaHandler`.
schemaHandlerFactory = com.squareup.wire.kotlin.grpcserver.GrpcServerSchemaHandler.Factory()
options = mapOf(
// Defaults to `true` if absent. Any other value than `true` is considered false.
"singleMethodServices" to "false",
// Defaults to `suspending` if absent. Any other value than `suspending` is considered
// non-suspending.
"rpcCallStyle" to "suspending",
)
// We set the custom block exclusivity to false so that the next `kotlin {}` block can also
// generate the protobuf Messages.
exclusive = false
}
kotlin {
rpcRole = "server"
singleMethodServices = false
rpcCallStyle = "suspending"
}
}
如果迁移过程中遇到任何问题,请在 wire-grpc-server 上提问。