Appearance
Building & rebranding the apps
Point an app at your server, put your name and icon on it, and produce the file you upload to the store. First build: about two hours. After that: minutes.
What changes where
This is the part that confuses people. Some things are passed in at build time and need no code editing; others live in files you must edit.
| What | Where it is set | Needs code edit? |
|---|---|---|
| Server address | --dart-define=API_ORIGIN | No |
| Name shown inside the app | --dart-define=APP_NAME | No |
| Splash title, login subtitle, "powered by" | --dart-define=… | No |
| Logo, colours inside the app | Sent by your server per school | No |
| Name under the icon on the phone | AndroidManifest.xml / Info.plist | Yes |
| App icon | Image files in the project | Yes |
| Package / bundle ID | Gradle and Xcode settings | Yes |
| Version number | pubspec.yaml | Yes |
Two different "app names"
--dart-define=APP_NAME changes the name inside the app — headers, splash screen. It does not change the name under the icon on the phone's home screen. That one is hardcoded in the Android and iOS project files and is edited separately, below.
Set only one and you get an app called "St Mary's" that installs as "Parent Student".
Step 1: Install Flutter
Install Flutter on the machine that will build, then check it:
bash
flutter doctorFix anything it reports for Android. For iOS you need a Mac with Xcode.
Step 2: Point the app at your server
Nothing to edit — pass it in when you build:
bash
flutter build apk \
--dart-define=API_ORIGIN=https://erp.stmarys.edu.in \
--dart-define=APP_NAME="St Mary's School" \
--dart-define=APP_SPLASH_TITLE="Parent Portal" \
--dart-define=APP_SUBTITLE="Parent & Student Portal" \
--dart-define=APP_POWERED_BY="Powered by St Mary's"| Setting | Controls |
|---|---|
API_ORIGIN | Your server — no trailing slash, and it must be https |
APP_NAME | Brand name shown inside the app |
APP_SPLASH_TITLE | Big headline on the splash screen |
APP_SUBTITLE | Line under the logo on the login screen |
APP_POWERED_BY | Footer on the splash screen |
If you leave these out, the app uses its built-in defaults, which point at the ProjectWorlds demo server. Always pass API_ORIGIN for a real build.
Step 3: Change the name under the icon
Android — android/app/src/main/AndroidManifest.xml:
xml
<application android:label="St Mary's School" ...>iOS — ios/Runner/Info.plist:
xml
<key>CFBundleDisplayName</key>
<string>St Mary's School</string>The iOS name is currently auto-generated
Out of the box iOS shows "School Erp Parent App" — machine-made, with "Erp" instead of "ERP". Change it before any iOS release.
Step 4: Change the icon
There is no icon-generating tool set up in this project, so either replace the images by hand or add the standard tool.
The easy way — add flutter_launcher_icons to pubspec.yaml:
yaml
dev_dependencies:
flutter_launcher_icons: ^0.14.1
flutter_launcher_icons:
android: true
ios: true
image_path: "assets/app_icon.png"Then:
bash
flutter pub get
dart run flutter_launcher_iconsUse a 1024×1024 PNG, square, no transparency, and keep important detail away from the edges — Android crops icons into circles and squircles.
By hand: replace every size in android/app/src/main/res/mipmap-*/ic_launcher.png and the images in ios/Runner/Assets.xcassets/AppIcon.appiconset/. This is tedious and easy to get wrong; the tool is worth the two minutes.
Step 5: Change the package / bundle ID
Only needed if this client publishes their own app — see Before you build. Skip it if you publish one app for everyone.
Android — android/app/build.gradle.kts, change both:
kotlin
namespace = "com.stmarys.parent"
applicationId = "com.stmarys.parent"The folder path of MainActivity.kt under android/app/src/main/kotlin/… must match the new package, and the package line inside that file too.
iOS — in Xcode, or in ios/Runner.xcodeproj/project.pbxproj, change every PRODUCT_BUNDLE_IDENTIFIER.
The iOS bundle ID is still the Flutter placeholder
It currently reads com.example.schoolErpParentApp. Apple will not accept a com.example.* identifier, and it does not match the Android ID either.
Change it before your first iOS build, and use the same identifier on both platforms so the two stores agree.
A changed ID means a new Firebase entry
The package name is registered in Firebase. Change the ID and register the new one, or push notifications stop — silently. See Push notifications.
Step 6: Set the version
In pubspec.yaml:
yaml
version: 3.0.0+5The part before + is what users see. The number after + is the build number, and stores reject an upload whose build number is not higher than the last one. Raise it every single release.
Step 7: Build the release file
Android — for the Play Store, build an app bundle:
bash
flutter build appbundle --dart-define=API_ORIGIN=https://erp.stmarys.edu.inOutput: build/app/outputs/bundle/release/app-release.aab
Android — for direct install (sending an APK to a school, or your own download page), build an APK:
bash
flutter build apk --release --dart-define=API_ORIGIN=https://erp.stmarys.edu.inOutput: build/app/outputs/flutter-apk/app-release.apk
iOS — on a Mac:
bash
flutter build ipa --dart-define=API_ORIGIN=https://erp.stmarys.edu.inSigning: get this right once, or lose the app forever
A release build must be signed with your key, and every future update must use the same key. Lose it and you can never update that app again — you would publish a new one and every user would have to reinstall.
Back up the key file and its passwords somewhere you will still have them in five years. Not only on the build machine.
Before you upload, check the build
Install the built APK on a real phone and confirm:
- It opens on your server, not the demo one — log in with a real account
- The name under the icon is right
- The icon is right
- Push notifications arrive (parent app)
- Photos and documents load
Catching a wrong API_ORIGIN now takes a minute. Catching it after store review takes days.
Common build problems
| What you see | Cause |
|---|---|
| App opens but cannot log in | API_ORIGIN missing, has a trailing slash, or is http not https |
| Installs as "Parent Student" | Step 3 not done — APP_NAME alone does not change it |
| "Package name already exists" at the store | That ID is already published — you need your own |
| Store rejects the upload as a duplicate version | Build number not raised — step 6 |
| Push works in testing, not after rebranding | New package ID not registered in Firebase |
| iOS build fails on bundle identifier | Still com.example.… — step 5 |