---
title: How to build the mobile app for Android and iOS
description: "Building your own handyman business app from the Flutter source: its profile, its icon, registering it on your site, Android and iOS."
url: "https://osdots.com/docs/handyman-booking-os-mobile-app-build/"
updated: "2026-11-03"
category: Product Documentation / Handyman Booking OS by OsDot™
---

# How to build the mobile app for Android and iOS

The folder `Flutter-App-Source/` holds the source of the Handyman Booking OS by OsDot™ app for Android and iOS. The app talks to your own installed site. The iOS app is built from the same source: OsDot builds and tests it on the iPhone simulator; you build and publish your own iOS app in Xcode, or let us do it (iOS Build & Deployment).

## Video tutorial

[Building the app](https://www.youtube-nocookie.com/embed/8mPtyBVcjBo?rel=0)

[Watch Building the app on YouTube](https://www.youtube.com/watch?v=8mPtyBVcjBo)

![The app's home for a customer.](https://osdots.com/wp-content/uploads/2026/11/handyman-booking-os-app-customer-home.png)

## Build it

1. Install Flutter 3.47.7 and run `flutter pub get` in `Flutter-App-Source/`.
2. Copy `config/production.example.json` to `config/production.local.json` and fill in your site's values (`API_BASE_URL` on your own HTTPS domain, `SITE_NAME`, `ANDROID_APPLICATION_ID`, ...). `ANDROID_APPLICATION_ID` is your own app's ID (for example `com.yourbusiness.app`), never `com.osdots.handyman`. `DEPLOYMENT_ID` is your site's **Installation identifier**: the installer shows it on its last page, **System → About this software** shows it as **Installation ID**, and it stays in `Web/config/installed.php` (`installation_id`) on your server.
3. Check the profile: `dart run bin/validate_profile.dart --platform android config/production.local.json`.
4. Android: create your own upload keystore and a private `android/key.properties` naming it (`storeFile`, `storePassword`, `keyAlias`, `keyPassword`). Never commit either file.
5. Build: `flutter build appbundle --release --dart-define-from-file=config/production.local.json`. The release build checks the profile again and refuses a development profile.
6. iOS (on a Mac): `flutter build ipa --dart-define-from-file=config/production.local.json`; the build first checks the profile with `bin/validate_profile.dart --platform ios`.

## Register the app on your site

Your site answers only the apps it knows. Once, on your server, in the site's folder (where `bin/cake.php` is), run:

`php bin/cake.php auth client add --id app.android --platform android`

It registers the Android app (`app.android`) and the iPhone app (`app.ios`) together; `php bin/cake.php auth client list` shows them. Until then the app's first sign-in answers "This app is not registered for this site". Where your host needs the PHP program's full path, use it in place of `php` (see the server requirements).

## Your own app icon

The source carries the app's own neutral icon (a house with a wrench, no brand). Replace it with your own before you publish your app:

- **Android:** `android/app/src/main/res/` — the `mipmap-*/ic_launcher.png` files (48, 72, 96, 144 and 192 px), the adaptive icon's layers `mipmap-*/ic_launcher_foreground.png` and `mipmap-*/ic_launcher_monochrome.png` (108 dp: 108 to 432 px, your mark inside the middle 66 dp circle, the rest transparent), and its background colour in `values/ic_launcher_background.xml`. Android Studio's **Image Asset** tool (right-click `res` → **New → Image Asset**) writes the whole set from one picture.
- **iOS:** `ios/Runner/Assets.xcassets/AppIcon.appiconset/` — square, opaque PNG files at the sizes its `Contents.json` names (1024 × 1024 for the App Store); or drop one 1024 px picture into the AppIcon set in Xcode.
- The launch screens: Android's `res/drawable/launch_background.xml`, iOS's `LaunchImage` set (its own `README.md` says how).

Use the same names and sizes, then build again.

The rest of the documentation is in Documentation/index.html.
