Install and run the app
The Flutter, Android SDK, JDK and Xcode versions the project needs, what is in the download, the three settings a first run needs, running it on an emulator or phone, and your first release build.
The app arrives as Flutter source code, not as a finished app. Installing it means four things: put the right toolchain on your machine, tell the app where your server is, run it once on an emulator or a phone, and make one release build to prove the chain works end to end. Branding, signing and store upload come after that, on their own pages.
Nothing here touches your server. The app talks to an existing Bicrypto v5 install over its public address, the same one your customers use in a browser.
What you need
These come from the project's own files, not from a guess. Where a file sets the value, it is named, so you can check your own copy.
| Tool | Version | Where it is set, and why |
|---|---|---|
| Flutter (stable channel) | 3.38 or newer, which brings Dart 3.10 or newer | pubspec.lock ends with dart: ">=3.10.0 <4.0.0" and flutter: ">=3.38.0". The sdk: ^3.5.0 line in pubspec.yaml is not the real floor: the package versions the project is locked to need 3.38. |
| Android SDK Platform | API 36 | compileSdk = 36 and targetSdk = 36 in android/app/build.gradle.kts. Pinned because Google Play requires target API 36 for new apps and updates from 31 August 2026. |
| Android NDK | 27.0.12077973, exactly | ndkVersion in android/app/build.gradle.kts. |
| JDK | 17 or newer, but not newer than Gradle 8.14.3 can run on | Runs Gradle and the Android Gradle Plugin, which needs 17. The project itself compiles to Java 11. Flutter uses the JDK bundled with Android Studio when it finds one, which is the simplest choice. |
| Gradle, Android Gradle Plugin, Kotlin | 8.14.3, 8.11.1, 2.2.20 | The Gradle wrapper and android/settings.gradle.kts. The wrapper downloads Gradle by itself. |
| Memory for Gradle | The daemon asks for an 8 GB heap | org.gradle.jvmargs=-Xmx8G ... in android/gradle.properties. On a smaller machine, lower -Xmx. |
| A Mac with Xcode (iOS only) | A current Xcode | iOS apps build only on macOS. The project pins no Xcode version; Apple sets the minimum Xcode that App Store Connect accepts for uploads and raises it over time. |
| CocoaPods (iOS only) | 1.x | The template was last resolved with CocoaPods 1.16.2. |
The app runs on Android 7.0 (API 24) or newer (minSdk = 24) and iOS
13.0 or newer (the Xcode project's deployment target). Both are pinned, so
two operators on two Flutter versions ship the same floor.
In Android Studio's SDK Manager, install Android SDK Platform 36, NDK (Side by side) 27.0.12077973 and Android SDK Command-line Tools, then accept the licences. Flutter needs the command-line tools for the licence command below and for a check it runs on every release App Bundle.
flutter doctor --android-licensesThe platform and the NDK are pinned on purpose. A machine that lacks them does not quietly build against a different version: if Gradle cannot get the exact package, the build stops and names it.
The package also contains web/, windows/, linux/ and macos/ folders.
They came with the Flutter project template and are not supported targets.
The app is built and tested for the two phone platforms only.
What is in the download
The zip holds two things side by side: the project folder,
bicrypto_v<version>/ (for example bicrypto_v5.3.9/), and
INSTALLATION_GUIDE.html.
Inside the project folder, the parts you will touch are:
| Path | What it is |
|---|---|
assets/config/app_config.json |
Your configuration. The package ships it as a copy of the example, pointing at a placeholder address. |
assets/config/app_config.example.json |
The template the file above was copied from. Leave it alone; the app falls back to it if your file goes missing. |
assets/icons/app_icon.png |
The source of the app icon. It ships as a short text placeholder, not an image, until you replace it. See Branding. |
tool/ |
apply_app_config.dart, release_preflight.dart and ios_app_identity.dart. The iOS build runs the last one, so keep tool/ in the project. |
setup/ |
The interactive installers and the older text guides. |
run_tests.sh, test/ |
The test suite. |
Some things are deliberately not in it, and your machine creates them:
ios/Pods/, ios/Podfile.lock, android/local.properties and
ios/Flutter/Generated.xcconfig. flutter pub get and pod install write
them on your first run. There is no .git folder and no top-level
.gitignore. If you keep the project in git, ignore
assets/config/app_config.json, android/key.properties, your keystore,
android/app/google-services.json and ios/Runner/GoogleService-Info.plist
before your first commit. Each of those is yours alone.
You do not need to run code generation. Its output ships with the source, so a
fresh copy builds without build_runner. Run
dart run build_runner build --delete-conflicting-outputs only if you change
a model class yourself.
Before you start
- Flutter 3.38 or newer on the stable channel (
flutter --version) - Android SDK Platform 36, NDK 27.0.12077973 and the Android SDK Command-line Tools installed, licences accepted
- For iOS: a Mac with Xcode and CocoaPods
- Your Bicrypto v5 site reachable over
https://, with WebSockets passing through on/api - A test account on that site that can sign in (email verified)
- An Android emulator, an iOS Simulator, or a phone with developer mode on
Steps
-
Unpack the zip and open a terminal in the project folder,
bicrypto_v<version>/. Every command on this page runs from there. -
Check Flutter before anything else, because a version below 3.38 fails later and less clearly.
flutter --version flutter doctor -
Point the app at your server. Open
assets/config/app_config.json. It already exists: the package ships it as a copy of the example, with placeholder values. Change three values and leave the rest for now:{ "baseUrl": "https://exchange.example.com", "wsBaseUrl": "wss://exchange.example.com", "appName": "Example Exchange" }The table below says what each one must be. If the file is missing, copy
app_config.example.jsontoapp_config.jsonand edit the copy, never the example. -
Fetch the dependencies. This also writes
android/local.propertiesandios/Flutter/Generated.xcconfig, which the Android and iOS builds need.flutter pub get -
iOS only: install the pods. Always after
flutter pub get, never before; the Podfile reads the file that step writes.cd ios pod install cd ..From now on, open
ios/Runner.xcworkspacein Xcode, not the.xcodeproj. -
Check the configuration. This changes nothing. It prints what each platform will use, and exits with an error when a value is invalid.
dart run tool/apply_app_config.dart --check -
Run it. List the devices Flutter can see, then run on one:
flutter devices flutter run -d <device-id>The first build takes several minutes.
flutter runmakes a debug build.
The three settings
| Key | What to put there | Why |
|---|---|---|
baseUrl |
The address your customers open in a browser, such as https://exchange.example.com. No /api on the end, because the app adds it. A trailing / is removed for you. |
Every request goes to this host: the API under /api/..., coin images under /img/crypto/..., and uploaded files such as avatars under /uploads/.... It has to be the host that answers all three, which is your site's public address. |
wsBaseUrl |
The same host with wss://, such as wss://exchange.example.com |
The app opens its live connections under /api/... on this host, for example /api/exchange/ticker for prices. Your web server must pass WebSocket upgrades on /api through. See Apache or Nginx and reverse proxy. |
appName |
Your app's name, on one line | The name inside the app and under the icon on both platforms. It is applied when the app is built. Left out or blank, it is BiCrypto. A tab or line break in it stops the build. |
baseUrl and wsBaseUrl have no default. Leave either one out, or blank, and
the app does not start: it opens on a Configuration Error screen naming the
missing key. The other keys are optional, and
App configuration covers them.
A file that is not valid JSON, such as one with a comma after the last entry,
does not get as far as the app. The Android build stops with
assets/config/app_config.json is not valid JSON (at line 4 column 2) and a
hint, and the iOS build phase stops on it too, naming the file. The app itself
would refuse the file, so the build refuses it first.
Testing against a server on your own computer
A debug build on the Android emulator can reach a backend running on your
computer through 10.0.2.2, the emulator's name for the machine it runs on:
{
"baseUrl": "http://10.0.2.2:4000",
"wsBaseUrl": "ws://10.0.2.2:4000"
}10.0.2.2 exists only inside the Android emulator. A physical phone cannot
use it; point a phone at an https:// address it can reach, such as a staging
copy of your site.
Only a debug or profile build accepts http:// and ws://. A
release build refuses a baseUrl that is not https:// or a wsBaseUrl that
is not wss://, and opens on the Configuration Error screen instead, with the
key and the value in the box:
… sets "baseUrl" to "http://10.0.2.2:4000", which is not a https:// address, and this is a release build.
Sign-in tokens travel with every request, and nothing in Android or iOS stops
the app sending them unencrypted, so the app checks this itself.
flutter build does not know about this rule, so a release build with an
http:// address still builds and then stops on its first screen.
dart run tool/apply_app_config.dart --check --release and the release
preflight both report it before you build.
Configuration changes need a new build
app_config.json is packed into the app when it is built, and parts of it are
applied only by the build itself: the name under the icon and the Android
application ID. After you edit it, stop the app and run it again rather than
hot-restarting. A hot restart in particular does not pick up a config file that
was missing from the last build. You do not need flutter clean.
What a working first run looks like
The app opens on the sign-in screen. There is no guest mode: apart from the sign-in, registration and password-reset screens, everything in the app needs an account. Before anyone signs in, the app has already fetched your market list and opened the price connection, so a problem with either one shows up straight away.
Sign in with your test account. The home screen should show your markets with live prices. Home, Market, Trade and Wallet are always in the bottom bar; the Futures tab and the tiles in the Trading Tools row on Home appear only for the modules your server offers this account. That is decided by your server, not by the build, apart from three restricted modules that also need a build flag; see Which screens the app shows.
You can check the first request from a desktop without the app. It must answer 200 with a JSON array:
curl -H "platform: mobile" "https://exchange.example.com/api/exchange/market?eco=true"When it does not connect
| What you see | What it usually means |
|---|---|
| A Configuration Error screen, and the box on it names a key | A required key is missing or blank, a value has the wrong form, or a release build has an http:// or ws:// address. Fix the key it names, stop the app and build again. |
| Every screen fails, but no error screen appears | The app is still on the placeholder address https://your-backend-url.com. Either you edited the example instead of app_config.json, or the app was built before your edit. |
| No internet connection while the phone is online | baseUrl points at a host the phone cannot reach: a typo, a firewall, or an address that only exists on your network. A firewall that silently drops the connection shows Connection timeout instead. |
| A banner saying Unable to connect to server. Using offline mode. | The market list could not be fetched when the app started. Same causes as above. |
| Unexpected error occurred on every request | If the address is right, check the certificate. The app accepts no self-signed, expired or wrong-host certificate, and a failed TLS handshake is reported this way rather than as a connection problem. The curl check above, run without -k, shows the same complaint. See Domains and SSL. |
More symptoms and their fixes are on Troubleshooting.
setup/installers/install.sh (macOS and Linux) and setup/installers/install.bat
(Windows) ask for the same values interactively and write app_config.json
for you. This page does it by hand so that you know what each step did. See
Build and tools reference.
Your first release build
Make one release build now, before any branding, to prove the toolchain. Android is the quicker proof:
flutter build apk --releaseThe APK lands at build/app/outputs/flutter-apk/app-release.apk. Copy it to a
phone and install it.
Until you create android/key.properties, a release build is signed with
the Android SDK's debug key. It installs and runs, and Google Play refuses it.
There is a second catch: a phone holding a debug-signed copy will not accept
your properly signed build as an update, because the signatures differ.
Uninstall the test copy first. Build for Android
sets up the real key.
Before any build you intend to publish, run the preflight. It fails, and lists
why, while the project still carries the template's name, identifiers, colours
or icon, has no release signing key, has an http:// or ws:// backend
address, or names no Apple signing team for iOS. It checks the project; it
does not stop flutter build by itself, so run it yourself:
dart run tool/release_preflight.dart --explainIf you publish on Android only, add --android-only. It skips the iOS checks,
the signing team among them, and still runs every Android one.
Before you move on
-
flutter --versionreports 3.38 or newer -
assets/config/app_config.jsonholds yourbaseUrl,wsBaseUrlandappName -
dart run tool/apply_app_config.dart --checkpasses - The app reached the sign-in screen and your test account signed in
- The market list shows your markets with live prices
- A release APK built, installed and opened
- For iOS:
pod installran, and you openios/Runner.xcworkspace
Where next
Name, store identifiers, colours and icon, all from one file.
Every other key in app_config.json, and what the app does when one is wrong.
Upload key, APK or AAB, version numbers and the first Play upload.
Pods, signing team, bundle id, archive and TestFlight.
Firebase on both platforms, and the server half.
Accounts, licences and keys that must be yours before you submit.