MMashDiv

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.

7 min readUpdated 26 September 2026mobile, keys, rpc, privacy-policy, account-deletion

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:

  1. Create a Firebase project and add an Android app registered with your androidApplicationId from app_config.json, and an iOS app registered with your bundle identifier.

  2. Download google-services.json into android/app/. The build detects it and switches push on; you will see google-services.json found - Firebase push ENABLED in 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".

  3. For iOS, add GoogleService-Info.plist to 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.

  4. Configure the server half — FCM_PROJECT_ID, FCM_CLIENT_EMAIL and FCM_PRIVATE_KEY from 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 --icons

Skip 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 — androidApplicationId in app_config.json. Gradle reads it on every build; there is nothing else to edit.
  • iOS — iosBundleId in app_config.json, then dart run tool/apply_app_config.dart to 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.