A React Native cycling training app that allows cyclists to ride virtual routes with real-time sensors. Supports iOS and Android.
- Node.js 22+
- React Native development environment — follow the official setup guide
- For iOS: macOS with Xcode and CocoaPods
- For Android: Android Studio with SDK
The app has three build variants:
debug — Development build that requires Metro to be running. Supports hot reload and React Native dev tools. Best for active development.
dev — Standalone build that installs and runs without Metro. If local builds of incyclist-services or incyclist-devices are present they are used automatically, otherwise the published npm versions are used. Best for testing a complete build on a device.
release — Production build. Requires device attestation (Apple App Attest on iOS, Google Play Integrity on Android) and a running secrets microservice. Required for App Store / Play Store distribution.
For forking and sideloading, use dev or debug. Attestation is disabled in both — secrets are provided locally in settings.json instead.
For active development, check out the following repositories as siblings:
git clone https://github.com/incyclist/services.git
git clone https://github.com/incyclist/devices.git
git clone https://github.com/incyclist/mobile.gitYour directory layout should look like this:
├── services/
├── devices/
└── mobile/
When running a dev or debug build, Metro automatically picks up local builds of incyclist-services and incyclist-devices from these sibling directories if they exist. This allows you to develop and test changes across all three repos simultaneously without publishing to npm.
If you only want to work on the mobile app itself, you only need the mobile repo — the published npm versions of incyclist-services and incyclist-devices will be used.
cd mobile
npm installThis file is gitignored and must be created manually. A template is at config/config.example.json.
{
"GOOGLE_PROJECT_NUMBER": "<your Google Cloud project number>"
}This is only required for release builds. For dev and debug you can leave it empty ({}).
Create config/dev/settings.json (or config/debug/settings.json for debug builds). This file provides secrets and configuration directly to the app — no secrets microservice needed.
{
"MQ_BROKER": "mqtts://your-mqtt-broker.example.com",
"MQ_USER": "your-mqtt-username",
"MQ_PASSWORD": "your-mqtt-password",
"INCYCLIST_API_KEY": "your-api-key"
}You can add any additional key-value pairs here that your app needs, for example a uuid for uniquely identifying the user across runs.
Note:
INCYCLIST_API_KEYis required to connect to the Incyclist backend. Contact the Incyclist team to obtain a valid key. Without it, calls to the Incyclist backend will fail — but you can still run the app against your own backend.
The release build will not process the settings files as settings will be provided by the Incyclist backend after successfully performing device attestation (i.e. verifying that the app was installed through play store / app store)
cd ios && bundle install && bundle exec pod install && cd ..First start Metro:
npm start:debugThen in a separate terminal:
# Android
npm run debug:android
# iOS
npm run ios# Android
npm run dev:android
# iOS — build and run from Xcode, selecting the 'dev' schemeSee Release builds below — additional setup required.
Release builds require device attestation and a deployed secrets microservice. This is not needed for local development or sideloading.
Google Play Integrity (Android)
- Create a Google Cloud project and enable the Play Integrity API
- Link the project to your app in Google Play Console → Setup → App integrity
- Note the project number — this goes in
config/config.jsonasGOOGLE_PROJECT_NUMBER - Create a service account with Play Integrity API access, download the JSON key — required by the secrets microservice
Apple App Attest (iOS)
- Enable the App Attest capability for your App ID in the Apple Developer portal
- Note your Team ID and bundle identifier — configured on the secrets microservice as
APPLE_TEAM_IDandAPPLE_APP_ID
Secrets microservice
Deploy the secrets microservice from the incyclist/microservices repository. See that repo's README for full deployment instructions.
After deploying, seed the store with your secrets via the admin API — the secrets will then be distributed to the app after successful attestation on each device.
If you're having issues getting the above steps to work, see the React Native Troubleshooting page.