This tutorial describes how to develop a mobile application powered by Google Cloud Platform. The application includes an Android client and an App Engine backend.
The example app is called the Mobile Shopping Assistant. The app lets users get information on products at the store they are in, as well as find nearby stores.
You will write custom code to wire the basic Android app client to the App Engine cloud backend, using Google cloud endpoints, so it can determine user location, locate nearby stores, and allow the user to obtain relevant offers and recommendations.
The following figure shows the main components of such application. Notice that the example in this tutorial only applies to the Android platform.
This tutorial is directed to any developer interested in learning how to build services in the cloud and use them from mobile applications which give to the customers a more engaging environment and better experience.
You need to know how to program in Java and use Eclipse. Also, you should be familiar with building Android mobile apps. A basic knowledge of App Engine technology is not required but is a plus.
Make sure you have installed the following tools and packages for the tutorial:
From within Eclipse, open the Android SDK manager to install the latest SDK platform tools. It is recommended that you install the latest Google API. The example shown in this tutorial were verified using API level 17.
In this phase you’ll learn how to set the development environment to build the mobile application. You’ll also learn how to allow the client to communicate with the mobile backend.
The application will contain the following projects:
By following the steps described in this section, you will create an Android project with a n App Engine backend. The Android client will be able to call the backend.
As you progress, the tutorial will show you how to test what you have built up to that point.
Download the code from the MobileAssistant-Tutorial folder in Mobile Shopping Assistant. The archive contains phase 1 and phase 2 snippets that you need for the tutorial. It also contains a basic project that you might use as a reference.
If you already know how to setup an Android development environment and create an Android client application project, you can skip to Setup App Engine Backend Application Project after you c reate a client application project called MobileAssistant.
This section shows you how to create a mobile client application project. The application provides the interface which allows the customer to interact with the backend, for example to obtain sales information.
The MobileAssistant project is created. The project contains several generated classes that belong to the com.google.samplesolutions.mobileassistant package.
This section shows you how to set up the project to create the mobile backend application which runs on Google Cloud Platform (App Engine). The application contains the data repository and the business logic to support the mobile client requests.
So fa r you have created the environment for the development of the mobile assistant application, for both client and backend. In the next section you’ll start building the application and then test the communication between the mobile device and the App Engine cloud service.
In this section you will start building the application by creating a simple CheckIn entity class that allows the customer to check in a store, using her mobile device.
An entity class provides an “object-relational interface” between your application and the backend data repository.
After the customer checks in, the class insert s the store information in the backend datastore.
Now, let’s create the class in the MobileAssistant-Appengine backend application by following these steps :
Open the class in the editor. Then, in the insertCheckIn method delete the following lines:
if (containsCheckIn(checkin)) { throw new EntityExistsException("Object already exists"); }
This is because the CheckIn class is configured to use auto-generated key s. This is defined by the attribute @GeneratedValue(strategy = GenerationType.IDENTITY).
Using the endpoint design pattern and with minimal custom code, you have created the infrastructure that allows the communication between the client and the backend.
Before going forward, you’ll test the current minimal code and verify that the client and backend applications can communicate.
In this section you’ll add some code to the MainActivity class to test if the client communicates with the backend. The code contains a CheckInTask class. At power-up this class sends a fictitious store ID to the backend endpoint to indicate that the customer has checked in.
Follow these steps to add the code:
This code sets the store ID to the arbitrary value StoreNo123. This ID is assigned to the CheckIn variable setPlaceId that will be stored in the App Engine datastore. You will see this value displayed in the Datastore viewer during testing described in the next section.
The goal of this test is to verify that the code written so far is working and that the infrastructure is in place so the client and backend can communicate. Specifically, you must verify that the fictitious store ID sent by the client is stored in the App Engine datastore.
The following snippet, from the Android MainActivity.java class, shows the code that calls the backend:
Checkinendpoint.Builder builder = new Checkinendpoint.Builder( AndroidHttp.newCompatibleTransport(), new JacksonFactory(), null); Checkinendpoint endpoint = builder.build(); …....... endpoint.checkInEndpoint().insertCheckIn(checkin).execute();
Note. This test runs on your local development server, so you first must start the backend and then the client application. |
This indicates that the MobileAssistant client application connects to the local d evelopment server.
This starts the MobileAssistant client Android application simulation. The application will communicate with the backend MobileAssistant-Appengine.
If you have not selected a device for the emulation, you ’ ll be asked to do so now. Follow the steps indicated by the wizard. The model 4.0”WVGA (480x800:hdpi) was selected for the example in this tutorial.
If you get errors with 'R' being undefined and this is the first time you've tried to compile the project, it's likely that you've incorrectly installed the SDK.
If you receive this error on subsequent builds, try deleting "R.java" (a generated class) and see whether you can regenerate it successfully. If this step fails, some error exists in the files of the "res" (resources) directory. Look for Eclipse warnings particularly in the XML files.
To complete the test, you must verify that the store ID is stored in the App Engine datastore by performing the following steps:
With this, you have completed the preliminary steps in creating the mobile a pplication infrastructure.
In the next steps, you ’ ll add logic to the backend that allows the customer to obtain information about places (stores) contained in the backend data repository.
This section shows how to add more logic to the application to allow the customer to obtain information about stores contained in the backend repository. To achieve this goal, you must add a new entity class to the MobileAssistant-Appengine backend application called Place. In a real world application the information would be about places near to the customer’s location obtained in real time through GPS. The example uses simulated information contained in the App Engine datastore. Refer to the test section shown later to see how to populate the datastore.
You have created the infrastructure that allows the client application to retrieve places information that is in the backend datastore.
Let’s now modify the client application again. This will allow you to obtain information from the the backend and display it in your Android client application.
In this new version of the code, t he global resultsList variable contains the information obtained from the backend.
The client application instantiates the ListOfPlacesAsyncRetriever class at the creation time and calls its execute method (in the onCreate method).
The class makes asynchronous Mobile Assistant API calls when the customer check into a place. In the example code, it retrieves places information from the backend.
You will see this information displayed in the Android client application.
<TextView android:id="@+id/results" .../>
This defines a single layout covering the whole screen (the width and height values are “match_parent”). Inside the layout there is a single “TextView” element. This text box is initialized with the string literal “@+id/results” which identifies the list of the stores.
The results identifier is used in the OnCreate routine as follows :
resultsList = (TextView) findViewById(R.id.results); |
This allows access to the widget so you can set new content (the list of stores). Notice, you can open the Activity_main.xml file using the Android XML (visual) editor and you can assign the value @+id/results to the Id property.
The purpose of the test is to retrieve the list of places from the backend. The test is performed on local development server. Refer to the steps performed in the case of the CheckIn entity class to enable local testing. Before you can proceed with testing, you must populate the backend repository with data, as shown next.
This is the script that actually uploads the simulated information into the backend datastore.
For information about the bulkloader.yaml and more, refer to the App Engine documentation in: Uploading and Downloading Data. Also, you can find the bulkloader.yaml file and the test data here MobileAssistant-Data.
#!/bin/sh appcfg.py upload_data --config_file bulkloader.yaml --url=http://localhost:8888/remote_api --filename $1 --kind=$2 -e nobody@nowhere.com
The previous script accepts two arguments separated by a blank space:
./upload_data.sh<data.csv> <class entity name>
The first argument is the name of the csv file that contains the data you want to upload, The second is the name of the entity class to handle the data.
The simulated data is contained in the file places.csv that you downloaded earlier from the MobileAssistant-Data directory in Mobile Shopping Assistant.
The file contains the following comma separated fields:
To upload data to the datastore, reference the “remote API servlet” and associate it with a URL. You’ll define these mappings in the Web.xml file of the MobileAssistant-Appengine application, as shown next. The web server uses this configuration to identify the servlet to handle a given request.
Note. Notice, you might need to restart Eclipse. if you skip th e Web.xml modification you will get Error 404 Not Found. |
<servlet> <display-name>Remote API Servlet</display-name> <servlet-name>RemoteApiServlet</servlet-name> <servlet-class>com.google.apphosting.utils.remoteapi.RemoteApiServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>RemoteApiServlet</servlet-name> <url-pattern>/remote_api</url-pattern> </servlet-mapping>
To upload the test data to the data store, run the script that uploads the data from your script directory.
Before you upload your data, make sure to start MobileAssistant-AppEngine as a Web Application (in Debug mode) in Eclipse.
To ensure that the data has been uploaded in the datastore, perform the same steps you followed in the case of the Checkin class. Refer to Test Client and Backend Communication section from step 3 forward.
In the browser of your development machine, open the App Engine administration dashboard at: http://localhost:8888/_ah/admin,
Now that the application infrastructure is in place, let’s proceed with the second phase of this tutorial. You ’ll add the logic that allows the customer to perform the actual tasks of checking in a place and obtaining relevant information such as sales that are in progress, offers, and so on.
Note. In this phase, the tutorial will describe the logic of key points without showing all the code involved. For that you can refer to the provided downloadable examples. |
This section shows the steps to add the user interface to the client application so the customer can interact with the backend.
In order to build the UI you are going to add a few files to the MobileAssistant project and modify the MainActivity.java class as described next. The simple UI provides the following control buttons : Price Check, Online Shopping and My Account. The buttons are not yet functional in this phase.
In order for the application to do something meaningful you must add two more entity classes to the MobileAssistant-AppEngine application. The classes allow the customer to obtain information about offers and shopping recommendations.
The following are the classes you must add that you can obtain from the snippets archive downloaded earlier:
The classes you have just added rely on data information stored in the backend data repository. This means that you must populate the repository with meaningful data as shown in the test section later.
This section describes the logic to be added to the client. This logic supports the display of offers and shopping recommendations. Moreover, the code adds formatting logic to properly display text and images applicable to the store selected by the customer.
import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; private OnItemClickListener placesListClickListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Place selectedPlace = places.get((int) arg3); new CheckInTask().execute(); } };
In the onCreate method enter the following line to enlist the handler:
placesList.setOnItemClickListener(placesListClickListener);
import android.content.Intent;
PlaceDetailsActivity.currentPlace = selectedPlace; Intenti = newIntent(MainActivity.this, PlaceDetailsActivity.class); startActivity(i);
<activity android:name= "com.google.samplesolutions.mobileassistant.PlaceDetailsActivity" > </activity>
import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.json.jackson2.JacksonFactory; import java.io.IOException; import com.google.samplesolutions.mobileassistant.offerendpoint.Offerendpoint;
/** * Retrieves the list of offers through appropriate CloudEndpoint. * @param params the place for which to retrieve offers. * @return collection of retrieved offers. */ @Override protected CollectionResponseOffer doInBackground(Place... params) { Offerendpoint.Builder endpointBuilder = new Offerendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), null); endpointBuilder = CloudEndpointUtils.updateBuilder(endpointBuilder); CollectionResponseOffer result; Offerendpoint endpoint = endpointBuilder.build(); try { result = endpoint.listOffer().execute(); } catch (IOException e){ e.printStackTrace(); result=null; } return result; } }
Similar code applies to the recommendations collection.
The purpose of the test is to retrieve the offers and the recommendations from the backend. The test is performed on local development server. Refer to the step performed in the case of CheckIn entity class to enable local testing.
Before, you can proceed with testing, you must populate the backend repository with data, as shown next.
In this section you are going to define test data following the same steps as in the ca se of the places simulated data.
The simulated data is contained in the fle offers.csv and recommendations.csv that you downloaded earlier from the MobileAssistant-Data directory in Mobile Shopping Assistant.
The offers.csv file contains the following comma separated fields:
The recommendations.csv file contains the following comma separated fields:
To upload the test data to the datastore, you are going to use the same script described in Create Upload Script and follow the same steps described in Upload Places Simulation Data. From your script directory, where the offers.csv and recommendations.csv files are, execute the following steps:
Repeat the same steps for the recommendations data, as follows:
If there are no errors, you should get a successful transfer message.
To assure that the test data has been uploaded in the datastore, perform the following steps:
This section describes how to run the application using the MobileAssistant-AppEngine backend deployed in the cloud.
#!/bin/sh appcfg.py upload_data --config_file bulkloader.yaml --url=http://yourappid.appspot.com/remote_api --filename $1 --kind=$2 -e your_email
In yourappid.appspot.com replace yourappid with your App Engine application ID and replace your_email with the e-mail of the administrator for the application. You get this information from the App Engine console.
The previous script accepts two arguments separated by a blank space:
./upload_data_deploy.sh<data.csv> <class entity name>
The first argument is the name of the csv file that contains the data you want to upload, The second is the name of the entity class to handle the data.
<application>yourappid</application>
./upload_data_deploy.sh offers.csv Offer
You might be asked to enter your account password. Run the script for the other two files.
In this tutorial, you have created an app that allows users to “ shop smart ” by getting information on products they are looking for at the store they are in, as well as find stores nearby.
You used some custom code to wire a basic Android app to the App Engine cloud backend, using Google cloud endpoints, so it can determine customer location, locate nearby stores, and allow the customer to obtain relevant offers and recommendations.
The following are the highlights of the areas you must focus on to create your own application:
Y ou can use the example code in this tutorial as a starting point for your mobile application, powered by the App Engine cloud backend.
If you need more information about the technology behind the tutorial, check out these resources.
Google Cloud Endpoints allow you to define business logic on App Engine and access them via RESTful APIs on multiple platforms including Android, IOS and JavaScript. Cloud Endpoints are built using Google’s API infrastructure. For more information, see Overview of Google Cloud Endpoints.
The Google Plugin for Eclipse (GPE), that you have installed when setting the development environment, allows you to create and consume Cloud Endpoints.
In particular, it allows the automatic generation of askeleton Endpoint class that contains code to create, get, list, update and delete your entity classes.
An entity class is a POJO (Plain Old Java Object) with JPA/JDO persistence annotations. This is an ordinary Java class that is marked (annotated) as having the ability to represent objects in the database.For more information, see Storing Data in the App Engine datastore. The class shown in the example is of a JPA type. Where
To create and use an entity class you must follow the following steps: