gRPC для Swift (iOS/macOS): библиотеки, настройка и примеры

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

gRPC для Swift (iOS/macOS): библиотеки и примеры

gRPC — это высокопроизводительный фреймворк для удалённого вызова процедур (RPC), разработанный Google. Он использует Protocol Buffers (protobuf) для сериализации данных и HTTP/2 для транспорта. Для платформ Apple (iOS, macOS) существует официальная экосистема Swift gRPC, которая позволяет создавать как клиентские, так и серверные приложения с полной поддержкой современных возможностей Swift, включая async/await.

Основные библиотеки и инструменты

Для работы с gRPC в Swift используются следующие компоненты:

  • gRPC-Swift — официальный пакет от Google. Включает в себя runtime, кодогенератор и поддержку клиент-серверного взаимодействия.
  • Swift Protobuf — библиотека для работы с protobuf-сообщениями. Необходима для генерации Swift-структур из .proto файлов.
  • protoc — компилятор Protocol Buffers. Для генерации Swift-кода требуется плагин protoc-gen-grpc-swift и protoc-gen-swift.
  • Swift Package Manager (SPM) — основной способ интеграции зависимостей.

Установка и настройка

Для начала работы добавьте зависимости в Package.swift:

// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "GRPCExample",
    dependencies: [
        .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.21.0"),
        .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0")
    ],
    targets: [
        .executableTarget(
            name: "GRPCExample",
            dependencies: [
                .product(name: "GRPC", package: "grpc-swift"),
                .product(name: "SwiftProtobuf", package: "swift-protobuf")
            ]
        )
    ]
)

Также необходимо установить protoc и плагины через Homebrew:

brew install protobuf
brew install grpc-swift
brew install swift-protobuf

Пример .proto файла

Создадим простой сервис для приветствия. Файл hello.proto:

syntax = "proto3";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

Сгенерируйте Swift-код командой:

protoc --swift_out=. --grpc-swift_out=. hello.proto

В результате появятся файлы hello.pb.swift и hello.grpc.swift.

Серверная часть на Swift

Создадим gRPC-сервер, который будет обрабатывать запросы SayHello:

import GRPC
import NIO
import NIOPosix

class GreeterProvider: GreeterProvider {
    func sayHello(request: HelloRequest, context: StatusOnlyCallContext) -> EventLoopFuture<HelloReply> {
        var reply = HelloReply()
        reply.message = "Привет, \(request.name)!"
        return context.eventLoop.makeSucceededFuture(reply)
    }
}

let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { try! group.syncShutdownGracefully() }

let server = try Server.insecure(group: group)
    .withServiceProviders([GreeterProvider()])
    .bind(host: "localhost", port: 50051)
    .wait()

print("Сервер запущен на localhost:50051")
try server.onClose.wait()

Клиентская часть на Swift (с async/await)

Для iOS/macOS клиент удобно реализовать с использованием async/await. Убедитесь, что используете Swift 5.5+ и минимальную цель развёртывания iOS 13.0 / macOS 10.15.

import GRPC
import NIO
import NIOPosix
import SwiftProtobuf

func greet(name: String) async throws -> String {
    let group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
    defer { try? group.syncShutdownGracefully() }

    let channel = try GRPCChannelPool.with(
        target: .host("localhost", port: 50051),
        transportSecurity: .plaintext,
        eventLoopGroup: group
    )
    defer { try? channel.close().wait() }

    let client = GreeterClient(channel: channel)
    var request = HelloRequest()
    request.name = name

    let response = try await client.sayHello(request)
    return response.message
}

// Использование:
Task {
    do {
        let message = try await greet(name: "Мир")
        print(message) // "Привет, Мир!"
    } catch {
        print("Ошибка: \(error)")
    }
}

Работа с потока

Рекомендаций