快速入门

本指南将通过一个简单的运行示例,带您开始在 iOS 平台上使用 Objective-C 进行 gRPC 开发。

快速入门

本指南将通过一个简单的运行示例,带您开始在 iOS 平台上使用 Objective-C 进行 gRPC 开发。

准备工作

系统要求

  • macOS 10.11 (El Capitan) 或更高版本
  • iOS 7.0 或更高版本

先决条件

  • CocoaPods 1.0 或更高版本

    检查系统上 CocoaPods 的状态和版本

    pod --version
    

    如果尚未安装 CocoaPods,请遵循 CocoaPods 安装说明

  • Xcode 7.2 或更高版本

    通过从 Launchpad 运行 Xcode 来检查您的 Xcode 版本,然后在菜单中选择 Xcode > About Xcode

    确保已安装命令行开发工具

    xcode-select --install
    
  • Homebrew

  • autoconf, automake, libtool, pkg-config

    brew install autoconf automake libtool pkg-config
    

下载示例

您需要一份示例应用源代码的本地副本才能完成本快速入门。请从 GitHub 仓库 复制源代码

git clone --recursive -b v1.78.1 --depth 1 --shallow-submodules https://github.com/grpc/grpc

安装 gRPC 插件和库

cd grpc
make
[sudo] make install

安装 protoc 编译器

brew tap grpc/grpc
brew install protobuf

运行服务器

对于此示例应用,我们需要在本地机器上运行一个 gRPC 服务端。gRPC Objective-C API 支持创建 gRPC 客户端,但不支持创建 gRPC 服务端。因此,我们改为在同一个仓库中构建并运行 C++ 服务端

cd examples/cpp/helloworld
make
./greeter_server &

运行客户端

生成客户端库和依赖项

让 CocoaPods 根据我们的 .proto 文件生成并安装客户端库,同时安装若干依赖项

cd ../../objective-c/helloworld
pod install

(这可能需要编译 OpenSSL,如果您的计算机缓存中还没有该库,则大约需要 15 分钟。)

运行客户端应用

打开由 CocoaPods 创建的 Xcode 工作区

open HelloWorld.xcworkspace

这将在 Xcode 中打开应用项目。点击 Xcode 窗口左上角的“运行”按钮,在 iOS 模拟器中运行该应用。您可以查看 main.m 中的调用代码,并在 Xcode 控制台中看到结果。

该代码向本地服务端发送了一个包含字符串“Objective-C”的 HLWHelloRequest 请求。服务端返回一个包含字符串“Hello Objective-C”的 HLWHelloResponse 响应,该响应随后被输出到控制台。

恭喜!您刚刚运行了一个使用 gRPC 的客户端-服务器应用程序。

更新 gRPC 服务

现在,让我们看看如何通过在服务端添加额外方法来更新应用程序。我们的 gRPC 服务是使用 Protocol Buffers 定义的;您可以在 Protocol Buffers 网站 上了解更多关于如何在 .proto 文件中定义服务的信息。目前您只需知道,服务端和客户端“桩 (stub)”都有一个 SayHello RPC 方法,该方法接收来自客户端的 HelloRequest 参数并返回来自服务端的 HelloResponse,且该方法的定义如下所示

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

让我们更新它,使 Greeter 服务有两个方法。编辑 examples/protos/helloworld.proto 并使用一个新的 SayHelloAgain 方法进行更新,该方法具有相同的请求和响应类型

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  // Sends another greeting
  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

记得保存文件!

更新客户端和服务端

我们现在有了新的 gRPC 服务定义,但仍需在示例应用程序的人工编写部分实现并调用该新方法。

更新服务器

正如您所记,gRPC 不提供 Objective-C 的服务端 API。因此,我们需要更新 C++ 示例服务端。打开 examples/cpp/helloworld/greeter_server.cc。按如下方式实现新方法

class GreeterServiceImpl final : public Greeter::Service {
  Status SayHello(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("Hello ");
    reply->set_message(prefix + request->name());
    return Status::OK;
  }
  Status SayHelloAgain(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("Hello again ");
    reply->set_message(prefix + request->name());
    return Status::OK;
  }
};

更新客户端

编辑 examples/objective-c/helloworld/main.m 中的主函数,按如下方式调用新方法

int main(int argc, char * argv[]) {
  @autoreleasepool {
    HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];

    HLWHelloRequest *request = [HLWHelloRequest message];
    request.name = @"Objective-C";

    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
    // this example does not use TLS (secure channel); use insecure channel instead
    options.transport = GRPCDefaultTransportImplList.core_insecure;
    options.userAgentPrefix = @"HelloWorld/1.0";

    [[client sayHelloWithMessage:request
                 responseHandler:[[HLWResponseHandler alloc] init]
                     callOptions:options] start];
    [[client sayHelloAgainWithMessage:request
                      responseHandler:[[HLWResponseHandler alloc] init]
                          callOptions:options] start];

    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

构建并运行

首先终止已经在后台运行的服务端进程

pkill greeter_server

然后在 examples/cpp/helloworld 目录下,使用以下命令构建并运行更新后的服务端

make
./greeter_server &

将目录更改为 examples/objective-c/helloworld,然后使用以下命令清理并重新安装客户端应用的 Pods

rm -Rf Pods
rm Podfile.lock
rm -Rf HelloWorld.xcworkspace
pod install

这会基于我们上面编写的新 proto 文件重新生成 Pods/HelloWorld 中的文件。在 Xcode 中打开客户端 Xcode 项目

open HelloWorld.xcworkspace

并运行客户端应用。如果您查看控制台消息,将会看到两个 RPC 调用,一个是 SayHello,另一个是 SayHelloAgain。

故障排除

安装 CocoaPods 时,出现错误 activesupport requires Ruby version >= 2.2.2

安装旧版本的 activesupport,然后安装 CocoaPods

[sudo] gem install activesupport -v 4.2.6
[sudo] gem install cocoapods
使用 CocoaPods 安装依赖项时,出现错误 Unable to find a specification for !ProtoCompiler-gRPCPlugin

通过运行 pod repo update 更新本地的 spec 仓库克隆

编译 objective_c_plugin.cc 时出现编译器错误

在构建 gRPC 之前使用 Homebrew 移除 protobuf 包可能会解决此问题。我们正在研究更优雅的修复方案。

构建 HelloWorld 时,出现错误 ld: unknown option: --no-as-needed

此问题是由于 Apple LLVM 中的链接器 ld 不支持 --no-as-needed 选项所致。我们目前正在修复中,很快就会合并修复程序。

构建 grpc 时,出现错误 cannot find install-sh install.sh or shtool

删除 gRPC 目录,重新克隆一份并重试。很可能是某些自动生成的文件损坏了;删除并重建可以解决该问题。

构建 grpc 时,出现错误 Can't exec "aclocal"

缺少 automake 包。安装 automake 应该能解决此问题。

构建 grpc 时,出现错误 possibly undefined macro: AC_PROG_LIBTOOL

缺少 libtool 包。安装 libtool 应该能解决此问题。

构建 grpc 时,出现错误 cannot find install-sh, install.sh, or shtool

部分自动生成的文件已损坏。删除整个 gRPC 目录,从 GitHub 重新克隆,然后再次构建。

构建 HelloWorld 时找不到 protoc

运行 brew install protobuf 以获取 protoc 编译器。

接下来