This guide gets you started with gRPC on the iOS platform in Objective-C with a simple working example.
The minimum deployment iOS version for gRPC is 7.0.
OS X El Capitan (version 10.11) or above is required to build and run this Quickstart.
CocoaPods
: version 1.0 or higher
pod
--version
.Xcode
: version 7.2 or higher
[sudo] xcode-select --install
Homebrew
brew
--version
. /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
autoconf
, automake
, libtool
, pkg-config
brew install autoconf automake libtool pkg-config
You’ll need a local copy of the sample app source code to work through this Quickstart. Copy the source code from GitHub repository:
$ git clone --recursive -b v1.17.1 https://github.com/grpc/grpc.git
$ cd grpc
$ make
$ [sudo] make install
$ brew tap grpc/grpc
$ brew install protobuf
For this sample app, we need a gRPC server running on the local machine. gRPC Objective-C API supports creating gRPC clients but not gRPC servers. Therefore instead we build and run the C++ server in the same repository:
$ cd examples/cpp/helloworld
$ make
$ ./greeter_server &
Have CocoaPods generate and install the client library from our .proto files, as well as installing several dependencies:
$ cd ../../objective-c/helloworld
$ pod install
(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn’t have it yet on your computer’s cache.)
Open the Xcode workspace created by CocoaPods:
$ open HelloWorld.xcworkspace
This will open the app project with Xcode. Run the app in an iOS simulator
by pressing the Run button on the top left corner of Xcode window. You can check
the calling code in main.m
and see the results in Xcode’s console.
The code sends a HLWHelloRequest
containing the string “Objective-C” to a
local server. The server responds with a HLWHelloResponse
, which contains a
string “Hello Objective-C” that is then output to the console.
Congratulations! You’ve just run a client-server application with gRPC.
Now let’s look at how to update the application with an extra method on the
server for the client to call. Our gRPC service is defined using Protocol
Buffers; you can find out lots more about how to define a service in a .proto
file in Protocol Buffers
website. For now all you
need to know is that both the server and the client “stub” have a SayHello
RPC method that takes a HelloRequest
parameter from the client and returns a
HelloResponse
from the server, and that this method is defined like this:
// 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;
}
Let’s update this so that the Greeter
service has two methods. Edit
examples/protos/helloworld.proto
and update it with a new SayHelloAgain
method, with the same request and response types:
// 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;
}
(Don’t forget to save the file!)
We now have a new gRPC service definition, but we still need to implement and call the new method in the human-written parts of our example application.
As you remember, gRPC doesn’t provide a server API for Objective-C. Instead, we
need to update the C++ sample server. Open
examples/cpp/helloworld/greeter_server.cc
. Implement the new method like this:
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;
}
};
Edit examples/objective-c/helloworld/main.m
to call the new method like this:
int main(int argc, char * argv[]) {
@autoreleasepool {
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
[GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
HLWHelloRequest *request = [HLWHelloRequest message];
request.name = @"Objective-C";
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
NSLog(@"%@", response.message);
}];
[client sayHelloAgainWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
NSLog(@"%@", response.message);
}];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
First terminate the server process already running in the background:
$ pkill greeter_server
Then in directory examples/cpp/helloworld
, build and run the updated server
with the following commands:
$ make
$ ./greeter_server &
Change directory to examples/objective-c/helloworld
, then clean up and
reinstall Pods for the client app with the following commands:
$ rm -Rf Pods
$ rm Podfile.lock
$ rm -Rf HelloWorld.xcworkspace
$ pod install
This regenerates files in Pods/HelloWorld
based on the new proto file we wrote
above. Open the client Xcode project in Xcode:
$ open HelloWorld.xcworkspace
and run the client app. If you look at the console messages, you should see two RPC calls, one to SayHello and one to SayHelloAgain.
When installing CocoaPods, error prompt activesupport requires Ruby version >= 2.2.2.
Install an older version of activesupport
, then install CocoaPods:
[sudo] gem install activesupport -v 4.2.6
[sudo] gem install cocoapods
When installing dependencies with CocoaPods, error prompt Unable to find a specification for !ProtoCompiler-gRPCPlugin
Update the local clone of spec repo by running pod repo update
Compiler error when compiling objective_c_plugin.cc
Removing protobuf
package with Homebrew before building gRPC may solve
this problem. We are working on a more elegant fix.
When building HellowWorld, error prompt ld: unknown option: --no-as-needed
This problem is due to linker ld
in Apple LLVM not supporting the
–no-as-needed option. We are working on a fix right now and will merge the fix
very soon.
When building grpc, error prompt cannot find install-sh install.sh or shtool
Remove the gRPC directory, clone a new one and try again. It is likely that some auto generated files are corrupt; remove and rebuild may solve the problem.
When building grpc, error prompt Can't exec "aclocal"
The package automake
is missing. Install automake
should solve this problem.
When building grpc, error prompt possibly undefined macro: AC_PROG_LIBTOOL
The package libtool
is missing. Install libtool
should solve this problem.
When building grpc, error prompt cannot find install-sh, install.sh, or shtool
Some of the auto generated files are corrupt. Remove the entire gRPC directory, clone from GitHub, and build again.
Cannot find protoc
when building HelloWorld
Run brew install protobuf
to get protoc
compiler.