How We Ship Match Breakdowns

The last week of build season can be a stressful time for teams. There’s a lot of loose ends to finish up! We’re the same way here at The Blue Alliance. We make make it seem effortless, but the end of build season (or, as we see it, the week before competition season) is a pretty busy time for us as well. We’re busy training computer vision models for GameDay CV, supporting avatars for the new season, all while supporting existing features and adding new features.

One of these season-specific updates that have to happen every year is updating our Match breakdown and Event insights views. In recent years, FIRST provided us detailed breakdown information about how points were scored during a match. We visualize this data on our website and in our mobile apps, as well as surface this data via our API.

Screen Shot 2019-02-19 at 6.52.06 PM.png
Breakdown data for a 2018/Power Up match

As mentioned, we surface this data in our mobile apps. The Android app ships an update every year to add a new view to the app to support the new breakdown. This approach can be problematic on mobile – especially on iOS. The turnaround time between figuring out what the match breakdown data will look like and matches being played can be extremely short (this year it was ~24 hours) – too short to build a new screen, ship to the App Store, and wait for our update to get reviewed and start propagating to users.

Additionally, mobile is different than the web, in that updates on mobile are usually opt-in. If we build the new match breakdown views on the web, all users will get the new match breakdown views. If we ship an update to our mobile apps with new match breakdown views, we rely on users to update their apps in order to get the new breakdown views. Most users auto-update their apps nowadays, but not all users do, and we can build a great experience to support those users.

On iOS, we’re pioneering using Facebook’s React Native to ship match breakdown views to clients over-the-air (OTA). This allows us to build/update match breakdown views quickly and ship to users instantly, without needing to go through App Store review, and without needing users to update their apps.

Header

There’s a few moving parts in our React Native setup. The view itself is a dummy view controller on iOS that wraps a dynamic React Native view. The dummy view will only show for years that have match breakdown information (2015 and onward). One we know to show the view, we attempt to dynamically load the match breakdown view for the match’s year.

Once we have our match breakdown view loaded, we need to give it some data to show! In order to keep things flexible, the React Native views expect to get a dictionary (a data type where a key refers to a value, for non-programmers) of arbitrary data. For our app, we use the match breakdown data from a Match model from our API.

Screen Shot 2019-02-22 at 12.48.21 PM.png
What our 2015 Match breakdown model looks like – each alliance has one of these objects

Note: At this point, the native app doesn’t care what this data looks like, or what the data is. Only that the data exists for this match. Keeping the native app agnostic of any of this logic and offloading it to our dynamic React Native views means we don’t need to update the native app to update or add a new match breakdown for a new season. Adding new match breakdown views and event insight views happens in a totally different repo, outside of the iOS app. This is especially important in the situation where we make a mistake and want to ship an update quickly.

Finally, our React Native view will figure out how to display the information we give to it. Usually this means creating some rows, comparing some values to show an icon, etc. We’re able to write JSX for these views, which means we can write JavaScript to implement any logic we might need inside the React Native views.

Finally, there’s the issue of making sure we can ship updates to these views, and our native app can download updates to these views. Our React Native repo will automatically publish a zip file of the compressed views (you know how we love CI/CD) to Firebase Storage.

Screen Shot 2019-02-22 at 1.11.01 PM.png
Our compressed React Native bundle in Firebase Storage – uploaded automatically by our CI server

When the iOS app launches (or periodically – every 15 minutes, to be exact), it will check to see if the compiled bundle in Firebase is different then the bundle it last downloaded. If the new bundle is different, it will download the new bundle, unzip the files, delete the compressed bundle, and record the latest version it downloaded. In fact, you can see the upload time and version of the React Native bundle you’re using in your iOS app in Settings!

IMG_1247.jpg
You can see our TBA RN bundle was uploaded to Firebase on February 19th at 6:45pm

For any iOS engineers out there – we also pull in the latest version of our React Native code in to the iOS repo via a git subtree, and have a build phase that will compile our React Native bundle to ship with a release binary. This is important so users that download your app from the App Store that may launch the app for the first time when they don’t have an internet connection can use your app without having to download anything (which is a very real use case for us, since events tend to have spotty cell service).

And there we have it! From start to finish how we ship match breakdown and event insight views to our iOS quickly and over the air, without forcing users to download an app update. We’re really happy with how this turned out, and we’re excited to use our learnings from this experiment in other places.

The Blue Alliance is an open-source project built by volunteers who write code for our websiteAndroid app, and iOS app; as well as mods who help us keep all our data accurate. Come help us build the future of FRC!

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s