Google I/O 2013 Session Overview: From Nothing to Nirvana in Minutes: Cloud Backend for your Android Application – Building Geek Serendipity

David Chandler and I just finished our session on cloud-enabling your Android applications at Google I/O 2013.

  1. the video of the talk is posted you YouTube.
  2. the source code for the demo published on github
  3. the Geek Serendipity application we created is on the Play Store

Here is the Geek Serendipity app we built.  It enables you to share your Geekly interest and see what geeks are around you. In the bottom we are showing your lat long and a geohash which we use to find who is “near” you.

There are four things that are important to me when we  started this application.

  1. Client Focused Dev – we didn’t want to manage servers, deal with security patches, or figure out availability zones. As an android guy, David wanted to focus 95% of my energy on building an amazing android app rather than writing server code.
  2. Location Saved to Cloud – We need to share locations between users and that means we do need a cloud backend to share this state.
  3. Update Geeks Nearby Live – We like android apps that living and active. If I look at the app while I drink my soy latte double cappuccino I’d like to see geeks pop in as they come near by.
  4. Avoid typing password – We don’t want my users to have to remember and type in passwords on the phone. Tiny screen, tiny keyboards and passwords don’t mix.

At Google I/O we are announcing the Mobile Backend Starter. This is a starter application that makes it easy for you to get started building your mobile backend in the cloud! We have focused on making it a no server code solution. So you can ship a production application with no server coding required. Of course if you’d like to download the server code you can customize it as much as you need. We have also added GCM support and continuous queries so you can register a query that will call you back at anytime in the future when it is true. All this with built in Google Authentication.

With this starter application, you don’t need to write any server code to get the basic experience we are showing up and running. Right out of the box, you get two things. A backend that stores your data with App Engine and a front end in android that makes it trivially easily to access that data.

We have taken that very cool Mobile Backend Starter and extended it for our Geek Serendipity use case. For the data, we are storing the geohash of the location and last reported timestamp for each user. We are also usingGoogle Cloud Messaging for Android and the continuous queries to keep each client up to date with where all the geeks are. And Finally we are using Google Maps V2 to display the locations.

Part One — Basic Cloud Connected App

To get started, go to the new Google Cloud Console. This console will be the one stop shop for all your Google cloud developers needs from getting access to Google APIs such as Google Maps to accessing computing resources such as Google Compute Engine and App Engine.

Here is our new Cloud Console. From here I can create and manage all my cloud backends. From here you can create a new project. We give the project a name, then we have an app ID that is used for programmatic access. Notice this is our startup name generator… let’s see if we can get a good one… I like dauntless-bay-213, but I’ll change it to geek-serendipity.

Now I have a project, we need to mobile enable it. To do that I will just click deploy here on this mobile backend. What this does is install the mobile backend starter on the app engine application

Clicking on deploy, starts the magic!

Step number 2 is to check out the settings for this backend. By clicking on the settings button there we are navigated to the setting page for the mobile backend.

By default this is set to locked down, no http requests will be accepted. We will move it to Open, this will make it so that anyone unauthorized client can access my backend, so this mode is suggested only for development.

Step #3 is to download the source code for the android client. We have pre-built a sample guestbook application that is intended for you to use as a way to get started. At the talk, we used Android with the latest version of the ADT installed.

Just import this into eclipse (this works just as well in Android Studio).

Then select the unzipped directory we downloaded…

…and import this project.

As you can see we have a few libraries here, then a main guestbook application.

 

We can open up Const.java and paste in our appid we gave when we created this app.

And set the project Id to the one we gave when we created the app.

 public static final String PROJECT_ID = "geek-serendipity";;

As you can see here, we have given the project ID on the client and that is the

Now we can run it and enter a few messages.

If we flip over to the Cloud Console and look at the Datastore, we see our two messages

Wow, that is pretty cool… 5 mins into this demo we already have a cloud connected application that will store it’s state in the cloud so it works perfectly as users change devices.

What we have done so far is spin up a backend on app engine, download the client, add the project ID and run it.

Part Two — Push Notifications

We are going to want a vibrant app that does live updates. Let’s see how we can work live updates into this application. A naive way to do this would be poll every few minutes by calling back to the server and see if there are new items. While this is a common technique the biggest problem is battery life, network traffic and load on your server. Not to mention latency the user sees for new messages arriving.

Google has already established a channel to communicate to the Google apps on the device. Google+, GMail and Chat, etc all get called back from the server whenever there is new content for you. Google handles making sure that connection stays active with the minimum power usage and network traffic. Wouldn’t it be cool if your applications could use that that exact same channel…. You can! Google Cloud Messaging for Android is exposed for your applications to use for exactly this reason.

But the setup for using Google Cloud Messaging has been tricky. You need to setup your own server, handle and track device registration, do OAuth2 auth, REST calls back to the GCM service, etc. Let’s see how easy it is with the Mobile Backend Starter.

We need to do two things. First, on the server side we need to enable GCM and enter the Server API key into the Mobile Backend Starter setting page. The Server API key identifies who (which project) is making the calls to GCM to register devices and send notifications.

The second thing we need to do is paste in the project number into the Const.java file in the client project. This is used as part of device registration with GCM. It tells GCM which notifications to send to this device.

Let’s look at how we do this.

First, we enable Cloud Messaging for Android in the API List of the Cloud Console by selecting APIs, and then enabling Cloud Messaging for Android.

Then we go to the Mobile Backend Starter setting page and enable GCM. As you see it needs a API Key.

I can create this in API Access by going back into the API Listing page and register a new app. In this case, I am registering the mobile backend app… such that it can access the GCM API we just enabled.

Now I can just grab that Server API Key and paste it into the config page and I am done!

The last step is to add the project number to the Const.java file. We are in the middle of transitioning to the new cloud console, but it isn’t easy to see the project number from the new console yet. You need to bounce back to the old APIs console to see it. The easy way to do that is to click on

And finally, we need to paste the project number into the client project.

Now, we really need two devices to really test this out. If you are not lucky enough to have two, you can run them in virtual devices as well. If all is working well, when you click send on one a few seconds later you see the message show up on the other.

Part Three — Add Map

The sample app for our talk shows the locations of geeks on a map. You can create a new MapActivity in your project by following the instructions at Getting Started with Google Maps Android API v2. To enable backward compatibility with older versions of Android, the demo app uses the MapFragment from the Android support library. The layout looks like this:

 


The FrameLayout and TextView are not required for maps. We’re using the TextView overlay to show authentication status directly on the map. Here is our corresponding MapActivity:

 

package com.google.cloud.backend.android;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.widget.TextView;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MapActivity extends FragmentActivity {

	private GoogleMap mMap;

	private void setUpMapIfNeeded() {
		// Do a null check to confirm that we have not already instantiated the
		// map.
		if (mMap == null) {
			// Try to obtain the map from the SupportMapFragment.
			mMap = ((SupportMapFragment) getSupportFragmentManager()
					.findFragmentById(R.id.map)).getMap();
			// Check if we were successful in obtaining the map.
			if (mMap != null) {
				setUpMap();
			}
		}
	}

	private void setUpMap() {
		mMap.setMyLocationEnabled(true);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_map);
		setUpMapIfNeeded();
	}

	@Override
	protected void onResume() {
		super.onResume();
		setUpMapIfNeeded();
		TextView overlay = (TextView) findViewById(R.id.overlay);
		overlay.setText("Not signed in");
	}

}

Part Four — Store Location in the Cloud

 

To send our location to the cloud backend, we need to get notified of location updates, then make a request to our backend service. To get notified of location updates, we’ll register the MapActivity class as an OnMyLocationChangeListener. To do this, we call mMap.setOnMyLocationChangeListener(this) in the setUpMap() method and let the MapActivity class implement OnMyLocationChangeListener. The required method looks like this:

	private void setUpMap() {
		mMap.setMyLocationEnabled(true);
		mMap.setOnMyLocationChangeListener(this);
	}

	protected String myLocation;
	protected static boolean locSent;
	private static final Geohasher gh = new Geohasher();

	@Override
	public void onMyLocationChange(Location location) {
		this.myLocation = gh.encode(location);
		if (!locSent) {
			sendMyLocation();
		}
	}

To send our location to the server, we can use the features of the Mobile Backend Starter project. MBS provides a generic entity (CloudEntity) on which we can set arbitrary properties and a set of CRUD services that know how to send and receive it. To implement sendMyLocation(), we simply let our MapActivity extend CloudBackendActivity, then create a new CloudEntity and update the server:

 

	private void sendMyLocation() {
		CloudEntity self = new CloudEntity("Geek");
		self.put("interest", "Cloud");
		self.put("location", this.myLocation);
		getCloudBackend().update(self, new CloudCallbackHandler() {
			@Override
			public void onComplete(CloudEntity results) {
				locSent = true;
				drawMyMarker();
			}
		});
	}

Note: at the time of this writing, CloudBackendActivity extends the basic Activity class. To use it with a MapFragment and the support library, you’ll need to modify CloudBackendActivity to instead extend FragmentActivity from the support library.

 

Part Five — Add Authentication

 

We are now storing sensitive information (your location) up in the cloud and as such we want to be sure we have locked down access to our server to only our client.  We also want users to authenticate so that we know who they are even if they use different devices.   Authentication can be difficult on mobile devices.  Are you going to ask your users to type in a username and password on the little keyboard?  Will they even be able to remember a username and password for just your app?  what if they lose their password or it gets stolen?

 

The Mobile Backend Starter makes it very easy to use Google Authentication.   Nearly every Android phone has a Google account that your customers are already using for GMail, Chat, Google Now or other google services.     You can use that same account in our application no passwords for our users to remember, no admin headaches for you.

We will just go in and enable auth in the Mobile Backend Starter setting page.

There are three steps to enabling auth. The first step is to ensure that we have strong identity for the android client. We want to lock down access to our Cloud Endpoints (our REST API) to only our own Android client.

That is way the first box is asking for — the Android Client ID. The Android Client ID is how we uniquely identify your application run in an android device. It allows for secure access between your code on the device and your code in the cloud. One common way to do this is to create a “secret” and embed that into the client application. The problem with this approach is that it is easy to find that secret. How many of you have ever decompiled a class file? yea — not that hard. The secrets don’t work well if they are easy to find.

We are going to use a different approach. The same approach in fact that Google Play uses to uniquely identify an application to update. You might imagine it would be “bad” to update the wrong app. So we have developed a mechanism that is client-secret free to strongly identify an application.

To do this, let’s create a client ID for Android in the Cloud Console, in the API section, select Register App. This time we want to register the Android client, so we select Android and directly from Android.

In the Android Identification section it asks for a package name and SHA1 fingerprint. It is a cryptographically secure hash of the manifest we use to sign the android app. There is a handy keytool app (you can get that for Windows as well) and run it over your keystore. Eclipse users can find it in ~/.android/debug.keystore. For the debug.keystore, there is likely not a password, so just hit return there.

There that is our SHA1 hash… now we give that to the Cloud Console along with our package name (com.google.cloud.backend.android) to give us a key.

And we give that key to the Mobile Backend Starter.

OK, I mentioned there’d be three steps for enabling auth… That was step 1, restricting access to just our client. Now for step 2, establishing the client and the server are from the same developer so we can avoid the standard OAuth2 prompt. You may have seen an OAuth2 dialog when an application is asking for permission to, for example, access your data on Google+.

It makes perfect sense that in this case the application has to ask the user for permission to access their data stored in google+. But in our case there is no 3rd party here. Our users are using our app to access their data stored by us. There is really no reason to prompt the user in this case.

So to avoid this dialog, we need to establish that the same developer is building the client and the server. To do this we share a token between them. Notice this is NOT a secret. Feel free to publish this client ID. Even if someone has this token they will still not be able to access your server as the requests would not be coming from a signed application.

We already have a Web Server Application created for GCM, we just need to grab the OAuth2 client ID.

And add it to the Mobile Backend Starter.

We just add this to the backend and the client.. and set the client to be auth enabled..

The final step is to pass the user name from the client to the server. Luckily Android, App Engine and the Mobile Backend Starter all have built in support for Google Auth so it is very easy to have the same user on the client and server. No explicit code need to enable it.

Now you see we are giving a chance to select an account (because I have more than one). and NO password typing on the phone!

You can see the client has access to my user name…

And there we see in Datastore in cloud console you see the entities are now owned by users. We keep up with who created and who updated each entity.

Part Six — Continuous Queries

One powerful feature of the Mobile Backend Starter code is continuous queries. Built on the App Engine Prospective Search API, this capability notifies the mobile client via Google Cloud Messaging whenever query results change on the server. For our Geek Serendipity app, the process works like this:

 

  1. The client sends an updated location to the server.
  2. Prospective Search notifies the MBS App Engine code.
  3. The MBS server sends a GCM message to the client.
  4. The MBS client calls the original query for to get updated results.
  5. The MBS client invokes the query handler with the results.

 

All of this happens transparently using a single feature of the app. The relevant code for the Geek Serendipity app is here:

 

private void queryGeeks() {
		CloudCallbackHandler<List> handler = new CloudCallbackHandler<List>() {
			@Override
			public void onComplete(List results) {
				drawMarkers(results);
			}

			@Override
			public void onError(IOException e) {
				Toast.makeText(getApplicationContext(), e.getMessage(),
						Toast.LENGTH_LONG).show();
			}
		};

		CloudQuery cq = new CloudQuery("Geek");
		cq.setLimit(50);
		cq.setSort(CloudEntity.PROP_UPDATED_AT, Order.DESC);
		cq.setScope(Scope.FUTURE_AND_PAST);
		getCloudBackend().list(cq, handler);
	}

The queryGeeks() method registers a continuous query to return the top 50 most recent location updates. By setting Scope.FUTURE_AND_PAST, the handler passed to getCloudBackend().list() will be invoked whenever there are updated results on the server.

 

Because our geek query is a continuous query, we only need to register it once, but we want to do that only after MBS has been initialized (GCM has been registered and MBS is ready for query subscriptions). In addition, if authentication is enabled on the MBS settings page, we want to wait until the user has been authenticated. MBS has a special hook that meets all these criteria. To use it, simply override the onPostCreate() method from CloudBackendActivity:

 

	@Override
	protected void onPostCreate() {
	    queryGeeks();
	}


Now our query will run immediately on initialization and thereafter whenever there are new geek location updates on the server.

Part Seven — Customizing the Backend

Well, we have just about got this application wrapped up. And that Mobile Backend Starter we used has served us really well. We have not had to do any server coding at all. And that is great. This is a great way to get started, but what if I need more? What if I need to write a some custom server code? Well with the Mobile Backend Starter you never hit a limitation or roadblock you can’t work around.

The backend we deployed at the start of this talk, is actually an app engine application that you can go and download yourself. All the source code is on github. You can download it, see how we implemented it, and customize it to meet your needs.

To show that off, let’s look at how to add some custom client logging to server. As Googlers, we **LOVE** to make data driven decisions. Data on how our app is used on the client can help us make it better if we can see it in aggregate over time. So let’s add some logic for the clients to log directly to the server and stick them in App Engine’s logs where then can be imported in BigQuery for analysis.

So basically we are going to add a new custom Endpoint to the App Engine app (ClientLoggingEndpoint) that stores data in the app engine logs store, then add a CloudLog class to android app that sends client logs up to the server.

Lets’ start by downloading the backend, now we will important it into eclipse in the same workspace as our android project. (Note, for this part you do need the Google Plugin for Eclipse installed).

Now, let’s add our custom method…

ClientLoggingEndpoint.java

@ApiMethod(
   name = "logs.log",
   path = "logs/log/{message}",
   httpMethod = HttpMethod.POST
)
public void logFromClient(@Named("message") String message) {
   log.info("client log: " + message);
   return ;
}

Now we need to be able to access this method from the client. Well that is pretty easy. Right click on Google menu and select Generate Cloud Endpoint Library.

Now, the library will be generated in the endpoints-libs director. You see we have a new directory there for our logging service.

Now we simply need to copy this into the android project (you can just drag it down into the endpoints-libs of the android project.

Now we just add this library to the java build path… We actually need the clientlogging-v1-generated-source to the build path.

OK, great. Now we just need to use this client library from the Android app. To make that easy, I created a simple CloudLog.java class to encapsulate access. The main method of which is below.

Notice we are using a thread to get the network calls off the main UI thread. We want to be sure that this logging does not in anyway negatively affect the experience for the user. No laggy UI while we are posting the logs to the server. Also note, I am sending each log directly to the server… a better pattern would likely to be to batch, but I will leave that as an exercise for the user.

	public void Log (final String message) {

			new Thread(new Runnable() {
			    public void run() {

					Clientlogging.Builder builder = new Clientlogging.Builder (
							   AndroidHttp.newCompatibleTransport(),
                                                           new GsonFactory(), null);
					Clientlogging service = builder.build();
					try {
						String msg = android_id +":"+ message;
						service.logs().log(msg).execute();
						android.util.Log.d("log", msg);

					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						android.util.Log.e("log", e.toString());

					}
			    }
			  }).start();
	}

Now we just need to make some changes to the main activity to call it in GeekWatchActivity.java.

First we created the CloudLog class, passing the unique ID of this device (do we can look at pre-device usage patterns later).

android_id = Secure.getString(getApplicationContext().getContentResolver(),
		                Secure.ANDROID_ID);

cloudLog = new CloudLog (android_id);

Then we add some logging to interesting places, here is one example:

        @Override
        public void onCameraChange(CameraPosition position) {
                LatLngBounds visibleBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
                findGeeks(visibleBounds);
                cloudLog.Log("Camera Changed");
        }

Deploy the backend to App Engine and run the client app and use the app a bit. Logs are being written to the App Engine logs store.

 

Now that we have it in GAE logs, we can easily import this into BigQuery or other tool to get meaning and drive improvements.

 

Conclusion

 

Hopefully you’ll find that the Mobile Backend Starter project is an easy way to get started building a cloud back end for your Android app. The CloudEntity and corresponding CRUD endpoints allow you to update and query data in the cloud without having to write any server code, and continuous queries offer Google Cloud Messaging functionality right out of the box.

 

To learn more, please see these resources:

Google I/O 13 session video

Geek Serendipity source

Geek Serendipity application on Play Store

16 thoughts on “Google I/O 2013 Session Overview: From Nothing to Nirvana in Minutes: Cloud Backend for your Android Application – Building Geek Serendipity

  1. Pingback: Dew Drop – May 21, 2013 (#1,551) | Alvin Ashcraft's Morning Dew

  2. Pingback: Google Cloud + Android with Mobile Backend Starter « TurboManage

  3. Aaron Gifford

    Brad, thank you for putting up these server configuration details. This was exactly what I needed to get up and running with GCM.

  4. Chem Swift

    Is there any other documentation for the mobile backend project? Every time I try to run the app I get errors saying files are missing. Any help would be great.

  5. Anonymous

    This looks great – many thanks.

    I’m having some trouble adding authentication to the android client – when I try to create register the new application for the API, it reports:

    Register App Failed

    Error (projectId=YYYYYYY)

    OAUTH_CLIENT_KEY_ALREADY_EXISTS: OAuthClient key exists

    (I have replaced the project ID with YYYYYYY)

    I’m not sure if this is a config issue internal to my app, or if it’s a consequence of using the android debug keys.

    I’m going to dig around for a good primer on app engine client authentication…

    1. Anonymous

      Probem solved by (I think) deleting the same creds on another test app – that was deleted.

      (had to undelete the project via the old console https://code.google.com/apis/console , then delete the creds within it, then delete the project again.)

      I think possibly creds are valid globally even after an app has been deleted – presumably until the app has been fully deleted (ie undelete is no longer available.)

      I’m not 100% sure, but posted this in case anyone has the same issue.

  6. David Moberg

    java: package com.google.api.client.googleapis.services.json does not exist

    java: cannot find symbol

    symbol: variable super

    location: class com.google.cloud.backend.android.mobilebackend.MobilebackendRequestInitializer

    etc :S
    (Android Studio)

    1. Matt

      Try exporting the project from Eclipse (you might need to add a local.properties file as well) before importing to Android Studio, it’s working on Android studio for me after doing this.

  7. CloudEnthusiast

    Are the results the mobile client gets from querying the backend also stored locally in the mobile device ( something like a sqlite db), so that everytime the user starts the app it would not retreive all the records.

    I am a newbie to cloud storage, please dont shout at me if my question seems stupid.

  8. Asincrono

    I wander if you can hel me. I’m habing a really weird behabiour.

    I used the basic backend starter client code and tweaked it just to insert cusmtom data (didn’t actived authentication yet).

    The weird thing is that the insertions works fine for some time, but if some ours after I try (without change in the code) do more insertions I get the :

    com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found

    and keep failing till I redeploy the mobile backend and let pass some minutes.

    I’m just perplex an furstrated. Can you give me any idea why is that happening?

    Anyway thanks for the post and the IO video.

    1. Bill Lahti

      I too was getting 404 responses in the Android client. When I looked at the App Engine side it was reporting configuration errors. I found that I could get rid of the errors by setting the values for Audience and Client Ids in the Mobile Backend Settings. More information on Stack Overflow (see http://stackoverflow.com/a/17495210/1685670).

      1. Bill Lahti

        I finally got the whole thing working. Quite a challenge getting all the right client ids set up and placed in the right spots. Very nice demo. So much to learn. Thanks, Brad.

  9. Splaktar

    This Mobile Backend Starter project doesn’t appear to be listed anywhere that I can find in the Google Cloud Console. There is a get started by deploying our Photofeed sample app, but nothing else like shown in the video,.

  10. Krasimir

    I have a problem which I cannot solve from few days and not know what to do. The problem is :

    I do everything from this tutorial step by step and when I reached the end of “Part One — Basic Cloud Connected App” and run “CloudBackendAndroidClient” project as Android Application I get this Exception :

    12-17 16:38:02.052: I/CloudBackend(1884): Registration not found.

    12-17 16:38:02.100: D/AndroidRuntime(1884): Shutting down VM

    12-17 16:38:02.100: W/dalvikvm(1884): threadid=1: thread exiting with uncaught exception (group=0xa4c40648)

    12-17 16:38:02.188: E/AndroidRuntime(1884): FATAL EXCEPTION: main

    12-17 16:38:02.188: E/AndroidRuntime(1884): java.lang.RuntimeException: Unable to resume activity {com.google.cloud.backend/com.google.cloud.backend.sample.guestbook.GuestbookActivity}: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.google.android.gms.common.account.CHOOSE_ACCOUNT (has extras) }

    Please Help Me

    P.S. I have Project in Google Cloud Console

      1. Krasimir

        I download Android Client from link above and run on real device and I get this Exception :

        java.lang.IllegalStateException: The meta-data tag in your app’s AndroidManifest.xml does not have the right value. Expected 4030500 but found 13. You must have the following declaration within the element:

        and I replace it with “4030500″ and run it again.

        Guest Book start it but display that ERROR :

        12-18 20:37:06.567: I/CloudBackend(1801): com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException

        and I cannot write a message in EditText in Guest Book.