Your own keys and URLs
RPC endpoints, market-data and news keys, the Firebase project for push, the privacy-policy and account-deletion URLs, and the four quiet steps — icon, signing team, identifiers, build number — that make a build yours before you submit.
Everything on this page has to be yours in a published build. Most of it works in a development build with our placeholders or with nothing at all, which is exactly why it gets missed.
RPC endpoints
Your deployment talks to chains through RPC providers. Vendor or demo endpoints are shared quota: your customers' traffic competes with everyone else's, and the provider rate-limits the endpoint rather than the app, so the failure looks like your platform being slow.
Register your own with whichever providers you use, restrict them to your own origins, and put them in your server configuration — not in the app. The client never talks to a chain directly.
Give each chain more than one endpoint while you are there. From Core 6.7.2 a chain accepts a comma-separated list, moves to the fastest, drops one that keeps failing and picks it up again when it recovers — which matters more for an app than for a website, because a rate-limited endpoint reaches your customer as a balance that will not load.
An Origin not allowed error from a provider is nearly always the dashboard
allow-list rather than a bad key.
Market-data and news keys
Same argument, plus one of Apple's. None of these keys belongs in the app, and
the app carries none: prices come from your backend, and market news comes from
your own server's /api/news, which fetches from the providers you configure
there. The phone never calls a market-data or news provider itself.
The only client-side identifiers in assets/config/app_config.json are public
ones — stripePublishableKey and googleServerClientId — and the example file
ships both empty. package_for_codecanyon.sh packs a copy of the example in
place of app_config.json, so a vendor value cannot reach a buyer by accident. Put your own in, and never a secret: anything in that file is
readable by anyone who unpacks your app. Apple 5.2.2 treats using a third
party's credentials in your app as your problem, not theirs.
A Firebase project, if you want push notifications
Push is optional and off until you configure it. The app builds, runs and publishes with no Firebase project at all — it simply receives no push notifications.
It has to work that way. The app ships as source, so a Firebase configuration
committed to it would be ours, registering your customers' devices against our
project. And the Google Services Gradle plugin fails the build outright when its
configuration file is missing, so requiring it would mean your first
flutter build failing on a file you had never heard of.
To turn it on — the full walk-through is Push notifications:
-
Create a Firebase project and add an Android app registered with your
androidApplicationIdfromapp_config.json, and an iOS app registered with your bundle identifier. -
Download
google-services.jsonintoandroid/app/. The build detects it and switches push on; you will seegoogle-services.json found - Firebase push ENABLEDin the Gradle output. Without it you get the same line saying DISABLED, and the build succeeds. A file downloaded for a different application ID fails the build with "No matching client found for package name". -
For iOS, add
GoogleService-Info.plistto the Runner target and upload an APNs key in the Firebase console. iOS delivers through APNs whatever Firebase is doing, so an app with FCM configured and no APNs key sends nothing and reports no error. -
Configure the server half —
FCM_PROJECT_ID,FCM_CLIENT_EMAILandFCM_PRIVATE_KEYfrom a service account in the same project. See Notifications. Neither half reports the other's absence.
android/app/google-services.json and ios/Runner/GoogleService-Info.plist
identify your project. Both are gitignored for the same reason
android/key.properties is. The packaging scripts in the source
(package_for_codecanyon.sh, setup/packaging/package-source.sh and
package-source.ps1) leave them out of the package, along with
key.properties, keystores, APNs keys, provisioning profiles and .env files,
but a copy or zip of the project made any other way carries whatever is in the
folders. A buyer creates their own; there is nothing to hand them.
Enable Push Notifications in Xcode, or iOS push is dead
firebase_messaging ships, and the app asks for notification permission. On
iOS, that is not enough: APNs needs the
aps-environment entitlement, and the project has none until you add it.
Xcode target Runner → Signing & Capabilities → + Capability → Push
Notifications. That creates Runner.entitlements and points the build at it.
Nothing tells you if you skip it. The permission prompt still appears, the
customer still agrees, the build still archives and still passes review — and
no notification is ever delivered. The preflight refuses it once a
GoogleService-Info.plist is present, which is the point at which you have
said you want push.
A privacy policy URL
Required by both stores, on a URL you control, describing your service — what you collect, why, how long you keep it, and who you share it with. A policy that names the vendor rather than the operator is a rejection.
An account-deletion URL
Both stores require an in-app path to delete an account and a public URL that explains it. The platform ships both: deletion anonymises the record inside the same transaction as the soft delete — email tombstoned, password, phone, avatar, username, wallet address, profile and settings cleared — and the email address is released, so a deleted customer can register again.
The public page is at /account-deletion on your frontend. Give that URL to
Apple and Google, and check it describes what your deployment actually does:
the prose and the code list the same fields and are kept in step by hand.
Four steps nothing else will tell you about
Each of these fails quietly or late. Your name, identifiers and colours all come
from assets/config/app_config.json and your icon from one image — see
Make it your app for every key — but four things still
need a deliberate step from you.
Replacing the app icon does nothing on its own
assets/icons/app_icon.png is an input — a square PNG of at least
1024×1024. What ships is the Android and iOS icon files generated from it, and
those do not regenerate themselves. So after you replace the image:
dart run tool/apply_app_config.dart --iconsSkip it and your app carries our green mark on every home screen, while the source PNG sitting beside it is yours. The preflight checks the generated icons as well as the source.
Set your own iOS signing team
Xcode cannot archive without a signing team you belong to. The project now
ships with no team at all. Put your 10-character Apple Team ID (upper-case
letters and digits, from your Apple developer account's Membership details) in
iosTeamId in app_config.json and run dart run tool/apply_app_config.dart,
which writes it into every Runner build configuration of the Xcode project; or
choose your team in Xcode under the Runner target → Signing & Capabilities.
Older releases shipped the project with our own team, 52K7QMD7KR. The
preflight refuses a project that still carries it, or whose Release
configuration has no team at all (ios-team), and one whose team differs from
a set iosTeamId (ios-team-mismatch).
Choose your identifiers before the first upload
The identifier is what the stores key your app on, and it is never guessed for you:
- Android —
androidApplicationIdinapp_config.json. Gradle reads it on every build; there is nothing else to edit. - iOS —
iosBundleIdinapp_config.json, thendart run tool/apply_app_config.dartto write it into the Xcode project. Left empty, as the example ships it, the build keeps whatever id the Xcode project has.
Use a domain you control, reversed. Neither store lets you change the
identifier after your first release, and a changed Android ID is a new Play app
that existing installs will not update to. The preflight refuses anything still
under com.bicrypto — including the misspelt com.bicryptto, which is the one
in the template's iOS project.
Bump the version between releases
version: in pubspec.yaml is name+build — 1.0.0+1, for example. Both
stores refuse an upload whose build number they have already seen, and the
message arrives after a full release build has finished. Raise the number after
+ for every upload, and the part before it whenever the release is worth a
version to a customer.
A new source release from us arrives with our own version: line. Before you
upload an update built from it, check that its build number is higher than the
last one you uploaded. See
Version name and build number.
Before you submit
dart run tool/release_preflight.dart --explain fails, and lists the fix, while
the project still carries the template's name, identifiers, colours or icon,
points at a demo backend, uses an http:// baseUrl or a ws:// wsBaseUrl
(backend-not-encrypted), has no iOS signing team of your own or one that
differs from iosTeamId, or has no Android signing key configured. If you
publish only on Google Play, run it with --android-only: that skips every
iOS check and runs every Android one.