 |
Finished version of "Built It Bigger" |
It’s official. Yes, I did complete the “Build It Bigger” project
for the Android Developer Nanodegree, but that was a week ago. The only news is
that I’ve finally put my laziness aside to write about it!
Like the post on Popular Movies, I’ll detail the key
features, how I chose to implement them, and the challenges involved. And of
course, there will be plenty of screenshots of the finished product.
The Assignment:
The accompanying course for this project was all about
Gradle; that mysterious thing in Android studio that keeps displaying yellow
messages about “syncing”. Previously, my only encounter with Gradle was
hopelessly updating the version number on older projects and occasionally
adding the dependency for ButterKnife or the Android Support library.
But Gradle does much more than that. Despite the annoyances,
it’s a full automation tool that saves you lots of time when working on large
projects. Hence, the name “Build It Bigger”.
For this project, I had to create a joke telling app, with
functionality separated into libraries. In addition, there were also free and
paid versions that needed to share the same code base. There was even some
“cloud code” to supply the jokes.
The Implementation:
The starting code was a simple screen with a prompt and a
button to tell a joke. Nothing thrilling; just a place to begin.
 |
Starting point for this project. |
The first task was to create two libraries: one to supply
the jokes, and the other containing an activity to display the joke. Note that
because there needed to be free and paid versions, and because both versions
tell jokes, this functionality is included in separate libraries, as it’s
unchanged across builds. While the joke provider was a simple Java library, the
joke presenter was an Android library, because it contains Android-specific
components (an activity), its own resource files, and even a manifest.
At first, the joke provider library returned a hardcoded
joke, but this was only temporary. I then needed to create a GCE (Google Cloud
Endpoints) server to supply jokes in a more proper manner. After all, it would
be silly charging for an app that just contains a handful of hardcoded jokes.
The ability to add new jokes without requiring users to install updates is what
makes an app more powerful than a joke telling book.
While the assignment only required a single GET request to
download jokes, I wanted to further explore GCE. For this reason, the paid
version of the app also has access to a POST request that allows users to
upload jokes straight from the app. Free users don’t get an upload button and see
the banner advertisement instead. We only want to hear from serious jokesters,
and freeloaders are more likely to submit spam or bad jokes.
 |
Paid users can submit jokes. |
But inevitably, there will be that corny joke that nobody
likes. What can we do to ensure the quality of jokes is maintained for all the
users?
To solve this problem, I added a joke popularity system.
After viewing a joke, users would get the chance to submit an up vote or a down
vote. This is included in the activity from the joke presenting library, so
it’s available to both free and paid users. All jokes start with a popularity
of 3 and each vote is worth 1 point. Once a joke’s popularity reaches zero, it gets
permanently booted off the server.
 |
Bad jokes like this one can be voted off. |
So where does the Gradle part come in?
While all this could technically be done by hand, it would
be very tricky if you only want one Android studio project. Instead, Gradle
handles most of the difficult work in the build process. Both joke supplying
libraries are listed by Gradle as dependencies in addition to third party
libraries. The build script also defines “product flavors” allowing both the
paid and free versions to coexist on the same device. Finally, dependencies can
be filtered by their product flavor. Only the free version contains ads, so
Gradle excludes this dependency from the paid version. Similarly, only paid
users can upload jokes, so the free version has no need for the material
dialogs library. Only the paid version will include this dependency.
 |
Only free users see ads. |
The Challenges:
Compared with previous projects, this app was not
particularly complicated. However, there were a few issues encountered during
the development.
When configuring the API, I was surprised to find that
endpoint names were not those supplied to the “name” parameter of the
@ApiMethod annotation. Instead, they used the name of the Java bean the method
returned. So with the default GCE template, the “joke” method was named
“mybean”. To override this behavior, I learned it’s necessary to use the “path”
parameter. So this method
@ApiMethod(name = “getJoke”, path = “get_joke”)
public JokeResponse getJoke() { … }
Would be known as “get_joke” in the endpoint. If this
parameter were omitted, it would be known as “JokeResponse”.
There were a couple minor snags along the way, but this one
stood out the most. To get the gradient on the “tell a joke” button I used the
tool at http://angrytools.com/android/button/. Quite useful if you’re new to
Android graphics and want a simple way to learn about each of the properties.
Conclusion:
While not as code-intensive as some of the previous
projects, I like how the joke telling app turned out. Nowadays, the freemium
model appears to be more common than having separate free and paid versions,
but it’s nice to know Gradle product flavors can handle most of the difficult
work for you. And abstracting functionality into libraries is certainly
something I’ll be using a lot in the future.