devsnack
Documentation

Overload documentation

Run it, point it at your own accounts, ship it under your own brand. Written against version 1.0.0 of the download you get on CodeCanyon.

$19 on CodeCanyon
On this page
01

Overview

Overload is a workout logger, not a workout library. It is the complete Flutter source for an Android and iOS app that records sets in a gym: weight, reps, rest, personal records, progress over time.

The distinction matters commercially. Almost every fitness app on this marketplace is a preset-routine library with bundled demonstration videos, GIFs and photographs. Overload ships zero media assets. There is no video to license, no image rights to verify, and nothing to re-source when you publish under your own brand. The exercise catalogue is 590 text-only records from a public-domain dataset, bundled as one JSON file.

It is built for an intermediate lifter training three to five times a week, on bad gym connectivity, one-handed, between sets. Logging a set is one tap. The app works fully offline.

What it is not

Stated plainly here rather than discovered after purchase:

  • No exercise videos, GIFs, images or illustrations — text records only.
  • No preset training programmes or content library. Three minimal starter routines are offered during onboarding and are obviously editable.
  • No AI or automated coaching.
  • No web or desktop build. Android and iOS only.
  • No backend code. Firebase only — there are no Cloud Functions and no server to deploy.
  • No trainer/client, gym-management or admin roles.
  • No Apple Health, Health Connect or wearable sync.
  • No nutrition or calorie tracking, no social feed.
  • English only. There is no localisation layer, no intl and no ARB files.
  • No Firebase, RevenueCat or AdMob account, and no Play Console or Apple Developer membership. These are third-party services with their own pricing — some of them paid — and you sign up for each yourself. Read Third-party services and their costs before you buy.
  • No design source files. The Overload icon and splash ship for both platforms, but they are drawn from geometry by a Python script rather than authored in Illustrator or Figma — you change two colour constants and re-run it. There is no .ai or .fig to open.
02

Screens

Every screen below is a real screenshot from the app, in roughly the order you meet them. Nothing here is a mockup or a render. The content is the output of the bundled demo seeder — about 13 weeks of plausible training history — which is what your own build looks like once you have run Demo data.

Routines list with a workout-in-progress banner at the top
Routines — the home screenAn unfinished workout floats to the top as a resume banner. Sessions survive backgrounding and force-quit, so one is never lost. Routines drag to reorder and group into folders.
Routine detail showing four exercises with target sets, rep ranges and rest
Routine detail and builderEach exercise carries its own targets — 4 × 4–8 · 180s rest. Drag to reorder, group into supersets, then Start workout opens a session pre-filled from those targets.
Active workout session logging sets, with previous-session values shown as ghost text
Logging a set — the screen that mattersPREV shows last session. The dimmed 117.5 × 5 on rows 3 and 4 is ghost text, not saved data: tap the toggle on an empty row and it fills from last time in one tap. Elapsed, volume and set count run live in the header.
Rest timer docked above the finish button, counting down from just under three minutes
Rest timerAuto-starts on set completion and docks above the finish button — adjustable ±15s, skippable. The deadline is wall-clock, so a timer backgrounded for two minutes returns correct, and a local notification fires if the app is suspended.
Personal record banner reading plus 2.5 kg on your heaviest Barbell Squat
Personal records, as they happenDetected on heaviest weight, best estimated 1RM (Epley) and session volume, and announced the moment the set is logged rather than buried in a report afterwards.
History screen with a calendar heatmap above a list of past sessions
HistoryA calendar heatmap over the training year, then every session with its PR count, tonnage, duration and set count. Past sessions are editable, repeatable and deletable.
Progress screen with consistency stats, a sessions-per-week bar chart and a weekly volume line chart
ProgressTraining streak and consistency, sessions per week, weekly volume, and volume split by muscle group. Every chart is drawn from real logged history — including the dip where a deload week was.
Body screen with a bodyweight chart and a history of measurements
Body metricsBodyweight plus seven measurements, charted over real elapsed time rather than evenly spaced entries. Tap a chip to switch series.
Exercise catalogue of 590 movements with muscle group and equipment filter chips
Exercise catalogue590 movements, text only — no videos, GIFs or photographs to license. Prefix-per-word search across name, muscle group and equipment, filterable by both. Custom exercises merge into the same list.
Plate calculator showing plates per side for 140 kg and a four-step warm-up ramp
Plates and warm-upWhat to load per side for a target weight, from the bar and the plate pairs your gym actually stocks, plus a warm-up ramp up to it. Turn off any plate you do not have.
Settings screen with theme mode, six accent colours, units and an RPE toggle
Settings — the rebranding surfaceTheme mode, six accent colours, kg/lb, and the optional RPE column. Weights are always stored in kilograms; switching to pounds changes display and input only and never rewrites a logged value.
Pro paywall listing three benefits and explaining that RevenueCat keys are not configured
Pro paywallLogging stays free; Pro removes ads and adds CSV export and per-exercise charts. Shown here unconfigured — with no RevenueCat keys it states what to set rather than erroring, which is exactly what a fresh clone does.
03

What’s included

  • Complete Flutter source for one app targeting Android and iOS.
  • 590-exercise catalogue as a bundled JSON asset, public domain, licence archived in LICENSES/.
  • firestore.rules — restrictive security rules, plus firestore.indexes.json.
  • A rules test harness under tools/rules_test for the Firebase emulator.
  • RevenueCat subscriptions and AdMob, both fully wired, both optional, shipping with test credentials so the app runs before you configure anything.
  • The Hearth design system — hand-authored light and dark themes, one palette file, a bundled type scale.
  • Three starter routines as editable seed data.
  • An in-app demo data seeder for filling a fresh install with 13 weeks of plausible history (debug builds only).
  • 370 automated tests plus on-device integration tests that run against a real Firebase project.
  • Buyer documentation: README.md, SETUP.md, REBRANDING.md, TROUBLESHOOTING.md.
  • Six months of item support.
04

Features

Logging a workout

  • One-tap set logging. Last session’s numbers appear inline as ghost text; tapping the completion toggle on an empty row fills them in.
  • Rest timer with a wall-clock deadline, so a timer backgrounded for two minutes returns correct. Fires a local notification when the app is suspended.
  • Sessions survive backgrounding and force-quit. A workout in progress is always resumable.
  • Warm-up sets, drop sets and failure sets; per-set and per-session notes; optional RPE column.
  • Supersets, exercise reordering mid-session, and adding an exercise on the fly.
  • Automatic personal records on heaviest weight, best estimated 1RM (Epley) and session volume — announced the moment they happen.

Routines and exercises

  • Routine builder with drag reorder, supersets, folders and per-exercise targets (sets, rep range, rest).
  • 590 searchable, filterable movements — prefix-per-word search across name, muscle group and equipment.
  • Custom exercises, merged into the same search as the seeded catalogue.
  • Three starter routines offered at onboarding, plainly editable.

History and progress

  • Session history with a calendar heatmap, editable past sessions, and repeat-a-workout.
  • Per-exercise progress: estimated 1RM over time, heaviest set, per-session volume, and every record.
  • Aggregate progress: sessions per week, weekly volume, volume by muscle group, and a training streak.
  • Body metrics — bodyweight plus seven measurements, charted over real elapsed time.
  • Plate calculator and warm-up ramp.
  • CSV export of the full history, exported in kilograms with the unit named in the header.

Platform

  • Offline-first. Firestore local persistence is enabled with an unlimited cache; logging works with no signal and syncs when one returns.
  • Anonymous-first auth. The app signs in anonymously on launch, so there is always an account. Creating a real one links the credential and preserves the same uid — data is never migrated or copied, so it cannot be lost.
  • Email/password, Google and Apple sign-in. Account deletion in-app, which both stores require.
  • Kilograms and pounds. Weights are always stored in kilograms; the setting affects display and input only.
  • Light and dark themes, dark by default, plus six selectable accent colours.
05

Architecture

Project layout

overload/
lib/
  main.dart                       app entry, Firebase init, offline persistence
  config/
    app_config.dart               THE config file — name, AdMob IDs, RevenueCat, flags
    routes.dart                   GoRouter: every route and the redirect gate
    providers.dart                app-wide Riverpod providers
    theme/
      app_theme.dart              public entry point
      app_palette.dart            the only file containing hex values
      app_color_scheme.dart       hand-authored Material 3 ColorSchemes
      app_typography.dart         the type scale
      app_spacing.dart            spacing, radius, motion
      overload_colors.dart        ThemeExtension for domain colours
  core/
    utils/  widgets/              shared helpers and widgets
  data/
    models/                       freezed models mirroring the Firestore shapes
    repositories/                 one per collection — the only Firestore callers
    services/                     auth, purchases, ads, notifications, CSV export
  features/
    <feature>/
      presentation/               screens and widgets
      providers/                  Riverpod providers for that feature
assets/
  data/exercises.json             590 movements, text only
  data/starter_routines.json      three editable starter routines
  google_fonts/                   bundled type, five weights
firestore.rules                   security rules — deploy these
firestore.indexes.json
tools/rules_test/                 emulator test harness for the rules
test/                             370 unit and widget tests
integration_test/                 on-device tests against a real Firebase project

Stack

LayerChoiceVersion
Framework
Flutter (Dart)
3.47.2 / Dart 3.13.2
State
Riverpod — Notifier / AsyncNotifier
^3.4.2
Routing
GoRouter
^17.5.0
Models
freezed + json_serializable
^3.1.0
Auth
firebase_auth
^6.5.7
Data
cloud_firestore, offline persistence on
^6.8.0
Sign-in
google_sign_in, sign_in_with_apple
^7.2.0 / ^8.1.0
Subscriptions
purchases_flutter (RevenueCat)
^10.9.1
Ads
google_mobile_ads
^9.1.0
Notifications
flutter_local_notifications + timezone
^22.3.0
Charts
fl_chart
^1.1.1
Export
csv + share_plus
^6.0.0 / ^13.3.0
Type
google_fonts, bundled from assets
^8.2.1

Design invariants

These are the rules the codebase holds itself to. Breaking one is where bugs come from, so they are worth knowing before you edit.

  • Widgets never touch Firestore. Widget → provider → repository, one direction. The classes in lib/data/repositories/ are the only Firestore callers.
  • Weights are always stored in kilograms. The kg/lb setting affects display and input only and must never mutate a stored value.
  • Hex literals live only in app_palette.dart. Everything else reads from the ColorScheme or from the OverloadColors theme extension, which is what makes a rebrand a one-file change.
  • The seeded exercise catalogue is local, not in Firestore. It is identical for every user, so per-account copies would cost reads for nothing. Only custom exercises are stored per user.
  • Generated code is committed. *.freezed.dart and *.g.dart are in the repository, against the usual Dart convention, so the project compiles from a fresh clone without anyone first discovering build_runner. Re-run codegen and commit the output when you change a model.
  • Anything rendering aligned numbers uses a metric text style carrying tabular figures, so weight and rep columns do not twitch as digits change.
  • English only. User-facing strings are plain literals in the widget that renders them.
06

Requirements

RequirementVersionNotes
Flutter
3.47.2
Pinned. Other versions may work; this is what it is built and tested against.
Android
minSdk 24, target/compile SDK 37
Compile SDK is pinned rather than tracking Flutter’s default.
iOS
17.0 minimum
Xcode required for iOS builds.
JDK
17
For Android builds. The Firebase CLI needs JDK 21 if you run the emulator suite.
Firebase project
Spark (free) tier
Enough to build and evaluate everything in this app. Beyond the free quotas Google bills you on usage — see Third-party services and their costs.
Developer accounts
Play Console, Apple Developer Program
Only to publish. Both charge a fee — see Third-party services and their costs.
07

Third-party services and their costs

Warning
What you bought is source code, and nothing else. Overload talks to services run by Google, RevenueCat and Apple. Not one of them is included in the purchase price, none of them is resold to you here, and several of them can cost you money. You sign up for each one yourself, in your own name, and you are billed directly by that provider under their terms — some require a paid account before you can publish at all.
ServiceNeeded forWhat it costs you
Firebase — Auth + FirestoreRequired
All persistence, sync and sign-in. The app does not run without it.
The free Spark plan is enough to build the app, evaluate it, and serve a small user base. Firestore’s free tier is capped on daily reads, writes and stored data; a real audience will pass those caps, and going past them means moving to the Blaze pay-as-you-go plan, billed by Google on usage. Overload uses no Cloud Functions, so Auth and Firestore are the whole bill.
RevenueCatOptional
Pro subscriptions. Skip it and Pro simply stays locked.
Free below a monthly tracked-revenue threshold, then a paid tier charged as a percentage of the revenue it tracks. Check their current pricing before you build a business on it — the threshold and the rate are theirs to change.
Google AdMobOptional
Banner and interstitial ads. Skip it and the shipped test IDs keep working.
No fee — AdMob pays out rather than charges. You must create and manage your own AdMob account; the app ships with Google’s public test ad unit IDs until you replace them with yours. Complying with Google’s AdMob and Play ad policies is your responsibility, as are payment thresholds, tax forms and approval. Approval is not guaranteed.
Google Play ConsoleRequired to publish
Distributing the app on Google Play.
A one-time registration fee — US$25 at the time of writing — plus Google’s commission on anything you sell.
Apple Developer ProgramRequired to publish
Distributing the app on the App Store, and TestFlight.
An annual membership — US$99/year at the time of writing — plus Apple’s commission on anything you sell.
Store commission
Every subscription sold through either store.
Apple and Google each take a cut of every subscription — commonly 15–30% depending on the programme you qualify for. This is charged before RevenueCat’s share, not after.
Firebase AnalyticsOptional
A minimal set of events.
Free, and included with the Firebase project.
Local notifications
The rest-timer alarm while the app is suspended.
Free, and needs no account. There is no FCM and no server to pay for.
Note

Every price above is set by its provider, not by us, and can change without notice. Treat the figures here as a starting point and confirm the current terms on each provider’s own pricing page before you budget or commit.

Item support covers this code. It does not cover your bills. We will walk you through connecting each service; we cannot supply the accounts, absorb their charges, or intervene in a billing or account-approval decision made by Google, Apple or RevenueCat.

08

Setup

Warning
There is one setup step a fresh clone genuinely cannot skip. Firebase configuration files are not included in the download — they carry a real project ID and API key, and shipping them would point every buyer’s app at someone else’s Firebase project. You generate your own with flutterfire configure. Until you do, the project will not build.

Toolchain

terminal
# Confirm your Flutter version
flutter --version        # expect 3.47.2

# Install the Firebase tooling
npm install -g firebase-tools
dart pub global activate flutterfire_cli

firebase login

Create a Firebase project

  1. 01
    Create a project in the Firebase console.
  2. 02
    Under Build → Authentication → Sign-in method, enable Anonymous (required — the app signs in anonymously on launch), plus Email/Password, and Google and Apple if you want them.
  3. 03
    Under Build → Firestore Database, create a database. Choose a region close to your users; it cannot be changed later.
Note
Anonymous sign-in is not optional. The app has no signed-out state by design — it signs in anonymously so there is always an account, and creating a real one later links the credential rather than replacing it, preserving the uid and all the data underneath it. If anonymous sign-in is disabled, the app will not get past its startup gate.

Connect the app to your project

terminal
cd overload
flutter pub get

flutterfire configure \
  --project=your-project-id \
  --platforms=android,ios

That command writes three files, all deliberately gitignored:

lib/firebase_options.dart
Dart-side configuration read by main.dart.
android/app/google-services.json
Android native configuration.
ios/Runner/GoogleService-Info.plist
iOS native configuration.

.example files ship next to the last two so you can see the expected shape.

Warning
When you change the Android applicationId or the iOS bundle identifier, re-run flutterfire configure. The generated files embed the identifier, and a mismatch produces a runtime failure that is easy to misread as a code problem.

Deploy the security rules

This is the step reviewers check and the one most commonly skipped. A Firestore database created in test mode is open to the world and expires after 30 days.

terminal
cp firebase.json.example firebase.json    # if you do not already have one
firebase use --add                        # select your project

firebase deploy --only firestore:rules,firestore:indexes

Run it

terminal
flutter devices
flutter run -d <device-id>

On first launch the app signs in anonymously and takes you through onboarding: training goal, experience, units, and an offer to install the three starter routines. All of it is skippable.

Note
No credentials are needed to run it. There is no seeded login and no demo account, because there is no server and no user table to seed — the app creates an anonymous account for you on launch. See Demo data for filling a fresh install with realistic history.
09

Data model and security rules

Firestore
users/{uid}
  displayName, email, units, theme, accentColor,
  onboardingComplete, showRpe, isPro, createdAt

users/{uid}/exercises/{id}          custom exercises only — the 590 seeded live in assets
users/{uid}/routines/{id}
users/{uid}/sessions/{id}           status: active | completed | discarded
users/{uid}/records/{exerciseId}    denormalised, so a PR check mid-set is one read
users/{uid}/measurements/{id}

Why it is shaped this way

  • Everything lives under users/{uid}. The data model is deliberately single-user — there is no gym-management or trainer/client seam — which makes the security rule simple and the audit trivial.
  • Records are denormalised on purpose. Checking whether a set is a personal record happens mid-workout, so it must be one document read rather than a scan over history.
  • Sessions carry a status. Discarded sessions are stored as discarded and never appear in history or in any aggregate.

The rules

firestore.rules restricts every path to request.auth.uid == uid with a deny-all fallthrough. Clients cannot write isPro — the subscription state is mirrored onto the profile for instant UI, but RevenueCat remains the source of truth and the rules forbid a client granting itself Pro.

A test harness for the Firebase emulator ships under tools/rules_test, and integration_test/app_test.dart asserts the deny cases against a real project on a device.

Warning
Deploy the rules before you ship. An open ruleset is the single most common reason a Firebase app fails review, and under Envato policy it is a refund-obligating security vulnerability.
10

Optional integrations

Every integration below is optional and degrades cleanly. A fresh clone with nothing configured runs, logs workouts, and does not crash or show a broken screen. That is a hard requirement of the codebase, not an accident.

IntegrationUnlocksConfigured viaWith nothing set
Firebase Auth + Firestore
All persistence and sync
flutterfire configure
Required. The project will not build without it.
RevenueCat
Pro subscriptions
--dart-define=REVENUECAT_ANDROID_KEY=… --dart-define=REVENUECAT_IOS_KEY=…
Pro stays locked. The paywall renders and explains what to configure rather than erroring.
AdMob
Banner and interstitial ads
AdMobConfig + both native manifests
Works out of the box — Google’s public test IDs ship as the default and need no AdMob account.
Google Sign-In
Google as an account provider
Firebase console + SHA-1 fingerprint
Button is present; sign-in fails until the provider is enabled. Email/password and anonymous still work.
Apple Sign-In
Apple as an account provider
Xcode capability + Firebase console
Same. Required by App Store review if you offer any other third-party sign-in.
Local notifications
Rest timer alarm while suspended
Nothing — no server, no FCM
Works. Permission is requested when the user first starts a timer.
Firebase Analytics
A minimal set of events
Enabled with the Firebase project
Works, or silently does nothing.
Note
No API key is ever read on the client from a committed file. RevenueCat keys come from --dart-define at build time. The AdMob values in AppConfig are Google’s public test IDs, which are safe to ship and safe to click. There is no .env, and there are no server-side secrets, because there is no server.
11

Subscriptions (RevenueCat)

Pro is not a wall in front of logging. Everything core is free: unlimited routines, unlimited history, and the aggregate progress view. Pro removes ads and unlocks CSV export and the per-exercise charts.

The gate is defined in one place, in FreeTier inside lib/config/app_config.dart:

app_config.dart
abstract final class FreeTier {
  static const int? maxFreeRoutines = null;   // null = unlimited
  static const int? freeHistoryDays = null;   // null = all of it
  static const bool csvExportRequiresPro = true;
  static const bool advancedChartsRequirePro = true;
}

The capped model is fully implemented and simply switched off. Set maxFreeRoutines to 3 and freeHistoryDays to 30 and the allowance logic starts enforcing again with no other change — which is why they are nullable rather than sentinel numbers.

Configuring it

  1. 01
    Create a RevenueCat project and connect your Play Console and App Store Connect apps.
  2. 02
    Create products in each store first. RevenueCat surfaces store products; without them the paywall renders with nothing to sell.
  3. 03
    Create an entitlement identified exactly pro, and an offering named default with your monthly and annual packages.
  4. 04

    Pass the public SDK keys at build time:

    terminal
    flutter run \
      --dart-define=REVENUECAT_ANDROID_KEY=goog_xxxxx \
      --dart-define=REVENUECAT_IOS_KEY=appl_xxxxx
Note
Pro is never granted from the cached profile field alone. isPro is mirrored onto the user document so the UI is not blocked on a network call, but RevenueCat is the source of truth and the Firestore rules forbid a client writing that field.

Restore purchases

The paywall includes a restore action. This is an App Store requirement, not a nicety — an app that sells a subscription without one is rejected.

12

Ads (AdMob)

The app ships with Google’s official test unit IDs and works without an AdMob account. Replace them in three places before release:

  1. 01
    AdMobConfig in lib/config/app_config.dart — banner and interstitial unit IDs.
  2. 02
    android/app/src/main/AndroidManifest.xml — the com.google.android.gms.ads.APPLICATION_ID meta-data. The SDK reads the app ID from the manifest and crashes at startup if it is absent.
  3. 03
    ios/Runner/Info.plist — the GADApplicationIdentifier key.

AdMobConfig.usingTestIds exists so you cannot ship test ads to production by forgetting a step. Set it to false once you have replaced the IDs.

Warning
Never click your own live ads during development. Real IDs clicked in a debug build will get your AdMob account suspended. That is what the test IDs are for.

Where ads appear

  • Never during an active workout. Banners are shown on non-session screens only.
  • One interstitial on workout completion, frequency-capped by AdMobConfig.interstitialCooldown (four hours by default).
  • Nothing at all for Pro users.
13

Demo data

There are no seeded accounts and no demo credentials — the app is anonymous-first, so it creates an account for you on launch, and there is no server or user table to seed.

To fill a fresh install with realistic content, use the in-app seeder:

  1. 01
    Run a debug build.
  2. 02
    Open More → Settings and scroll to Demo data.
  3. 03
    Tap to seed. It writes roughly 13 weeks of history to your own account.

The seeded history is built to look like real training rather than generated data: progression curves with plateaus and deload weeks, sessions that were missed, weights a gym can actually load, plus bodyweight and measurement history so every chart has something in it. Clearing it removes only what the seeder wrote and leaves your own sessions alone.

Note
The whole section is gated on kDebugMode, so the compiler removes it from a release build entirely. You cannot ship the seeder by forgetting to turn something off.
14

Branding and customization

Two files carry almost everything: lib/config/app_config.dart and lib/config/theme/app_palette.dart.

Identifiers

WhatWhereShips as
Android application ID
android/app/build.gradle.kts — namespace and applicationId
dev.devsnack.overload
iOS bundle identifier
ios/Runner.xcodeproj — PRODUCT_BUNDLE_IDENTIFIER
dev.devsnack.overload
Android display name
android/app/src/main/AndroidManifest.xml — android:label
Overload
iOS display name
ios/Runner/Info.plist — CFBundleDisplayName
Overload
In-app name
AppConfig.appName
Overload
Support email, privacy and terms URLs
AppConfig
example.com placeholders — replace before release

Change the identifiers first, then re-run flutterfire configure.

Colour

The design system is called Hearth: dark-first, warm, built to be read at arm’s length on a dim gym floor. Light is tuned separately rather than derived by inverting dark.

Every hex value in the app is in lib/config/theme/app_palette.dart. Nothing else contains one. Change the accent there and it propagates through both themes.

Warning
Re-check contrast after a rebrand. The shipped accent is deliberately not reused on light backgrounds — it fails contrast for text there, so the light scheme uses a deepened variant, and text on an accent fill is a dark warm brown rather than white. The test suite asserts these ratios, so a rebrand that breaks legibility fails a test rather than being discovered by a user.

Typography

Five weights of Plus Jakarta Sans are bundled under assets/google_fonts/. Runtime fetching is disabled, so the app never makes a network request for a font and a missing weight throws loudly instead of silently falling back. Adding a weight to the scale means adding the file.

Starter routines

Edit assets/data/starter_routines.json. Every exercise id must resolve against assets/data/exercises.json — there is a test that fails loudly if one does not.

The style guide screen

Debug builds carry a design-system reference screen listing every colour, type style and component the theme defines, reachable from Settings → Design system. It is the fastest way to check a rebrand in one scroll. It is compiled out of release builds.

15

Release builds

Android

Generate a keystore and create android/key.properties:

terminal
keytool -genkey -v -keystore ~/upload-keystore.jks \
  -keyalg RSA -keysize 2048 -validity 10000 -alias upload
key.properties
# android/key.properties  — never commit this file
storePassword=…
keyPassword=…
keyAlias=upload
storeFile=/absolute/path/to/upload-keystore.jks
terminal
flutter build appbundle --release \
  --dart-define=REVENUECAT_ANDROID_KEY=goog_xxxxx

iOS

Open ios/Runner.xcworkspace in Xcode, set your team and bundle identifier, add the Sign in with Apple capability if you offer it, then:

terminal
flutter build ipa --release \
  --dart-define=REVENUECAT_IOS_KEY=appl_xxxxx
16

Production checklist

  1. 01
    Replace the identifiers in android/app/build.gradle.kts and ios/Runner.xcodeproj, then re-run flutterfire configure.
  2. 02
    Replace AppConfig.supportEmail, privacyPolicyUrl and termsUrl — they ship as example.com placeholders.
  3. 03
    Replace the AdMob unit IDs in AppConfig, AndroidManifest.xml and Info.plist, then set AdMobConfig.usingTestIds = false.
  4. 04
    Supply RevenueCat keys via --dart-define in your release command.
  5. 05
    Deploy the Firestore rules and indexes. Verify a signed-in user cannot read another user’s documents.
  6. 06
    Enable Anonymous sign-in in the Firebase console, plus every provider whose button you keep.
  7. 07
    Replace the app icon and splash artwork — the Overload mark ships. Edit the colour constants in tools/icon/generate_icon.py, re-run it, then dart run flutter_launcher_icons and dart run flutter_native_splash:create.
  8. 08
    Confirm no keystore, key.properties, or Firebase config file is committed.
  9. 09
    Run flutter analyze (expect zero issues) and flutter test (expect 370 passing).
  10. 10
    Build a release on both platforms from a clean checkout before submitting.
17

Changelog

Every version published so far. Updates are free for the life of the item.

v1.0.0 · Sep 2026
Initial release
18

Support and licensing

Six months of item support is included with your purchase, per the CodeCanyon standard: answering questions about how the item works, help with defects, and updates for bugs.

Support does not include your Firebase, RevenueCat, AdMob or store accounts, the fees any of those services charge you, your hosting, or customisation work. We walk you through setup; we cannot supply the accounts or pay their bills. See Third-party services and their costs.

Before writing in, check TROUBLESHOOTING.md in the download — it covers the errors people actually hit, including the missing firebase_options.dart on a fresh clone, iOS build failures in the ads SDK, permission-denied errors from undeployed rules, and paywalls with nothing to sell.

Licence

Sold under the standard Envato Regular and Extended licences. The bundled exercise dataset is public domain; its provenance and licence are archived in LICENSES/. Every third-party dependency is listed with its licence in README.md.

What support covers

  • Six months of support from purchase, extendable at checkout
  • Support covers bugs in the template and questions about how it is put together
  • It does not cover custom feature work, third-party API changes or store review outcomes
  • The Regular licence covers one free end product. Charging users for the app itself needs the Extended licence