Build a Mobile App Using Google Compute Engine and gRPC

The gRPC framework makes it possible for a mobile app to directly call methods on a backend service as if it was a local object. You can use gRPC to make your mobile app more bandwidth-efficient and to reduce latency between your app and backend service running on Google Cloud Platform.

Running your mobile backend on Google Compute Engine and using gRPC as the communication protocol between your mobile app and the backend server has several advantages.

  • It is the fastest way to move an existing service, running on an on-premises or virtual machine, to Cloud Platform.
  • Better bandwidth efficiency compared to HTTP/S.
  • It gives you full control over your virtual machine and server configuration.
  • You can use third party libraries.
  • You can configure an autoscaler to scale the number of virtual machines to meet demand.

The downside to running your service on Compute Engine is that you are responsible for maintaining and updating your server manually. For other options for building mobile backend services, see Build mobile apps using Google Cloud Platform.

This tutorial walks you through building a sample mobile app called Stickynotes. This sample app uses gRPC to connect to a backend service running on Compute Engine.

The Stickynotes sample includes code for a frontend mobile app and a backend service. In the mobile app, you can enter a message into a text field. The app sends your message to a backend service using gRPC. The backend service which converts the text message into an image using draw2d, and then returns the image to the mobile app. The mobile app then displays your message as an image with a yellow background.

The client app is an iOS app and the backend service is written in Go.

Objectives

In this tutorial you will learn how to:

  • Create an iOS mobile app that uses gRPC to connect to a backend service.
  • Configure and run a gRPC backend service on Compute Engine.

Costs

This tutorial uses billable components of Cloud Platform, including:

  • Google Compute Engine

Use the Pricing Calculator to generate a costc estimate based on your projected usage. New Cloud Platform users might be eligible for a free trial.

Before you begin

  • Sign in to your Google account.

    If you don't already have one, sign up for a new account.

  • Select or create a Cloud Platform project.

    Go to the Manage resources page

  • Enable billing for your project.

    Enable billing

  • Install the following software:

    • Git
    • XCode 7.2 or later
    • Go

      • Ensure that the Go installation is in your PATH variable, typically /usr/local/go/bin.
      • Install Go with your user account as the owner. If you install it as root, run the following command in the directory where Go is installed to change ownership, replacing <username> with your user name.

        sudo chown -R <username> go
        
    • Cocoapods

      sudo gem install cocoapods
      
    • Homebrew

      /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
      
    • protoc with the gRPC plugin

      curl -fsSL https://goo.gl/getgrpc | bash -
      

    Clone the sample code

    git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git
    

    Then navigate to /solutions/stickynoteapi/gRPC to find the sample code for this solution.

    Run the server locally

    In the /stickynoteapi/gRPC/Go directory, run the following command

    sh SETUP
    

    You should see the following output:

    0. Ensure that protoc is installed.
    /usr/local/bin/protoc
    OK
    1. Set gopath and search path
    2. Get the Go plugin for protoc
    3. Run protoc to generate the service API code
    4. Get the server and client dependencies
    5. Build the server and client
    6. Stop any previously-running instances of the server
    No matching processes belonging to you were found
    7. Start the server
    8. Run the client
    2016/03/03 15:53:21 OK: message.png
    9. Open the image in message.png
    

    The setup also runs a local client to test the server with the phrase “Remember the milk.” and generates an image with that message.

    Remember the milk.

    To generate images based on your own messages using the command-line client, run the following command.

    ./client "This is a test..."
    

    The file, /solutions/stickynoteapi/gRPC/Go/go/src/server/server.go, contains the code that runs the gRPC server. The code also defines a structure, StickyNoteServer that contains two elements, one representing the Request, and the other the Response.

    type StickyNoteServer struct{}
    
    var stickyNoteServer StickyNoteServer

    The main function defines a gRPC server for the root-level directory, which listens for traffic on port 8080. Because the server does not specify an IP address or domain, you can run this code on Compute Engine without any modification.

    func main() {
    	var err error
    	var lis net.Listener
    	var grpcServer *grpc.Server
    	if !useSSL {
    		lis, err = net.Listen("tcp", ":8080")
    		if err != nil {
    			log.Fatalf("failed to listen: %v", err)
    		}
    		grpcServer = grpc.NewServer()
    	} else {
    		certFile := "ssl.crt"
    		keyFile := "ssl.key"
    		creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
    		lis, err = net.Listen("tcp", ":443")
    		if err != nil {
    			log.Fatalf("failed to listen: %v", err)
    		}
    		grpcServer = grpc.NewServer(grpc.Creds(creds))
    	}
    	pb.RegisterStickyNoteServer(grpcServer, &stickyNoteServer)
    	grpcServer.Serve(lis)
    }

    The Get function recieves the message in the gRPC request, uses functions defined in sticky.go to build an image based on that message, and then returns the image in a gRPC response.

    func (s *StickyNoteServer) Get(ctx context.Context, r *pb.StickyNoteRequest) (*pb.StickyNoteResponse, error) {
    	var sticky Sticky
    	sticky.Message = r.Message
    	sticky.Centered = false
    
    	resp := &pb.StickyNoteResponse{}
    	stickyBytes, err := sticky.DrawPNG(512, 512)
    	resp.Image = *stickyBytes
    
    	return resp, err
    }

    Leave the local server running so you can use it to test the client application.

    Run the iOS client with the local server

    1. In the /stickynoteapi/gRPC/Objective-C directory, run the following command to install the BoringSSL, Protobuf, and gRPC dependencies. The installation process may take several minutes.

      pod install
      

      You should see the following output:

      Analyzing dependencies
      Fetching podspec for stickynote from stickyapi
      Downloading dependencies
      Installing BoringSSL (2.0)
      Installing Protobuf (3.0.0-beta-2)
      Installing gRPC (0.12.0)
      Installing stickynote (0.0.1)
      Generating Pods project
      Integrating client project

      [!] Please close any current Xcode sessions and use stickynotes.xcworkspace for this project from now on. Sending stats Pod installation complete! There is 1 dependency from the Podfile and 4 total pods installed.

    2. Open the workspace built by Cocoapods, stickynotes.xcworkspace, in Xcode.

    3. Select Product > Scheme > stickynotes to pick the correct scheme.

    4. Select Product > Run to build and start the client application. Ignore the warnings in Protobuf and gRPC.

    5. Enter a message in the text field and tap Return.

    An image of a yellow sticky note with your message should appear beneath the text field.

    This is a test...

    The client app sets the location of the backend service in the file StickyNotesViewController.m. For testing purposes, this is initially set to localhost.

    static NSString * const kHostAddress = @"localhost";

    When you tap Return after entering your message in the text field, the following action fires. The action encodes the message into a query string. Then it passes the query into an open streaming connection.

    - (IBAction)textDidChange:(UITextField *) sender {
      if ([_streamSwitch isOn]) {
        StickyNoteRequest *request = [StickyNoteRequest message];
        request.message = sender.text;
        [_writer writeValue:request];
      }
    }

    The streaming connection is opened by the function openStreamingConnection.

    - (void) openStreamingConnection {
      _writer = [[GRXBufferedPipe alloc] init];
      _updateCall = [_client RPCToUpdateWithRequestsWriter:_writer
                                              eventHandler:^(BOOL done, StickyNoteResponse *response, NSError *error) {
                                                [self handleStickynoteResponse:response andError:error];
                                              }];
      [_updateCall start];
    }

    Run the server on Compute Engine

    1. Go to the Create an instance page in the Google Cloud Platform Console.
      Go to the Create an instance page

      1. Set Name to sticky-grpc.
      2. Select Create.

      Create an instance

    2. Go to the Create a firewall rule page in the Cloud Platform Console.
      Go to the Create a firewall rule page

      1. In Name, enter default-allow-grpc.
      2. In Source filter, select Allow from any source (0.0.0.0./0).
      3. In Allowed protocols and ports, enter tcp:8080.
      4. Select Create

      Select SSH

    3. Go to the View your VM instances page in the Cloud Platform Console.
      Go to the View your VM instances page

      1. Note the External IP address next to sticky-grpc.
      2. Select SSH

      Select SSH

    4. Install Git on the instance.

      sudo apt-get update
      sudo apt-get install git
      
    5. Clone the Stickynotes server code.

      git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git
      
    6. Install Go and protoc. In the /solutions/stickynoteapi/gRPC/Go/ directory, run the following command.

      sh INSTALL
      
    7. Load the new environment variables set by the INSTALL script.

      source $HOME/.bash_profile
      
    8. Start the Stickynotes server on the instance. In the /solutions/stickynoteapi/gRPC/Go/ directory, run the following command.

      sh SETUP
      
    9. In Xcode, edit StickyNotesViewController.m to change localhost to the external IP address of your Compute Engine instance from Step 2.

      // static NSString \* const kHostAddress = @"localhost";
      static NSString \* const kHostAddress = @"198.51.100.0";
      
    10. Select File > Save to save your changes.

    11. Select Product > Scheme > stickynotes to pick the correct scheme.

    12. Select Product > Run to build and start the client application.

    13. Enter a message in the text field and tap Return.

    An image of a yellow sticky note with your message should replace the gray background.

    Testing on remote server...

    Cleaning up

    To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

    Deleting the project

    The easiest way to eliminate billing is to delete the project you created for the tutorial.

    To delete the project:

    1. In the Cloud Platform Console, go to the Projects page.

      Go to the Projects page

    2. In the project list, select the project you want to delete and click Delete project. After selecting the checkbox next to the project name, click
      Delete project
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    Deleting instances

    To delete a Compute Engine instance:

    1. In the Cloud Platform Console, go to the VM Instances page.

      Go to the VM Instances page

    2. Click the checkbox next to the instance you want to delete.
    3. Click the Delete button at the top of the page to delete the instance.

    Deleting firewall rules for the default network

    To delete a firewall rule:

    1. In the Cloud Platform Console, go to the Firewall Rules page.

      Go to the Firewall Rules page

    2. Click the checkbox next to the firewall rule you want to delete.
    3. Click the Delete button at the top of the page to delete the firewall rule.

    What's next

    This sample demonstrates the basics of how to connect a mobile app to code running on Compute Engine over gRPC. To extend this sample into a real app, consider adding the following enhancements:

    • Add a static IP address to your server -- by default, the external address associated with a Compute Engine instance is transient. For a production app you should attach a static IP address to your instance. For more information, see Configuring an Instance’s IP Address.

    • Add load balancing and autoscaling -- handle traffic spikes gracefully by setting up a load balancer and autoscaler to spin up extra instances when demand grows, and to route traffic evenly across those instances. For more information, see Setting up HTTP(s) Load Balancing and Autoscaling Groups of Instances.

    • Consider other hosting options for your backend service -- Compute Engine offers the greatest degree of control over your virtual machine, but at the cost of you manually updating and managing your instance. For a discussion of other ways to host a mobile backend service on Cloud Platform, see Build mobile apps using Google Cloud Platform.

    Send feedback about...