Skip to content


Hello, Hangboard: Mobile App Development with React Native

August 24, 2020
7 min read

As a product manager who recently moved from a web and publishing shop to Very, a team much more focused on apps and devices, I wanted to familiarize myself with the technologies we use. This way, I can continue to make strategic product recommendations and offer relevant guidance to my clients. So I set a goal: zero-to-app-stores with something simple. But what?

Well, it’s not revolutionary, but as I was mulling this over, the progression of COVID-19 closed my climbing gym, so I found personal a need – an interval timer for sets on my hangboard. Regardless of other apps that may be available, the fitness app I already use does not do this well.

Humble beginnings for the photo above: minimum viable product (MVP) functionality and design, packing-tape as a phone mount, and simple exercises before anything more challenging. And I think it goes without saying that we are so not telling my landlord about this.

Defining the Minimum Viable Product

First, I defined the features that would make up my MVP. The app needed to:

  • Easily run on either mobile device I own – my Pixel or Very’s loaner iPhone
  • Give audio and visual cues to progress through a set
  • Have the ability to handle the weird nested patterns of repeats I see on hangboard exercises being passed around

Here’s an example of one of those weird nested patterns:

Interval training and phone timers are good at “on” vs “off,” but not when it gets complicated. I can count it off in my head, too, but where’s the fun in that?

Professional Development Goals

This was entirely a professional development project, so what I was really aiming for was:

  • A mobile app, built on something Very is currently using
  • Cross-platform capabilities, the most common request we receive from prospective clients

My JavaScript may be a little rusty, but it’s serviceable, so I opted for React Native. React is hugely popular on the web and React Native is gaining traction quickly as a simple app development framework with the core promise of enabling cross-platform distribution of a single codebase.

Getting Started with Expo

The first page of React Native’s “Setting up the development environment” tutorial directs new developers to Expo for a quick start. Expo offers a ready-to-use bundling of tools and services with a baseline set of packages/components. Its local scripts and its SaaS platform handle all the bundling and building; no Android Studio or Xcode.

Perfect for the "Hello World" phase. // DO NOT COPY THIS! This is learning scratchwork, not best practices/patterns.
import React, { Component } from 'react';

import { Text, View } from 'react-native';

export default class HelloHangboard extends Component {

  render() {

    return (

      <View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>

        <Text style={{textAlign: "center", fontSize: 32}}>Hello, Hangboard.</Text>

        <Text style={{textAlign: "center"}}>

          I'm stuck in my apartment because of coronavirus.






Observations on Expo: Expo offers so much “for free.” It’s also upfront about the limitations. This was a fantastic way to start: limiting the number of new things I had to learn simultaneously. (Limit the work in progress, yo!) But I started running into trouble with sound.

Observations on component building: As an industry, we spent a long time highlighting the wisdom of separating concerns into separate files: HTML for content, CSS for appearance, and JS for interactive function. Bringing CSS into JS (and the multitude of conflicting practices for doing so) and using JSX templating for HTML/Content-in-JS both felt very odd, but I can learn. And I am starting to understand the arguments for it: that was (and still is, to a certain extent) for web page building, which this is not – this is application scaffolding. This model proposes consolidating “function, UI, appearance, frontend behavior” and instead opting for separation of feature as more sustainable. Well shoot, that’s how I write a backlog. That’s thin vertical slices.

Development Environments

Partly to use a replacement React Native module for better sound support and partly to play with it, I “ejected” out of Expo. I then spent longer than I’d care to admit setting up three development environments. I do a lot of development work on a Linux box, but I thought I’d see how “cross-platform” I could really get.

For iOS development, I got up and running on my Very Macbook. That was well documented and straightforward – and I already did most of it because I had a dev instance running for my first client at Very, Complex Networks, whose new project Sole Collector is also a React Native app. For Android testing and development, I got going on both the Macbook and my PC.

As Very’s seemingly lone Windows fan, I’ll admit it: many JS and web development tools have suffered poor experiences (or worse) on Windows in the past. There is a multitude of reasons for that, but I was impressed: it is a lot better than it used to be! Microsoft offers some great documentation and tools. React Native and Expo also have pretty good docs, though there are some conflicts between what they say and the installation defaults for recent versions of Android Studio.

For all three combinations in play, building locally to run on-device was actually quite easy.

Automatic Builds

I also configured automatic cross-platform builds on Bitrise, a CI/CD provider that Very uses on some projects. That was mostly simple, except for code signing on iOS, which is “easy” assuming you don’t run into trouble. Once you’ve “stepped in it” with code signing, though, I found it difficult to untangle.

Just deleting all my provisioning profiles and certificates, requesting an entirely new set from Apple Developer’s website (completely outside Xcode), and then manually importing them did the trick. But I felt a little deflated that the only time I truly felt stuck in this whole enterprise was this step, and it felt so opaque to troubleshoot.

Once configured, a push to the main branch on GitHub would kick off a job on Bitrise to build new, versioned, signed releases for both iOS and Android, and also push them up to their respective app stores.

Private Launch

The Apple App Store offers a simple way to do invite-only beta tests with TestFlight. My first build was “reviewed” and released on TestFlight within 48 hours. From there, TestFlight on my iPhone started downloading the latest builds as they came in from Bitrise.

My road to the Google Play Console was rockier because a rough draft of my app description included the word “coronavirus stay-at-home orders” (as a reason climbers may opt to train at home). This triggered a round of higher scrutiny — I had not realized that the app description field would be reviewed for an invite-only alpha. Ultimately, with revised content in that field and an appeal to Google, my alpha was released through Google Play as well. I did like that invite-only alpha and public-beta releases are handled through Google Play’s primary store app, rather than requiring something separate.

Ultimately, I found App Store Connect to more clearly explain review status and drive next steps, and while TestFlight is another app to have testers install, it’s simple. On the other hand, Google Play Console offers much more robust release multitracking tools but suffers from conflicting messaging within the user interface that can lead to confusion about review status and blockers.

Recap and Roadmap

So that was fun. Having little to do while staying-at-home made it come together a lot faster. It is still “minimum viable prototype” as an app — but that’s okay. It meets what I came for:

  • Has a usable interval timer for my own hangboard adventures — shareable with friends.
  • Gave me exposure to React Native, its fundamentals, tools, build techniques, as well as the nature, opportunities, and limitations of its cross-platform capabilities.
  • First Play Console and App Store Connect process exposure so I can help guide my clients through this exciting but intimidating part of their launches.

Good Enough, but Not “Done” Done

A rough roadmap of things that are needed, in rough priority order:

  • Being able to climb for real again…
  • This desperately needs a code review for technique and macro-level best practices. There are many competing examples and practices on how to “properly” build in this stack, but it’s all new and evolving quickly. Even within React Native’s own documentation, there are big discrepancies.
  • After a review for “do I know what I’m doing,” I need to lint this code for its micro-level structure and syntactical transgressions, which I assume are many.
  • I should learn more about functional exports versus classes, why object-oriented structures seem to have fallen out of favor, and more sustainable (DRY) ways to handle CSS-in-JS.
  • And if I ever get it in my head to release this publicly, it needs better design and more circuits/content.

React Native did get me from “I wonder what it would be like to build a mobile app” to having a compiled app running on both major platforms on physical devices in my hands in record time. I can definitely see why this approach has gained traction so quickly when it’s well-suited. The intimidating part was the number of moving pieces through many levels of abstraction, but the community is active and documentation is evolving quickly to help with that.

Meanwhile, I’ve got my strength trainer hanging over the stairs and two phones to holler at me to use it every day (well, maybe just “often”). That might be it for a while.

Stay healthy, folks. We’ll be back together one day. I’m looking forward to it.