跳到内容

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,当 rpcRoleclient 时,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'
  }
}
Wire 编译器将为服务器生成以下接口来实现
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>)
}
对于流式连接,服务器可以使用 Wire 的阻塞 API:MessageSourceMessageSink

协程 API

遵循此配置

wire {
  kotlin {
    rpcRole = 'server'
    rpcCallStyle = 'suspending'
  }
}
Wire 编译器将为服务器生成以下接口来实现
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>)
}
服务器可以使用 Kotlin 协程的 suspend 和 Channels 机制来执行协程网络调用。

实现客户端接口

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()
      }
    }
  }

  ...
}

GrpcCallGrpcStreamingCall 函数非常适合表达式函数。

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-serverwire-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 上提问。