Overview
Car Booking is a pair of Android apps for the Car Booking SaaS – Car Rental Management System website: a Driver app for drivers and a Customer app for renters. Rental company owners and staff keep using the website. The apps talk only to your website, so all data stays on your server.
What is in the package
| Folder / file | What it is |
|---|---|
driver_app/ | Flutter project of the Driver app (package id com.carbooking.driver_app), with its android/ folder ready. |
customer_app/ | Flutter project of the Customer app (package id com.carbooking.customer_app), with its android/ folder and tools/build_branded.py. |
docs/mobile-api.md | Reference of the website API the apps use (for developers who want to extend them). |
README.md | Short overview and quick start. |
documentation/ | This guide. |
Features
Driver app
| Area | What the driver can do |
|---|---|
| Sign in | Email and password of the driver account created on the website. Stays signed in (token kept in the phone's secure storage). |
| Home | Today's jobs, the week ahead, money earned and to be paid, and alerts. |
| Jobs | Jobs for the next days with call the customer and open in maps buttons. |
| Start and finish a rental | Odometer and fuel level at start and at return; the website closes the contract and works out late and extra-kilometre fees. |
| Photos | Pick-up, return and damage photos, uploaded to the booking (visible to the office and the customer). |
| Bookings | History of the driver's bookings with search and filters. |
| Rental agreements | Read the agreement and sign with a finger. |
| Expenses | Add an expense (fuel, parking, toll…) with a photo of the receipt. |
| Earnings | Commission per completed job and the payout history. |
| Notices & push | Office notices; push notification when a job is assigned or cancelled. |
Customer app
| Area | What the renter can do |
|---|---|
| Find a company | Search by name or city, scan the company's QR code, or type the company code. One app can serve many rental companies, or you can build an own-brand app for one company (see Own-brand customer app). |
| Sign in | Email code, password, or phone SMS code (each method can be switched on or off by the company). New customers are registered on first sign-in. |
| Search cars | Pick-up and return date and time, only the free cars with the trip price, sorting (price, seats, name), filters (type, gearbox, fuel) and saved favourites. |
| Car page | Photos, extras, pick-up and return places, promo or friend code, notes, price breakdown and the company's rules (online payment, approval, free cancellation). |
| Book and pay | Book, then pay on the company's secure payment page (Stripe, PayPal, Paystack, Flutterwave or Razorpay, whichever the company enabled). |
| My bookings | Upcoming, past and cancelled. Per booking: status, dates, places, extras, money (total, paid, to pay), "show at pick-up" card, pay, extend the rental, rate the rental, invoice (PDF), cancel inside the free window, car photos, deposit and driver details, report a problem, add to calendar. |
| Home dashboard | Current trip, countdown to the next trip, directions, amount to pay, book again and offers. |
| Profile | Edit details, My documents (photograph the licence and ID with expiry date), Rewards (loyalty points, history, friend code, current promo codes), switch company, delete my account. |
| Contact | Call, WhatsApp, email, or a message into the company's inbox; Ask our AI helper when the company has it switched on. |
| Notifications | Inbox (bell) that keeps every message, plus push notifications when a booking is confirmed or cancelled and a reminder the day before pick-up and return. |
| Comfort & security | Light, dark and automatic appearance; optional fingerprint / face / PIN lock. |
Not included
- Paying by card inside the app (payment opens the company's own secure page, so card data never passes through the app).
- Saved cards and in-app language packs.
Requirements
Your computer (to build the apps)
| What | Version / notes |
|---|---|
| Operating system | Windows 10/11 (64-bit), macOS, or Linux (64-bit) |
| Flutter SDK | Latest stable release (3.27 or newer; tested with 3.47). Includes Dart. |
| Android Studio | Latest version. Gives you the Android SDK, build tools, Java (JDK 17+, bundled) and the emulator. |
| Android SDK | Installed by Android Studio (SDK Platform, Build-Tools, Command-line Tools, Platform-Tools). |
| Disk / memory | About 10 GB free space, 8 GB RAM or more recommended. |
| Python 3 with Pillow | Only for the own-brand build script (pip install pillow). |
Phones that can run the apps
Android 7.0 or newer (the minimum is Flutter's default for the Flutter version you build with).
Accounts
| Account | Cost | Needed for |
|---|---|---|
| Google Play Console | $25 one time | Publishing on Google Play |
| Firebase (Google) | Free (Spark plan is enough) | Push notifications |
Website
Car Booking SaaS v1.7 or newer on HTTPS — see Prepare the website.
Install Flutter & Android Studio
- Install Android Studio from developer.android.com/studio. Start it once and finish the setup wizard (Standard). Then open Settings → Languages & Frameworks → Android SDK → SDK Tools and tick Android SDK Command-line Tools and Android SDK Platform-Tools. In Plugins, install the Flutter plugin (it adds Dart).
- Install Flutter following docs.flutter.dev/get-started/install
(choose your operating system → Android). Unzip it to a folder without spaces (e.g.
C:\src\flutteror~/flutter) and add itsbinfolder to your PATH. - Accept the Android licences and check everything:
flutter doctor --android-licenses flutter doctorflutter doctormust show a tick for Flutter and Android toolchain. (Chrome, Xcode and Visual Studio are not needed for Android.)
flutter doctor cannot find Java, set JAVA_HOME to Android Studio's bundled JDK
(e.g. C:\Program Files\Android\Android Studio\jbr) or run flutter config --jdk-dir "<that folder>".Prepare the website
Do this once on the website before building the apps.
- Website on HTTPS. Install Car Booking SaaS v1.7 or newer on your domain with an SSL certificate (Let's Encrypt is free).
Release builds of the apps refuse plain
http://. - Run the update. If you upgraded an existing website, make sure the database update ran (
php artisan migrate --force, or the website's update screen). It creates the tables for phones, notifications, customer sign-in codes and photos. - Find your API address. It is your website address followed by
/api/mobile/v1, for examplehttps://rent.yourdomain.com/api/mobile/v1. Test it in a browser:https://rent.yourdomain.com/api/mobile/v1/companies?q=ashould answer with JSON (a list of companies), and…/api/mobile/v1/company/demoshows one company's name, logo and colour. - Online booking for each company. The customer app needs the company's online booking switched on (owner → Online Booking). The
company code is the web address name of that page:
…/book/demomeans codedemo. Owners also find the code, a QR code and a "copy message" button under Mobile apps in their menu. - Customer sign-in. Customers receive a 6-digit code by email, so the company needs working email settings (Settings → Email). The owner can also allow password sign-in and SMS code sign-in (needs the owner's Twilio account). Each method can be switched on or off by the company.
- Driver accounts. Create each driver under Driver in the owner's menu. Drivers sign in to the app with that email and password. Set the commission rule on the driver's page to see earnings in the app.
- Store links (optional but recommended). After publishing, add the Google Play / App Store links as super admin → Mobile apps. They appear on every
company's public "Get our app" page (
/book/<code>/app) together with the QR code. - Cron job and queue. The website's cron (
php artisan schedule:runevery minute) sends the reminders (pick-up, return, payment). For push notifications keep a queue worker running (php artisan queue:work) or setQUEUE_CONNECTION=syncin.env. - Upload size. Photos are sent from the phone: set PHP
upload_max_filesizeandpost_max_sizeto at least10M.
Set up the projects
Unlike many Flutter packages, the android/ folder of both apps is already included, with the permissions, app name, icon and Firebase hook applied. There is no setup script.
- Unzip the package. It contains
driver_app,customer_appanddocs; put them in a path without spaces, for example~/projects/android_app. - Download the libraries for each app:
cd ~/projects/android_app/driver_app flutter pub get cd ../customer_app flutter pub get - Set your website address. Either edit
lib/config.dartin each app:
or leave the file as it is and addstatic const String apiBase = String.fromEnvironment( 'API_BASE', defaultValue: 'https://your-domain.com/api/mobile/v1', );--dart-define=API_BASE=https://your-domain.com/api/mobile/v1to everyflutter run/flutter buildcommand. - Choose your package name. The placeholders are
com.carbooking.driver_appandcom.carbooking.customer_app. Change them to your own (for examplecom.acmerentals.driver) before you publish: inandroid/app/build.gradle.kts(namespaceandapplicationId) and rename the folderandroid/app/src/main/kotlin/com/carbooking/driver_app(and thepackageline inMainActivity.kt) to match.The package name can never change after the app is published on Google Play. Use lower case letters, numbers, underscores and dots only. - Open the project in Android Studio (File → Open → the
driver_apporcustomer_appfolder) or VS Code.
--dart-define=COMPANY=demo to the command, or use the build script
(Own-brand customer app).Run on a phone or emulator
On a real phone
- On the phone: Settings → About phone, tap Build number 7 times to enable Developer options.
- Settings → Developer options → USB debugging: on. Connect the phone with USB and allow the computer.
- Check the phone is listed, then run (in the app's folder):
flutter devices flutter run --dart-define=API_BASE=https://your-domain.com/api/mobile/v1
On the emulator
Android Studio → Device Manager → Create device (e.g. Pixel 8, latest system image) → Start. Then flutter run.
Testing against a local website (http)
Debug builds allow plain http:// so you can test against a website on your computer or local network (release builds need HTTPS):
# phone on the same Wi-Fi as your computer (use your computer's IP address)
flutter run --dart-define=API_BASE=http://192.168.1.10/car-booking-saas/main_file/api/mobile/v1
# Android emulator: 10.0.2.2 is your computer
flutter run --dart-define=API_BASE=http://10.0.2.2/car-booking-saas/main_file/api/mobile/v1
Which account to sign in with
| App | Sign in with |
|---|---|
| Driver | The email and password of a driver account created on the website (owner → Driver). |
| Customer | The company code of a company that has online booking switched on, then any email address: the 6-digit code arrives by email. New emails become customer accounts on first sign-in. |
A test APK to share
flutter build apk --debug --dart-define=API_BASE=https://your-domain.com/api/mobile/v1
# file: build/app/outputs/flutter-apk/app-debug.apk
Send this file to testers; they install it after allowing "Install unknown apps". For the store, use a release build (next sections).
Branding & customisation
Changes that need no new build (from the website)
| What | Where on the website |
|---|---|
| Company name, logo and colour shown in the customer app | Owner → Settings → General (company name, logo) and the website colour. The customer app follows them every time it opens. |
| Which sign-in methods customers get | Owner → Online Booking / Settings (email code, password, SMS code) |
| Whether the company is listed in the app's search | Owner → Mobile apps → "List my company in the app" |
| Store links, QR code and company code page | Super admin / Owner → Mobile apps |
| Which push messages are sent | Owner → Configuration → Email Notification (Push Enable column and "Phone app notifications") |
Changes in the code (then build again)
| What | How |
|---|---|
| App name under the icon | android:label in android/app/src/main/AndroidManifest.xml (currently "Car Booking Driver App" and "Car Booking"). |
| Website address | apiBase in lib/config.dart, or --dart-define=API_BASE=… when building. |
| Fixed company (customer app) | --dart-define=COMPANY=your-code when building: the company screen is skipped. |
| App icon | Replace ic_launcher.png in each android/app/src/main/res/mipmap-* folder (mdpi 48, hdpi 72, xhdpi 96, xxhdpi 144, xxxhdpi 192 px) and
ic_launcher-playstore.png (512 px) in android/app/src/main/. For the customer app the own-brand script (below) makes all sizes from one logo. |
| Login logo | Replace assets/logo.png (login screen) and assets/mark.png (small mark). |
| Driver app colours | lib/theme.dart. |
| Texts / translation | Screen texts are in lib/screens/. Search for the English text and replace it. |
Push notifications (Firebase)
Without this step the apps work and show updates in the inbox, but phones do not get pop-up notifications. Push needs a Firebase project, one file in each app, and one file on the website server.
- Go to console.firebase.google.com → Create a project (Google Analytics is not needed).
- In the project: Add app → Android, once per app. Android package name: exactly your app ID (
applicationIdinandroid/app/build.gradle.kts), for examplecom.acmerentals.driverandcom.acmerentals.customer. SHA-1 is not needed. Click Register app. - Download google-services.json and put it in the app's
android/app/folder. The build picks it up automatically (the Firebase plugin is only switched on when this file exists). Do this for both apps, each with its own file. - Firebase → Project settings → Service accounts → Generate new private key. A JSON file downloads. Keep it secret.
- Server: save that JSON file on the website server outside the web folder and put its path in the website's
.env:
Keep the queue running (FCM_CREDENTIALS=/home/youruser/firebase-service-account.jsonphp artisan queue:work) or useQUEUE_CONNECTION=sync. - Rebuild the apps, install them on a real phone (push does not work on most emulators), sign in and allow notifications when Android asks (Android 13+).
- Test: in the admin panel assign the driver a job. The driver's phone should ring within a few seconds. For the customer app confirm a booking of that customer.
When users are notified
| Who | Event | Opens |
|---|---|---|
| Driver | New job assigned | The job |
| Driver | Job cancelled | The job |
| Customer | Booking confirmed by the company | The booking |
| Customer | Booking cancelled by the company | The booking |
| Customer | Reminder the day before pick-up and the day before return | The booking |
Every message to a customer is also saved in the in-app inbox (the bell), even when phone notifications are off. The company switches push messages on or off under Configuration → Email Notification (the Push Enable column for driver job alerts and the Phone app notifications card for customer booking updates).
Version numbers
The version of each app is in its pubspec.yaml:
version: 1.0.0+1
1.0.0is the version users see (versionName).+1is the build number (versionCode). Google Play requires a higher number for every upload: 1.0.0+1, 1.0.1+2, 1.1.0+3 …
Signing key (keystore)
Google Play only accepts apps signed with your own upload key. Create it once (one key can sign both apps):
# macOS / Linux
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
# Windows (PowerShell)
keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias upload
keytool comes with Java; if it is not found, use the one in Android Studio's jbr/bin folder. Choose a strong password and answer the questions (name, organisation, country).
Tell the build where the key is
In each app create android/key.properties:
storePassword=your-store-password
keyPassword=your-key-password
keyAlias=upload
storeFile=/home/you/upload-keystore.jks(Windows: storeFile=C:\\Users\\you\\upload-keystore.jks.) Add android/key.properties to .gitignore.
Edit android/app/build.gradle.kts. At the top, after the plugins { … } block:
import java.util.Properties
import java.io.FileInputStream
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}Inside android { … }, before buildTypes, add a signing config, and use it for release:
signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
storePassword = keystoreProperties["storePassword"] as String
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
}
}Replace the existing release { signingConfig = signingConfigs.getByName("debug") } block (it is marked with a TODO) — do not keep both.
Build the release
Make sure the apps point to your https website, then in each app folder:
flutter clean
flutter pub get
# for Google Play (Android App Bundle)
flutter build appbundle --release --dart-define=API_BASE=https://your-domain.com/api/mobile/v1
# file: build/app/outputs/bundle/release/app-release.aab
# optional: an installable APK (direct download, other stores)
flutter build apk --release --dart-define=API_BASE=https://your-domain.com/api/mobile/v1
# file: build/app/outputs/flutter-apk/app-release.apk
If you set the address in lib/config.dart, the --dart-define part can be left out.
Test the release APK on a real phone before uploading (flutter install or copy the APK): sign in, open each screen, take a photo, create a test booking and send a test notification.
Publish on Google Play
Publish the Driver app and the Customer app as two separate store listings.
1. Developer account
Register at play.google.com/console ($25 one time, identity verification).
- Organisation account (needs a free D-U-N-S number for your company): can publish to production directly.
- Personal account: Google requires a closed test with at least 12 testers for 14 days in a row before you can apply for production. Plan for this.
2. Create the app
Play Console → Create app: app name, default language, App (not game), Free, accept the declarations. Do this once for each app.
3. Store listing (Grow → Store presence → Main store listing)
| Item | Requirement | Suggestion |
|---|---|---|
| App name | Max 30 characters | "Acme Rentals" (customer), "Acme Rentals – Driver" (driver) |
| Short description | Max 80 characters | "Find a car, book and pay in minutes." / "Your jobs, photos and earnings in one app." |
| Full description | Max 4000 characters | List the features of the app from this guide. |
| App icon | 512×512 PNG, 32-bit | Same mark as the launcher icon |
| Feature graphic | 1024×500 JPG/PNG | Logo + a short slogan on your brand colour |
| Phone screenshots | 2–8, 16:9 or 9:16, 320–3840 px | Customer: company, cars, car page, bookings, rewards. Driver: home, job, agreement, earnings |
| Contact details | Email (website and phone optional) | Your support email |
| Category | Auto & Vehicles or Travel & Local (customer), Business (driver) |
Tip: take screenshots on the emulator (camera button in the emulator toolbar) with demo data on your website.
4. App content (Policy → App content)
| Section | Answer |
|---|---|
| Privacy policy | URL of the privacy policy page on your website |
| App access | All or some functionality is restricted → add a demo login: for the driver app an email and password; for the customer app the company code and a test email (and how the code or password is obtained) |
| Ads | No, the apps do not contain ads |
| Content rating | Fill in the questionnaire (Utility / Travel; no violence etc.) → usually "Everyone" |
| Target audience | 18 and over (renters must be adults) |
| Data safety | See Privacy & data safety |
| Financial features | None in the app: payment is on the company's own payment page |
5. Upload and release
- Testing → Internal testing → Create release → accept Play App Signing → upload
app-release.aab→ release notes → Save → Review → Start rollout. Add your testers' emails and install through the opt-in link. - Closed testing (required for new personal accounts: 12+ testers, 14 days).
- Production → Create release → upload (or promote the tested release) → choose countries → Send for review.
- Review usually takes from a few hours to 7 days. You get an email when the app is live.
- Then add the store links on the website: super admin → Mobile apps.
Updates
Raise the build number in pubspec.yaml, build a new .aab, and create a new release in Production (or a testing track first). Use staged rollout (e.g. 20 %) for big changes.
Other distribution
The release APK (app-release.apk) can also be offered as a direct download from your website, through an MDM, or on other stores
(Amazon Appstore, Samsung Galaxy Store, Huawei AppGallery). Push notifications need Google Play services on the phone (not available on Huawei phones without Google services).
Privacy & data safety
Both stores require a privacy policy URL and a description of the data the apps handle. Publish a privacy policy page on your website (the website's own privacy policy page can be used) and use these answers in Play Console → Data safety:
| Data | Collected | Purpose | Notes |
|---|---|---|---|
| Name, email, phone number | Yes | Account management, app functionality | Entered by the company (drivers) or the customer |
| Driving licence / ID photos | Yes (optional, customer app) | App functionality | "My documents" so pick-up is faster |
| Photos of vehicles and receipts | Yes (optional, driver app) | App functionality | Pick-up, return and damage photos, expense receipts |
| Signature image | Yes (optional, driver app) | App functionality | Agreement signing |
| Messages | Yes | App functionality, customer support | Contact the company, report a problem, AI helper |
| Purchase / booking history | Yes | App functionality | Bookings, payments, loyalty points |
| Payment info | No (in the app) | — | Payment happens on the company's secure payment page |
| Device / push token | Yes | App functionality | To send notifications |
| Location | No | — | Directions open the phone's maps app |
| Analytics, ads, tracking | No | — | No analytics or advertising libraries |
- Data is encrypted in transit (HTTPS).
- Data is not sold or shared with third parties for advertising.
Android permissions used
| Permission | App | Why |
|---|---|---|
| INTERNET | Both | Talk to your website |
| CAMERA | Both | Driver: photos of the vehicle and receipts. Customer: photo of licence / ID and scanning a company QR code |
| USE_BIOMETRIC | Customer | Optional fingerprint / face lock |
| Notifications | Both | Android 13+ asks the user after sign-in (only when push is set up) |
Android settings reference
What is already set in the android/ folder of the apps, for reference or when you change something by hand.
android/app/src/main/AndroidManifest.xml
<manifest ...>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<!-- customer app only -->
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<application android:label="Car Booking" ...> ... </application>
<queries>
<intent><action android:name="android.intent.action.VIEW"/><data android:scheme="https"/></intent>
<intent><action android:name="android.intent.action.DIAL"/><data android:scheme="tel"/></intent>
<intent><action android:name="android.intent.action.SENDTO"/><data android:scheme="mailto"/></intent>
</queries>
</manifest>
android/app/src/debug/AndroidManifest.xml (debug builds only)
<application android:usesCleartextTraffic="true"/>
This is why http:// works while testing but not in release builds.
android/app/build.gradle.kts (Firebase)
// Firebase push: switched on by dropping your google-services.json into android/app/
if (file("google-services.json").exists()) {
apply(plugin = "com.google.gms.google-services")
}
Code structure
Both apps
| Path | Contents |
|---|---|
lib/main.dart | Start-up, theme, chooses the sign-in or the main screens |
lib/config.dart | Server address (API_BASE), fixed company (customer app), app version |
lib/api.dart | HTTP client: token, JSON, errors, uploads and downloads |
lib/push.dart | Firebase notifications: permission, registering the phone, opening the right screen |
lib/theme.dart | Colours and styles |
lib/format.dart | Money and date helpers |
test/ | Unit tests (flutter test) |
Driver app screens (lib/screens/)
login, home, dashboard, jobs, job_detail, agreements, expenses, earnings, more.
Customer app screens (lib/screens/)
company and scan_code (find a company), login, home, dashboard, cars, car_detail, bookings,
booking_detail, booking_photos, documents, rewards, profile, contact, assistant (AI helper), notifications,
switch_company. Extra files: app_lock.dart (fingerprint / face / PIN), favorites.dart, cars_filter.dart, settings.dart.
Libraries used: Driver — http, flutter_secure_storage, image_picker, url_launcher, intl, firebase_core, firebase_messaging. Customer — the same plus local_auth (app lock) and mobile_scanner (QR codes). No analytics or advertising libraries.
To add a screen: create it in lib/screens/, load data with the client in lib/api.dart, and add the endpoint on the website in routes/api.php
(every endpoint is described in docs/mobile-api.md).
Own-brand customer app
By default the customer app is one app for many companies: the renter finds a company by name, QR code or code. A rental company that wants its own app (its own name, icon and store listing, with no company search) can have a copy built just for it.
From the customer_app folder (needs Python 3 with Pillow: pip install pillow, and Flutter on the PATH for --build):
python3 tools/build_branded.py \
--company sunrentals \
--name "Sun Rentals" \
--logo logo.png \
--api https://your-domain.com/api/mobile/v1 \
--package com.sunrentals.app \
--build apk
| Option | Meaning |
|---|---|
--company | The company code (the web address name, e.g. sunrentals for …/book/sunrentals). The app skips the company screen. |
--name | App name under the icon |
--logo | PNG with the company's logo or mark (transparent background is best). All app icons and the login logo are made from it. |
--api | Your platform's API address |
--package | Android application id and iPhone bundle id, e.g. com.sunrentals.app (letters, numbers and dots, at least three parts) |
--build | apk, appbundle or none (only create the project) |
--out | Folder for the result (default build_branded/) |
The result is a copy of the app in build_branded/<company>/. The original is never changed. A company can add its own store links under Mobile apps in its menu;
they replace the platform's links on that company's website.
Updating to a new version
When a new version of the apps is released:
- Back up your project folders (
driver_appandcustomer_app), especially yourandroid/edits (signing,google-services.json),lib/config.dartandassets/. - Update the website first if the release notes say the apps need a newer website version.
- Copy the new
lib/,pubspec.yaml,test/anddocs/over your project. Put your own values back intolib/config.dart(or keep using--dart-define=API_BASE=…, which needs no edit). - Run
flutter pub get. - Raise the version in
pubspec.yaml(see "Version numbers"), build and upload as usual.
Troubleshooting
| Problem | Solution |
|---|---|
"Flutter is not installed" / flutter: command not found | Flutter's bin folder is not in PATH. Open a new terminal after changing PATH; check with flutter --version. |
flutter doctor: Android licences not accepted | flutter doctor --android-licenses and answer y. |
| "No connection" / "Could not reach the server" on every screen | Wrong API_BASE, or the website is on http:// (release builds need HTTPS). Open …/api/mobile/v1/companies?q=a in the phone's browser to check. |
| Emulator cannot reach a local website | Use 10.0.2.2 instead of localhost. |
| Customer app: "company not found" | Check the code (the last part of …/book/<code>) and that online booking is switched on for that company. |
| Customer app: the sign-in code never arrives | The company needs working email settings (and the email may be in spam). Allow password sign-in or SMS sign-in for the company, or check storage/logs/laravel.log. |
| Driver app: "sign in with a driver account" | The account is not a driver (owners, managers and admins use the website) or the password is wrong. |
| Gradle: "Unsupported class file major version" / Java errors | Use JDK 17 or newer: flutter config --jdk-dir "<Android Studio>/jbr". |
| Build very slow or out of memory | In android/gradle.properties set org.gradle.jvmargs=-Xmx4G; close other programs. |
| Play Console: "signed in debug mode" | Complete the signing steps, then build again. |
| Play Console: "Version code 1 has already been used" | Raise the +number in pubspec.yaml. |
| Play Console: package name already exists | Choose another package name (see Set up the projects). |
| No push notifications | Is google-services.json in android/app/ of that app, matching its applicationId? Is FCM_CREDENTIALS set in the website's .env and the queue running? Was the app rebuilt and notifications allowed on the phone? Is push switched on under Configuration → Email Notification? |
| Notifications arrive late when the phone is idle | Battery optimisation on some brands (Xiaomi, Oppo, Huawei…). Users can set the app to "No restrictions" in battery settings. |
| Photos fail to upload | Raise PHP upload_max_filesize / post_max_size to 10M+ on the server. |
| Payment page does not open | Online payment must be enabled and configured for the company on the website (Settings → Payment). |
| Old logo/colours shown | Close and reopen the customer app; it refreshes the company branding on start. |
FAQ
Do I need one app per rental company?
No. One customer app serves all companies on your website: renters find the company by name, QR code or code. A company that wants its own listing can have an own-brand build (Own-brand customer app).
Can owners and staff use the apps?
Not in this version. Owners, managers and staff use the website, which is fully mobile friendly. The apps are for drivers and customers.
Where is the data stored?
Only on your website/server. The phone keeps the sign-in token (in secure storage) and a few settings such as saved favourites.
Does the app work without the website?
No, every screen loads from your website's API.
Can I change the server address without a new build?
No, the address is built into the app (API_BASE). Company name, logo and colours are not built in: they come from the website.
How do payments work?
Pay now opens the company's secure payment page in the browser (Stripe, PayPal, Paystack, Flutterwave or Razorpay); card data never passes through the app.
Can I publish the apps under my own name?
Yes — your package name, app name, icon and Google Play developer account.
Do I need a Mac?
No, Android apps build on Windows, macOS and Linux. (The iPhone apps need a Mac, see the iPhone guide.)
Can I give testers the app before it is on Google Play?
Yes: Play Console internal testing, or share an APK.
Can customers delete their account?
Yes: Profile → Delete my account in the customer app.
Support & changelog
Before contacting support, please check the Troubleshooting section and run flutter doctor.
When you contact support, include:
- Your purchase code
- App version (
pubspec.yaml) and website version - Output of
flutter doctor -v - The exact error message or a screenshot
- What you did just before the problem
Support covers installation questions, bugs and help with the steps in this guide. Customisations (new features, design changes) are not included in support but can be ordered separately. Create a support ticket here.
Changelog
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | October 2026 | First release: driver app and customer app. Driver: jobs, start / finish with odometer and fuel, photos, agreements with signature, expenses with receipt, earnings, notices, push notifications. Customer: find a company, email / password / SMS sign-in, car search, booking and payment, my bookings, extend, rate, documents, rewards, messages, AI helper, notifications, app lock, own-brand build script. |