MMashDiv

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.

8 min readUpdated 26 September 2026mobile, install, flutter, android, ios, first-run

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-licenses

The 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

  1. Unpack the zip and open a terminal in the project folder, bicrypto_v<version>/. Every command on this page runs from there.

  2. Check Flutter before anything else, because a version below 3.38 fails later and less clearly.

    flutter --version
    flutter doctor
  3. 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.json to app_config.json and edit the copy, never the example.

  4. Fetch the dependencies. This also writes android/local.properties and ios/Flutter/Generated.xcconfig, which the Android and iOS builds need.

    flutter pub get
  5. 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.xcworkspace in Xcode, not the .xcodeproj.

  6. 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
  7. 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 run makes 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 --release

The 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 --explain

If 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 --version reports 3.38 or newer
  • assets/config/app_config.json holds your baseUrl, wsBaseUrl and appName
  • dart run tool/apply_app_config.dart --check passes
  • 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 install ran, and you open ios/Runner.xcworkspace

Where next

Branding

Name, store identifiers, colours and icon, all from one file.

App configuration

Every other key in app_config.json, and what the app does when one is wrong.

Build for Android

Upload key, APK or AAB, version numbers and the first Play upload.

Build for iOS

Pods, signing team, bundle id, archive and TestFlight.

Push notifications

Firebase on both platforms, and the server half.

Publishing obligations

Accounts, licences and keys that must be yours before you submit.