Bicrypto Mobile App 5.4.0
Latest26 September 2026
This release has upgrade notes. Read them before updating — they describe behaviour changes that need your attention.
Mobile App v5.4.0
Release Date: September 26, 2026 Tags: BRANDING, CONFIGURATION, BUILD TOOLS, SESSIONS, TWO-FACTOR, P2P, COIN LOGOS, PASSWORD RESET, GOOGLE SIGN-IN, PUSH NOTIFICATIONS, E-COMMERCE, SECURITY
Overview
The mobile app is the Flutter client for your platform, sold as source: you configure it against your own server, brand it, build it and publish it under your own Apple and Google accounts. This is its first release note — everything below is measured against 5.3.9.
Your app's name, Android and iOS identifiers and brand colours now come from one file, assets/config/app_config.json, and the name reaches the home screen on both platforms. Before, appName changed only the name inside the app. If you edited any of these by hand in an earlier release, move them into that file before you build this one — Upgrade Notes says how, and skipping it can build your update as a different Android app.
Password reset, Google sign-in and push notifications work in the app on a default server. "Forgot Password?" and Change Password were refused under the built-in proof-of-work captcha, every Google sign-in failed, and pushes reached nobody who had not found the Push Notifications switch. All three are fixed, and the sign-in code screen now takes recovery codes.
A mistyped code no longer signs anyone out. A wrong escrow-release code, withdrawal code, Transfer PIN or password used to end the whole session. Release builds now also refuse an http:// or ws:// server address.
Update Instructions
A new release arrives as a new download, not as an update to your copy. It has no version-control history to merge with, and its assets/config/app_config.json is a copy of the example that points at a placeholder address — so do not copy it over your tree, and do not build it as it comes.
-
Unpack the new release into a fresh folder, next to your current one.
-
Carry your own files into it:
assets/config/app_config.jsonassets/icons/app_icon.pngandroid/key.properties— and check that the keystore path in it still points at your upload keystoreandroid/app/google-services.json, if you use pushios/Runner/GoogleService-Info.plist, if you use push
-
Re-apply any changes you made to the app's own code by hand.
-
Run, from the new folder:
flutter pub get dart run tool/apply_app_config.dart dart run tool/apply_app_config.dart --icons -
On iOS, in Xcode: add the Push Notifications capability again if you use push, and any Google sign-in entries you had added to
ios/Runner/Info.plist— the project ships without either. Choose your signing team there too, unless you setiosTeamId. -
Set the build number in
pubspec.yamlhigher than the last one you uploaded. This release carries our ownversion:line, and both stores refuse a build number they have already received. -
Run the preflight, then build and upload as usual. Add
--android-onlyif you do not publish on the App Store:dart run tool/release_preflight.dart --explain
This release changes nothing on your server. See Build for Android and Build for iOS for the build and upload steps.
Upgrade Notes
Move a hand-edited name, ID or colour into app_config.json first
Earlier releases kept the home-screen name in AndroidManifest.xml and Info.plist, the Android ID in android/app/build.gradle.kts, the iOS bundle ID in the Xcode project and the colours in lib/core/theme/app_themes.dart. This release reads the name, the Android ID and the colours from assets/config/app_config.json and ignores those places. The iOS bundle ID still lives in the Xcode project, but dart run tool/apply_app_config.dart writes it there from iosBundleId.
- Put your name in
appName, your Android ID (theapplicationIdline of your oldbuild.gradle.kts) inandroidApplicationId, your iOS bundle ID iniosBundleId, and any colours you changed inprimaryColor,buyColor,sellColorandaccentColor. - Do not skip
androidApplicationId. Without it the update builds ascom.bicrypto.mobile, which is a different app from the one your users have installed, and Google Play will not accept it for your listing. - Keep this release's
android/app/build.gradle.kts,android/app/src/main/AndroidManifest.xmlandios/Runner.xcodeprojtogether. An olderbuild.gradle.ktswith the new manifest fails every Android build withManifest merger failed ... no value for <appName> is provided; an older manifest or Xcode project puts the old name back on the home screen. - Set
iosBundleIdtoo if you publish on iOS. This release's Xcode project carries the template's bundle ID,com.bicryptto.mobile, and an emptyiosBundleId— as the example ships it — means "keep whatever the project has". Put your ID iniosBundleIdand rundart run tool/apply_app_config.dartbefore you build; the preflight refuses a build still under the template's ID. - With none of the new keys set, a build comes out exactly as before: named BiCrypto, under
com.bicrypto.mobile, the Xcode project's own bundle ID, and the same colours. The preflight refuses that for a release.
Every key is described in Make it your app.
Release builds need https:// and wss://
A release build whose baseUrl is not https://, or whose wsBaseUrl is not wss://, opens on the Configuration Error screen instead of starting, and the message there names the key and the address. The sign-in token travels with every request, and Flutter's networking does not apply Android's or iOS's own cleartext rules, so the app enforces this itself. Debug and profile builds still accept http:// and ws:// for testing against a server on your own computer or network.
- Check before you build with
dart run tool/apply_app_config.dart --check --release. The preflight reports the same addresses asbackend-not-encrypted. - The installers still accept an
http://orws://address for a local test backend, but warn about it and will not start a release build until both addresses are encrypted.
Your own iOS signing team
The Xcode project no longer carries our signing team, or any team: this release ships with none. Put your 10-character Apple Team ID in the new optional key iosTeamId and run dart run tool/apply_app_config.dart, which writes it into the Runner target's Debug, Release and Profile configurations; or choose your team in Xcode under the Runner target → Signing & Capabilities.
iosTeamIdmust be exactly 10 upper-case letters and digits. The installers write it as"", which leaves the project's team alone.- The preflight reports
ios-teamfor a project that still carries the team older releases shipped with,52K7QMD7KR, or that names no team for Release, andios-team-mismatchfor a project whose team differs from a setiosTeamId. - If you publish only on Google Play, run the preflight with
--android-only. It skips every iOS check, so the missing team does not fail an Android release.
On your first iOS build of this release, check that the Apply app_config.json phase ran — see Build for iOS. The iOS build phase has been exercised in tests but not yet on a Mac build — report anything unexpected.
Google sign-in and googleAuthEnabled
- With
googleAuthEnabledabsent, Continue with Google now shows only whengoogleServerClientIdis set. An explicittrueorfalseis still obeyed, and the example file setsfalse. - On Android the client ID can come from
google-services.jsoninstead ofgoogleServerClientId. If you rely on that and leavegoogleServerClientIdempty, set"googleAuthEnabled": true, or the button disappears. - No Google sign-in completed in 5.3.9 or earlier. If you offered the button, sign in with a linked Google account on a test build before you publish this one.
Old configuration keys are ignored
Older configuration files may still contain recaptchaEnabled, recaptchaSiteKey, walletAuthEnabled, walletConnectProjectId, twoFactorEnabled, twoFactorSmsEnabled, twoFactorEmailEnabled, twoFactorAppEnabled, emailVerificationEnabled, defaultShowComingSoon, backgroundUpdateInterval, and cryptoCompareApiKey, which older installers wrote. None of them changes anything, and a file that carries them loads as before; you can delete the lines. Captcha, two-factor methods and email verification are decided by your server's own settings, which modules appear by your server's module settings, and news comes from your server.
Compatibility
- Installed copies of 5.3.9 keep working against your server. The app and the server update separately.
- Push to app users who never touched the Push Notifications switch needs Core 6.6.3 or later, whose device registry switches push on for them. On an older core, pushes still wait for that switch.
- Coin logos are loaded from your server: the icon it names for a coin, or the standard file under
<baseUrl>/img/crypto/. WhenbaseUrlis your website's own address — the usual layout, with the backend under/api— that address answers. AbaseUrlnaming a host that forwards only/apito the backend shows a letter in place of every logo. Open<baseUrl>/img/crypto/btc.webpin a browser to check: it must show the Bitcoin logo. - Delivered and read ticks in P2P trade chat appear only when your P2P server reports message receipts. On one that does not, stored messages carry no ticks.
Added
Name, identifiers and colours from one file
- Added
appName,androidApplicationId,iosBundleId,primaryColor,buyColor,sellColorandaccentColortoassets/config/app_config.json.appNameis the name inside the app and under the icon on Android and iOS; Gradle reads it andandroidApplicationIdon every Android build, and a new Apply app_config.json build phase applies the name on every iOS build. - Added
iosTeamId, the Apple signing teamdart run tool/apply_app_config.dartwrites into the Xcode project. - A colour is
#RRGGBBor#AARRGGBB, and an empty value means the default. Any other value stops the app on the Configuration Error screen naming the key. - Buy and sell, and prices up and down, follow
buyColorandsellColor. Errors stay red and success marks stay green whatever those two are set to, and text on primary-coloured buttons switches to dark on a very light primary. - An iOS build whose Xcode project disagrees with a set
iosBundleIdstops, with the fix in the message.
Tools that apply and check the configuration
- Added
dart run tool/apply_app_config.dart. It checks the whole configuration file, writesiosBundleIdandiosTeamIdinto the Xcode project, and with--iconsregenerates the Android and iOS icons fromassets/icons/app_icon.png. With--checkit changes nothing and only reports; with--releaseit also treats anhttp://orws://address as an error rather than a warning. - Added
dart tool/ios_app_identity.dart --dry-run, which shows what the iOS build phase will apply without running Xcode, so it also works on Windows and Linux. - Added three preflight findings —
ios-team,ios-team-mismatchandbackend-not-encrypted— and the--android-onlyflag, which skips the iOS checks and runs every Android one.
Recovery codes at sign-in
- Added a Can't get a code? Use a recovery code link to the sign-in code screen. It opens a Recovery code field that takes the code with or without its dashes, and Use a verification code instead goes back to the six boxes. Before, a customer without their second factor could not sign in to the app at all.
P2P trade chat shows how far each message got
- Added a status on your own messages: a clock while sending, then sent, delivered and read. A message that could not be sent is marked, and tapping it sends it again.
- Messages from support are drawn as a card of their own, so an instruction from your team cannot be mistaken for something the other trader typed.
- An open chat refreshes every ten seconds while it is on screen and the app is in front. A message that has not gone through yet stays where it was typed, and messages that arrive after it appear below it.
A notice when the session ends
- Added a one-time notice on the sign-in screen when the server ends a session: "Your session has ended. Please sign in again." When the server says why — for example after too many incorrect confirmation codes — its own sentence is shown instead. A sign-out the customer chose shows nothing.
Changed
The release preflight and the installers use the one file
- Changed
dart run tool/release_preflight.dartto read the name, identifiers and colours fromapp_config.json, the same file the build takes them from. It still refuses a build that carries the template's name, identifiers, colours or icon, and it names any Android or iOS project file that is still from an older release. - Changed the installers to ask for the four colours as well, write every answer into
app_config.json, and apply it from there withdart run tool/apply_app_config.dart. They no longer editAndroidManifest.xmlorInfo.plist. - Changed the installers to stop asking the Coming Soon and CryptoCompare questions and to stop writing the keys that did nothing. They write
"iosTeamId": "", and leavegoogleAuthEnabledout so that it followsgoogleServerClientId. - Changed
run_tests.shto run thetest/toolsuites as well.
Notification permission is asked once
The app used to ask the phone for notification permission at every sign-in and every start with a saved sign-in, and the in-app notification service asked again on its own.
- Changed so that, after the first sign-in on an install and only when the phone does not already allow notifications, the app shows a Stay informed sheet saying what it notifies about, and the phone's prompt follows only if the customer goes on. Android offers Turn on notifications and Not now; iOS shows one Continue button, because the iOS prompt that follows has its own Don't Allow. The answer is recorded and the app does not raise the subject by itself again on that install.
The in-app logo is your icon
- Changed the logo drawn inside the app to use
assets/icons/app_icon.png, the image your launcher icons are made from. It used to point at a file no build included, so every build showed the fallback.
Coin logos follow the website's file names
- Changed coin logos to try the icon your server names first and then the standard file for the coin, spelled the way the website spells it. Coins whose symbols carry a dot or other punctuation now show the same logo as on the website instead of a letter.
Fixed
A wrong code or PIN signed the customer out
Every HTTP 401 outside the sign-in screens was treated as an ended session. The server also answers a wrong confirmation code, a wrong Transfer PIN or a wrong password that way, so a seller who mistyped one digit of an escrow-release code was signed out, the dialog vanished, and getting back to the trade took a full sign-in. Withdrawals and transfers behaved the same.
- Fixed so that only a refusal that means the session has ended signs the customer out. A wrong code is shown where it was typed.
The escrow-release and withdrawal code dialogs
- Fixed the P2P escrow-release code dialog so a wrong code keeps it open, shows the server's message about attempts left or how long to wait, empties the field and gives the keyboard back. A refusal that arrived inside a successful response used to read as "The code was accepted but no release token came back."
- Fixed the withdrawal code dialog the same way: a refused code empties the field and gives the keyboard back, while a failed resend leaves what was typed in place.
- Fixed P2P chat reporting "No messages yet" when the server refused to read the conversation, and a message sent to a completed trade vanishing without a word. Both now show the server's reason.
Password reset was refused under the default captcha
Your server checks a captcha on the password-reset request as well as on sign-up, and its default captcha is the built-in proof-of-work. The app solved that challenge only at sign-up, so "Forgot Password?" — and Change Password, which uses the same screen — failed with "Security verification failed. Please try again." on a default server.
- Fixed so that the app fetches a reset challenge from your server and solves it before sending the reset, as it does at sign-up. With the captcha set to proof-of-work or none, both work in the app.
- Fixed sign-up and password reset under Turnstile, reCAPTCHA or hCaptcha, which the app cannot show. The server's refusal is replaced by a message telling the customer to create the account, or reset the password, on your website. On the Reset Password screen the message stays on the page; on sign-up it used to arrive as "Security verification failed", which the Create Account screen showed as a success and returned to Sign In.
Change Password broke the next sign-in
Change Password signs the customer out and opens the Reset Password screen. Leaving that screen shut down the app's sign-in handling, so the next attempt to sign in said "An error occurred. Please restart the app." until the app was closed fully. The home screen was built the same way.
- Fixed so that neither screen can shut it down.
No Google sign-in ever completed
A successful Google sign-in answers with a session and no user record, and the app required a user record, so every Google sign-in — including one the server had completed — ended in "Unexpected error during Google sign in". An account with two-factor on met the same error, because the server's request for a code was read the same way.
- Fixed so that the app reads the session, saves it on the phone as a password sign-in does, and loads the profile.
- Fixed accounts with two-factor on, which now go to the same Verification Required screen as a password sign-in.
- Fixed the Google account sticking after one attempt: the phone's Google account picker is shown again each time, so a refused account can switch and the next person on a shared phone does not get the previous one.
- Fixed the Google button showing on a build with no Google client ID and answering every tap with "Failed to get Google ID token." when
googleAuthEnabledwas absent.
Pushes waited for a switch nobody knew about
The app registered each phone for push without a device ID, and a device ID is what makes your server switch push on for a customer who has never set the preference. The preference starts off, so pushes were dropped until the customer found Push Notifications under Profile → Notifications.
- Fixed so that the app registers with a device ID of its own — different for each account on the phone, derived from a random secret that never leaves the phone — and a signed-in customer who allows notifications receives pushes without turning anything else on. A customer who turned the switch off stays off.
- Fixed sign-out, which now tells your server which phone is signing out so that it revokes that phone's device record, and deletes the push token on the phone even when the server cannot be reached.
The Store cart showed made-up shipping and tax
The cart summary read your E-commerce settings from an empty copy, so it always showed shipping of 9.99, free from 50.00, and no tax, whatever you had configured. Checkout charged what your server said, so the two totals disagreed.
- Fixed so that the cart uses the settings the app loaded from your server and works shipping and tax out as checkout does: each is on only when saved as
true, a setting never saved counts as off, the tax rate is a percentage, and shipping is one flat charge per cart with physical products in it. Until the settings have loaded the cart says "Shipping and tax are calculated at checkout". - Fixed a product card that, when it could not reach the app's cart, opened the product page in a way that shut the cart down: after one Add to Cart there and a step back, the cart took no more changes until the app was restarted. The app normally makes the cart reachable everywhere, so this was rare.
XT charts offered Binance's timeframes
- Fixed
defaultExchangeProvider: "xt", which never matched, so the chart offered Binance's timeframes instead of XT's.
The order book's current price vanished on the light theme
- Fixed the current price between the asks and the bids, which was painted white whenever the price was not moving — most of the time — and so could not be seen on the light theme. It now uses the theme's text colour when still, and your
buyColor/sellColorwhile it moves. - Fixed the Recent Trades rows and the order book's price flash using a second, fixed green and red instead of
buyColorandsellColor. With the default colours they now match the rest of the trading screens exactly.
Removed
Configuration keys that did nothing
- Removed
recaptchaEnabled,recaptchaSiteKey,walletAuthEnabled,walletConnectProjectId,twoFactorEnabled,twoFactorSmsEnabled,twoFactorEmailEnabled,twoFactorAppEnabled,emailVerificationEnabled,defaultShowComingSoonandbackgroundUpdateIntervalfrom the example configuration and the configuration guides. A file that still carries them loads as before.
Controls that did nothing
- Removed "Remember me" from the sign-in screen. Nothing read it: either way, the app keeps a customer signed in until they tap Logout or your server ends the session.
- Removed the News Settings page from Profile. Its two switches were never saved and had nothing to control.