Gradle Tutorial : Part 8 : Gradle + App Engine + Endpoints + Android Studio

Welcome to Part 8 of the Gradle Tutorial. In the previous episode i.e. Part 7, we looked at a multi-module Android project inside Android Studio. The multi-module Android project had an Android module and an App Engine module. The App Engine module was a basic one with a simple Servlet + JSP.

LAST UPDATE : January 22, 2015 :
i) Updated Screenshots for latest version of Android Studio 1.0.2
ii) Updated app/build.gradle as per the latest version of Android Studio 1.0.2
iii) Removed workaround for adding new Endpoint class in web.xml. This is now fixed in the current version of Android Studio (1.0.2)

In this part of the tutorial, we are going to look at another multi-module Android project in Android Studio, except that instead of the basic App Engine project, we are going to look at Cloud Endpoints support inside of Android Studio. This episode and an episode or two following this one, shall expand on Cloud Endpoints but in this episode, we will keep things simple and look at the Endpoints basics inside of Android Studio.

For those of you, who are not aware of Cloud Endpoints, I strongly recommend going through a couple of my blog posts, where I have covered the premise for Cloud Endpoints and Cloud Endpoints basics in the first two parts of my Cloud Endpoints blog series. They are present here : Part 1 and Part 2.

This tutorial is not a deep dive into what Cloud Endpoints is, what it brings to the table and so on. My assumption is that you are familiar with the concept, have written an Endpoint or two in Java and have primarily used the Eclipse plugin for GAE and now want to see how it is similarly supported in Android Studio.

In summary, Google Cloud Endpoints is a great way to add a mobile backend to your applications. And its integration and support inside of Android Studio is a good confirmation of the fact, that support for it inside of Android Studio is going to grow and get better. It might have its few issues in the initial versions but it is also a great time to get going with it in Android Studio. 

ep8-logo

This part assumes that you have installed Android Studio on your development machine and that you are familiar with basic Gradle commands, project structure and files as we have seen in the series so far.

I have used Android Studio (Beta) 1.0.2 on Windows for this blog post. It is not necessary to have the same version or the OS, things should be pretty much similar from a Gradle perspective.

The areas that we shall cover in this blog post are as follows:

  • Begin with a default Android application in Android Studio.
  • Add an App Engine module to the Android Project i.e. convert the Android Project into a multi-module project i.e. Android App and App Engine App. In the App Engine module for this episode, we shall go with the Endpoints module.
  • Study the Gradle files for the multi-module project that we now have.
  • Understand the sample Endpoint generated, look at adding your own Endpoint (minimal) and see what default code is generated by Android Studio to help you with your Endpoint code.

Android Application

Go ahead and create a new Android Project (call it HelloCloudEndpoints) using the Android Studio Wizard. Go with all the defaults. Nothing fancy. We have covered the steps for this in Part 6, if you want to take a look.

Add an App Engine Module

Now that we have an Android project and an Android app module within the project i.e. app, let us move forward and make this a multi-module project by adding an App Engine module to this project. We covered this in Part 7, if you want to take a look.

The steps are straightforward:

  1. Click on File –> New Module
  2. Select Google Cloud Module in the first step. Click on Next.
  3. In the New Google Cloud Module step, select App Engine Java Endpoints module for the module type.
  4. Select the module name as api and give a package name as needed.

part8-1

Click on Finish to generate the project. Once the project is generated, you will find that you have now an additional module named api in the Project hierarchy as shown below:

s21

You will also notice that you can now Run both the Android App and the App Engine if you want to.

s20

Gradle Files

In Part 3, we had covered multiple Java projects and how at the root folder, we can specify the settings.gradle and build.gradle files that apply across all the modules.

Let us recap, what we have so far:

  • We have an Android Studio Project
  • It has 2 modules
  • One module (app) is the Android app
  • One module (api) is the App Engine app

So, let us look at the settings.gradle file at the root:

include ':app', ':api'

It includes now both the app module and the api module, which is how we had seen in Part 3 of this series.

The build.gradle files at the root folder is the same as we had seen in the previous episode, so I am not repeating here.

app module – build.gradle

This file is the same as the previous episode, except for one important difference. 

As you know, Endpoints provides a backend for your mobile application and it does that by providing a standards-based REST API that exposes your backend functionality, such that it can be invoked from the Android application. We shall see in a later episode as to how to integrate this API i.e. Endpoints code into your Android application.

For now, what is important to note is that Android Studio assumes that since your app module (Android app) depends on the api module (App Engine Endpoints app), it puts that dependency into the build.gradle file for the app module. The relevant part from the dependencies section is shown below:

...

dependencies { 
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile 'com.android.support:appcompat-v7:21.0.3'
 compile project(path: ':api', configuration: 'android-endpoints')
}

...

We had learnt this stuff in Part 3, where we had look at multi module Java projects and how you can place the dependencies on each other in the build.gradle file. The above highlighted line simply states that to compile app module successfully, we have to first compile / build the api module. And which makes sense, doesn’t it ?

api module – build.gradle

Let us now, step inside of the api module. There you will find the module specific build.gradle that is shown below. Remember, this one is an App Engine application, so it will utilize the App Engine plugin. We had seen a similar looking build.gradle file in Part 5 of the series.

The api/build.gradle file is shown below:

// If you would like more information on the gradle-appengine-plugin please refer to the github page
// https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

buildscript {
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath 'com.google.appengine:gradle-appengine-plugin:1.9.14'
 }
}

repositories {
 mavenCentral();
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'

sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
 appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.14'
 compile 'com.google.appengine:appengine-endpoints:1.9.14'
 compile 'com.google.appengine:appengine-endpoints-deps:1.9.14'
 compile 'javax.servlet:servlet-api:2.5'
}

appengine {
 downloadSdk = true
 appcfg {
 oauth2 = true
 }
 
 endpoints {
  getClientLibsOnBuild = true
  getDiscoveryDocsOnBuild = true
 }

}

Some of the important points are:

  • Take a look at dependencies closure that we have seen earlier. It includes the App Engine SDK 1.9.14 and also the Servlet jar and in addition to that, it also includes the endpoint JARs. This is needed so that we can compile/build/run endpoints related code and all the annotations that are endpoints specific can be found.
  • In the appengine closure, you will notice another closure aptly titled endpoints that is in addition to the previous code. These attributes, when set to true, automatically download the Client Libraries and the Discovery Docs before the war task is called. Refer to the official documentation on the Gradle App Engine plugin.

That’s about it really as far as the Gradle stuff is concerned.

Tip: Keep in mind that anytime you make any changes to your build files, do remember to click on the Sync Project with Gradle Files as shown below. It should launch the build and you should be able to see the Gradle commands getting executed in the Gradle Console.

gradle-ep6-11

Cloud Endpoints – Understand the files

This section assumes that you are familiar with some extent with Google Cloud Endpoints in Java. I recommend going through Part 1 and Part 2 of my tutorials on End points, if you are absolutely new to Endpoints.

MyBean.java

This is the default Object Model generated when you use the add a Cloud Endpoints module to your Android Studio project. The MyBean.java is not much and I would have liked to see something more than this, but it suffices for the sake of understanding here.


package com.mindstorm.api;

/** The object model for the data we are sending through endpoints */
public class MyBean {

private String myData;

public String getData() {
 return myData;
 }

public void setData(String data) {
 myData = data;
 }
}

MyEndpoint.java

This is the Endpoint class and it exposes some of the operations around the MyBean model that we just saw. The code is listed below:


package com.mindstorm.api;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;

import javax.inject.Named;

/** An endpoint class we are exposing */
@Api(name = "myApi", version = "v1", namespace = @ApiNamespace(ownerDomain = "api.mindstorm.com", ownerName = "api.mindstorm.com", packagePath=""))
public class MyEndpoint {

/** A simple endpoint method that takes a name and says Hi back */
 @ApiMethod(name = "sayHi")
 public MyBean sayHi(@Named("name") String name) {
 MyBean response = new MyBean();
 response.setData("Hi, " + name);

return response;
 }

}

If you are familiar with Cloud Java Endpoints, here are the main points:

  • The @Api annotation marks the class as an Endpoint. Its name is myApi and it has been given a version v1
  • The method sayHi has been exposed as one of the Endpoints methods. The name of the API is sayHi as per the annotation @ApiMethod and the name attribute. There is nothing much happening in the code other than instantiating the bean and returning the bean. Do note that this episode will keep things simple and in a subsequent episode, we shall see persistent data and a lot more methods. 

Endpoints in Action

Let us see how to run and test out the Endpoints so far inside of Android Studio. I prefer giving you instructions via the Terminal, so that you can use the Gradle Tasks.

  1. Launch a Terminal window as shown below. Navigate to the root folder and then fire the gradle command as shown below. Do note that we are simply starting up the App Engine Local Dev Server here via the appengineRun task. We are prefixing it with the module name i.e. api , since we are at the root and we need to specify which module and Gradle Task inside of that, which we are interested in firing.s22
  2. Once the server is started, you should see the a message saying that the local server is running as shown below:

s23

Once the Local Dev Server is started, go ahead and visit the local dev server at localhost:8080 URL via browser as shown below.

s8

Enter some text and click on Say Hello, it should all work fine:

s9

The next thing that you should do is check out the Endpoints Explorer. As mentioned earlier, Google Cloud Endpoints provides a REST Endpoint that exposes your functionality. In our case, it is the MyBean with the Endpoint that exposes a single method sayHi.

Typically, this is accessible via http://localhost:8080/_ah/api in your browser. You could either type that out or you can click on the Google Cloud Endpoints API Explorer as shown below:

s10

Click that and it should bring up the API Explorer as shown below. Make sure you are connected to the Internet.

s11

The above screen indicates that you have an API, whose name we had seen earlier MyAPI with version 1.0. Click on the MyAPI API and it will display you the available methods that you can invoke as shown below:

s12

Click on the MyAPI.sayHi method. This will bring up a form where you can test out the API:

s13

Notice how the API Explorer is able to introspect your method parameters and provide you a convenient HTML form, where you can enter your parameter values. Enter some value and click on Execute. This will invoke your API, and show you the request / response details as given below:

s14

For those coming from the Eclipse + Cloud Endpoints world, this should all be familiar.

Add a new Endpoint API

Let us now look at adding our own Java class and creating an Endpoint around it. Though it is not going to be too different that the one (MyBean) that was generated for us, it is important to look at the tools available and I wanted to also show you a bug that I came across.

Let us add our own Bean class that we want to expose as an Endpoint. The class is a simple Quote.java class as shown below:

Quote.java


package com.mindstorm.api;

/**
 * Created by irani_r on 8/25/2014.
 */
public class Quote {
 Long id;
 String who;
 String whom;

public Long getId() {
 return id;
 }

public void setId(Long id) {
 this.id = id;
 }

public String getWho() {
 return who;
 }

public void setWho(String who) {
 this.who = who;
 }

public String getWhom() {
 return whom;
 }

public void setWhom(String whom) {
 this.whom = whom;
 }
}

You can create the above class via the File -> New -> Java class option. Make sure that you place the file in the api module inside the src/main/java and the respective package file.

Now, just like in Eclipse, you can use one of the Code Generation options that is available in Android Studio also. Simple select the Java file i.e. Quote.java and do the following:

  • Right click on the file.
  • It will popup a menu. Go right to the end and you will see an option to generate the Endpoint class as shown below:

    part8-2

  • Click that.

This will generate the QuoteEndpoint.java class as shown below:

QuoteEndpoint.java


package com.mindstorm.api;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;

import java.util.logging.Logger;

import javax.inject.Named;

/**
 * An endpoint class we are exposing
 */
@Api(
 name = "quoteApi",
 version = "v1",
 resource = "quote",
 namespace = @ApiNamespace(
 ownerDomain = "api.mindstorm.com",
 ownerName = "api.mindstorm.com",
 packagePath = ""
 )
)
public class QuoteEndpoint {

 private static final Logger logger = Logger.getLogger(QuoteEndpoint.class.getName());

 /**
 * This method gets the <code>Quote</code> object associated with the specified <code>id</code>.
 *
 * @param id The id of the object to be returned.
 * @return The <code>Quote</code> associated with <code>id</code>.
 */
 @ApiMethod(name = "getQuote")
 public Quote getQuote(@Named("id") Long id) {
 // TODO: Implement this function
 logger.info("Calling getQuote method");
 return null;
 }

 /**
 * This inserts a new <code>Quote</code> object.
 *
 * @param quote The object to be added.
 * @return The object to be added.
 */
 @ApiMethod(name = "insertQuote")
 public Quote insertQuote(Quote quote) {
 // TODO: Implement this function
 logger.info("Calling insertQuote method");
 return quote;
 }
}

The code that is generated is not something you want to put into production and I am sure that it will improve over time. But it gives you 2 methods getQuote and insertQuote as shown above. Notice that the appropriate @API Annotation (the API name is quoteEndpoint)  is added to the QuoteEndpoint.java class.

Restart the Dev Server and then navigate over to the API Explorer, you will be able to see both the API Endpoints now and if you navigate to the quoteEndpoint API, you will see both the methods as listed below:

s19

Deploying the API Module to App Engine

So far we have seen the Endpoints module (api) running locally. If you want to deploy the module to App Engine, you will need to do the following steps:

  1. Create a Project via the Cloud Console and note down the Project Id. If you already have a project that you wish to deploy into, then you just need the Project Id.
  2. Go to api/src/main/webapp/WEB-INF/appengine-web.xml file. Provide your Project Id in the <application> element. Save the file.
  3. Go to api/build.gradle and modify the appengine closure as shown below (Note the items in bold:
     appengine {
        downloadSdk = true
    
        appcfg {
           oauth2 = true
           noCookies = true
           email = "<Your Google Account Email Address>"
        }
    
     endpoints {
       getClientLibsOnBuild = true
       getDiscoveryDocsOnBuild = true
     }
    }
  4. Now go to the Terminal and from the root folder, fire the following Gradle command:gradlew api:appengineUpdateThe steps are similar to the ones that we saw in Part 5, where we covered how the OAuth process will kick in for authentication and how you need to paste the verification code, etc.
  5. The terminal should show a flurry of log statements after which the app will be deployed.
  6. You should visit the Cloud Console to confirm if the app is ready. Additionally, you can access the API explorer via the following URL :
    http://yourprojectid.appspot.com/_ah/api/explorer. Note that we have simply replaced the localhost:port with yourprojectid.appspot.com

Moving forward

This tutorial helped you understand support for Google Cloud Endpoints module in a multi-module Android project within Android Studio.

Cloud Endpoints is a vast topic and the next 1-2 episodes will focus on adding persistence to your Cloud Endpoints and how to invoke your Cloud Endpoints code from Android app. Well that is the main point since we generated the Android Studio project with the Android app, adding a Cloud Endpoints module and so we better be able to call the Endpoints API from the Android app ! 🙂

Till then, Happy Gradling!

Advertisements

16 thoughts on “Gradle Tutorial : Part 8 : Gradle + App Engine + Endpoints + Android Studio

  1. Awesome Tutorial…one of the best i ever saw….thank you iRomin….

    iRomin One Question From my side….can you just tell me how to upload images on google cloud storage from android app ..
    just give me some hint, Thank you in Advance

    1. Thank you for the feedback.

      You have several ways to upload an image to GCS via Android. I would suggest that you build out an App Engine service / endpoint that can take your image data. That would be the first step and which means that you can use your POST/PUT to send the data to the Server.

      Now, once you have this data – you can choose to use the Blobstore Service or better still GCS (which is the recommended way). GCS Provides APIs that help you put your image data into respective buckets.

      If your images are small, you may want to consider Datastore API itself. But you would be limited by the size of image data that you can put there. Max. 1MB.

      Check out this http://stackoverflow.com/questions/30410244/how-do-i-upload-a-filepicture-from-android-and-save-to-the-blobstore-using-gae/30420042#30420042 Thread for more information.

  2. can we upload via this kind of code :- given below

    class ImageUploadTask extends AsyncTask {
    private StringBuilder s;

    @Override
    protected void onPreExecute() {
    // TODO Auto-generated method stub
    super.onPreExecute();
    mProgress = new ProgressDialog(gappshap.this);
    mProgress.setMessage(“Loading”);
    mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    mProgress.setCancelable(false);
    mProgress.show();
    }
    @Override
    protected String doInBackground(Void… unsued) {
    try {
    String sResponse = “”;
    String url = “http://storage.googleapis.com/the-1/?”;
    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(url);
    MultipartEntity entity = new MultipartEntity();

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
    byte[] data = bos.toByteArray();
    entity.addPart(“post_id”, new StringBody(“1368”));
    entity.addPart(“user_id”, new StringBody(“62”));
    entity.addPart(“files[]”, new ByteArrayBody(data,”image/jpeg”, “test2.jpg”));

    httpPost.setEntity(entity);
    HttpResponse response = httpClient.execute(httpPost);

    BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), “UTF-8”));

    s = new StringBuilder();

    while ((sResponse = reader.readLine()) != null)
    {
    s = s.append(sResponse);
    }

    if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
    {
    return s.toString();
    }else
    {
    return “{\”status\”:\”false\”,\”message\”:\”Some error occurred\”}”;
    }
    } catch (Exception e) {
    Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
    return null;
    }
    }

    @Override
    protected void onPostExecute(String sResponse) {
    try {
    mProgress.dismiss();
    if (sResponse != null) {
    Toast.makeText(getApplicationContext(), sResponse + ” Photo uploaded successfully”,Toast.LENGTH_SHORT).show();
    }
    } catch (Exception e) {
    Toast.makeText(getApplicationContext(), e.getMessage(),
    Toast.LENGTH_LONG).show();
    Log.e(e.getClass().getName(), e.getMessage(), e);
    }
    }
    }

  3. I rarely take the time to leave comments on any site, but your tutorials on Cloud Endpoints in general and how to use them with an Android app are so good I had to take a minute to tell you how helpful your tutorials have been. WELL DONE!! EXTREMELY HELPFUL!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s