Today we're releasing the source
code for the official href="https://play.google.com/store/apps/details?id=com.google.samples.apps.iosched&hl=en">Google
I/O 2017 for Android app.
This year's app substantially modifies existing functionality and adds several
new features. It also expands the tech stack to use href="https://firebase.google.com/?utm_source=google&utm_medium=cpc&utm_campaign=1001467%20%7C%20Firebase*%20Brand%20GENERIC%20%7C%20US%20%7C%20en%20%7C%20Desk%2BTab%2BMobile%20%7C%20Text%20%7C%20BKWS%20%5B2017%5D&utm_term=%7Bkeyword%7D&gclid=Cj0KCQjwq7XMBRCDARIsAKVI5Qais3r2YPsnohDN1mzomMUFysiwEJJ5W2V-LfRO_0btHf5SAfMmp5caAofLEALw_wcB">Firebase.
In this post, we'll highlight several notable changes to the app as well as
their design considerations.
The most prominent new feature for 2017 is the event
reservation system, designed to help save in-person attendees'
time and provide a streamlined conference experience. Registered attendees could
reserve sessions and join waitlists prior to and during the conference; a
reservation provided expedited entry to sessions without having to wait in long
lines. Reservation data was synced with attendees' conference badges, allowing
event staff to verify reservations using NFC-enabled phones. Not only was the
reservation feature incredibly popular, but the reservation data helped event
staff change the size of session rooms both before and during I/O to adjust for
actual demand for seats.
The reservation feature was implemented using href="https://firebase.google.com/products/database/">Firebase Realtime
Database (RTDB) and href="https://firebase.google.com/products/functions/">Cloud Functions for
Firebase. RTDB provided easy sync across user devices — we just had to
implement a listener in our code to receive database updates. RTDB also provided
out-of-the-box offline support, allowing conference data to be available even in
the face of intermittent network connectivity while traveling. A Cloud Function
processed reservation requests in the background for the user, using
transactions to ensure correctness of state (preventing mischievous users from
grabbing too many seats!) and communicating with the event badging system.
As in previous years, we used a ContentProvider as an abstraction layer over all
app data, which meant we had to figure out how to integrate RTDB data with the
ContentProvider. We needed to negotiate between having two local caches for
data: 1) the extant local SQLite database accessed via the ContentProvider, and
2) the local cache created by RTDB to facilitate offline access. We decided to
integrate all app data under the ContentProvider: whenever reservation data for
the user changed in RTDB, we updated the ContentProvider, making it the single
source of truth for app data at all times. This meant that we needed to keep
open connections to RTDB only on a single screen, the Session Detail Activity,
where users might be actively managing their reservations. Reservation data
displayed in other parts of the app was backed by the ContentProvider. In
offline mode, or in case of a flaky or delayed connection to RTDB, we could just
get the last known state of the user's reservations from the ContentProvider.
We also had to figure out good patterns for integrating RTDB into the overall
sync logic of IOSched, especially since RTDB comes with a very different sync
model than the ping-and-fetch approach we were using in the app. We decided to
continue using Cloud Endpoints
to synchronize user data across devices and with the web and iOS clients (the
data itself was stored in href="https://cloud.google.com/appengine/docs/standard/java/datastore/">Datastore).
While RTDB provides out-of-the-box data syncing, we wanted to make sure that a
user's reservation data was current across all devices, even when the app
was not in the foreground. We used a Cloud Function to integrate RTDB
reservation data into the sync flow: once reservation data for a user changed in
RTDB, the function updated the endpoint, which triggered a href="https://firebase.google.com/products/cloud-messaging/">Firebase Cloud
Messaging downstream message to all the user's devices, which then scheduled
data syncs.
This year's app also featured a Feed to apprise users about
hour-by-hour developments at I/O (most of the app's users were remote, and the
Feed was a window into the conference for them). The Feed was also powered by
RTDB, with data pushed to the server using a simple CMS. We used a Cloud
Function to monitor RTDB feed data; when feed data was updated on the server,
the Function sent a Cloud Messaging downstream message to clients, which
visually surfaced the presence of new feed items to the user.
In 2015 and 2016, we had adopted an MVP architecture for IOSched, and we
continued using that this year. This architecture provides us with good
separation of concerns, facilitates testing, and in general makes our code
cleaner and easier to maintain. For the Feed feature, we decided to experiment
with a more lightweight MVP implementation inspired by href="https://github.com/googlesamples/android-architecture">Android
Architecture Blueprints, which provided the necessary modularity while being
very easy to conceptualize. The goal here was both pedagogical and practical: we
wanted to showcase an alternate MVP pattern for developers; we also wanted to
showcase an architecture that was an appropriate fit for our needs for this
feature.
For the first time, IOSched made heavy use of href="https://firebase.google.com/docs/remote-config/">Firebase Remote
Config. In the past, we had found ourselves unable to inform users when
non-session data - wifi information, shuttle schedule, discount codes for
ridesharing, etc. - changed just before or during the conference. Forcing an app
update was not feasible; we just wanted in-app default values to be updatable.
Using remote config easily solved this problem for us.
In the end, we ended up with a three-tier system of informing users about
changes:
- Conference data and user data changes were communicated via Cloud Messaging
and data syncs (ping and fetch model). - Feed data changes were controlled via RTDB.
- Changes to in-app constants were controlled via Remote Config.
Future plans
Even though we're releasing the 2017 code, we still have work ahead of us for
the coming months. We'll be updating the code to follow modern patterns for
background processing (and making our app "O" compliant), and in the future
we'll be adopting Android's href="https://developer.android.com/topic/libraries/architecture/index.html">Architecture
Components to simplify the overall design of the app. Developers can follow
changes to the code on GitHub.
0 comments