Overview
Smart FSM Mobile Apps are two iPhone apps for the Smart FSM SaaS field service website: FSM Technician for your field team and FSM Client for your customers. Owners, managers and the super admin keep using the website. The apps talk only to your website, so all data stays on your server.
What is in the package
| App | Folder | Package name | For |
|---|---|---|---|
| FSM Technician | technician_app/iphone_app/ | com.smartfsm.fsmTechnician | Field staff (users of type employee) |
| FSM Client | client_app/iphone_app/ | com.smartfsm.fsmClient | Your customers (users of type client) |
Inside each folder:
| Folder / file | What it is |
|---|---|
lib/ | The app's source code (Flutter / Dart): api/, state/, util/, screens/, widgets/. |
ios/ | The iPhone project, already set up (permissions, icons, links, signing hooks). |
assets/ | icon.png and icon_foreground.png (app icon). |
test/, tool/ | Automated tests and the script that makes store screenshots. |
docs/openapi.yaml | The website API the app uses (for developers who want to extend it). |
pubspec.yaml | App version and the list of libraries. |
documentation/ | This guide. |
Features
FSM Technician
| Area | What the technician can do |
|---|---|
| Home | Today's jobs, overdue alert, next job, shift clock, quick actions and the AI plan for the day (when AI is on for the company). |
| Jobs | Today / Open / Done tabs, search, calendar view, QR scan of equipment labels. |
| Job | Client and site details with call, email and navigate; GPS check-in / check-out; checklist; parts used (stock is deducted); equipment service history; before / after photos; notes with voice dictation and AI tidy-up; AI photo check; client signature; hold / start; complete job (the company's rules apply: signature required, locked statuses, automatic invoice). |
| Time | Clock in / out with a running timer, shift history, trips (mileage), time-off requests. |
| Inbox | Push notifications for new and changed jobs that open the right job. |
| Offline | Jobs cached; every change is queued and uploaded in order when online (More → Waiting to upload). |
FSM Client
| Area | What the customer can do |
|---|---|
| Home | Amount due, "technician is on site", overdue invoices, estimates waiting, next visit, jobs to rate, quick actions. |
| Services | New service request (description, equipment, urgency, preferred day and time, up to 5 photos, saved and sent later if offline); request and job lists. |
| Job | Status, progress timeline, who is coming and when, work and parts done, before / after photos, rating. |
| Billing | Estimates: approve with a drawn signature or decline. Invoices: lines, tax, credit, payments, balance, pay online (opens the company's secure payment page, already signed in). |
| Equipment | My equipment with service history and warranty, QR scan, service contracts. |
| Inbox | Push notifications for estimates, invoices, visits and finished jobs. |
Common to both
- Sign-in with email and password, two-factor code, and biometric lock.
- Company code, QR code and invite-link sign-in with the company's branding.
- Inbox, profile, password change, offline queue.
Requirements
Your computer (to build the app)
| Item | Needed |
|---|---|
| System | A Mac with a recent macOS (iPhone apps can only be built with Xcode) |
| Xcode | Latest stable version from the Mac App Store, with the command-line tools |
| Flutter SDK | Stable channel, Dart 3.13 or newer |
| CocoaPods | sudo gem install cocoapods (or Homebrew) |
Phones that can run the app
iPhone with iOS 15 or newer.
Accounts
- Apple Developer Program membership (yearly fee) to run on a real iPhone for more than a week and to publish.
- Firebase project (free) for push notifications, and an APNs key from Apple.
Website
Smart FSM SaaS v2.0 or newer on HTTPS, with the migrations run.
Install Xcode & Flutter
- Install Xcode from the Mac App Store, open it once and accept the licence. Then:
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer sudo xcodebuild -runFirstLaunch - Install Flutter from docs.flutter.dev and CocoaPods.
- Check everything:
Flutter and Xcode should show green ticks.flutter doctor
Prepare the website
- Update the website to Smart FSM SaaS v2.0 or newer and run
php artisan migrate. This adds the tables the apps need (tokens, devices, job notes, request photos). - Make sure the site opens on HTTPS and
APP_URLin.envis the real address. - As super admin, open Mobile Apps and fill in the store links and the minimum app version. You can also switch the apps off for one company or for maintenance.
- As owner, open Settings → Branding & Mobile App: set the company code, logo and colour. Your invite link, QR code and store buttons appear on your public website.
- For photos: set
upload_max_filesize = 12Mandpost_max_size = 40Minphp.ini(a request can carry 5 photos).
Open the project
Unlike a bare Flutter source package, the iPhone project is already included, so there is no setup script. Unzip, then in each app folder:
cd technician_app/iphone_app # or client_app/iphone_app
flutter pub get
The identifiers are com.smartfsm.fsmTechnician and com.smartfsm.fsmClient. Change them to your own before you publish (Xcode → Runner → Signing & Capabilities → Bundle Identifier):
- Xcode:
Runnertarget andRunnerTeststarget - The app name under the icon:
CFBundleDisplayNameinios/Runner/Info.plist
Point the app at your website
Give the website address when you build; it is then fixed in the app:
flutter run --dart-define=API_BASE_URL=https://your-company.example
If you leave it out, the sign-in screen asks for the server address, which is handy while testing.
Run on an iPhone or simulator
Xcode signing
- Run
flutter pub get, thencd ios && pod install. - Open
ios/Runner.xcworkspace(not the .xcodeproj) in Xcode. - Select Runner → Signing & Capabilities, tick Automatically manage signing, choose your Team and set your own Bundle Identifier.
- Add the capabilities Push Notifications and Background Modes → Remote notifications.
Simulator
open -a Simulator
flutter run --dart-define=API_BASE_URL=https://your-company.example
Camera, push notifications and Face ID do not work fully in the simulator.
Your iPhone
Connect it, trust the computer, turn on Developer Mode (Settings → Privacy & Security) and run flutter run. The first time, trust your developer certificate under Settings → General → VPN & Device Management.
Testing against a local website (http)
Debug builds accept plain http:// (use your Mac's address, for example http://192.168.1.20/…). Release builds require HTTPS.
Company code & branding
Changes that need no new build (from the website)
| What | Where |
|---|---|
| Company logo, name, colour, welcome text | Owner → Settings → Branding & Mobile App. The app shows them before sign-in and after. |
| Company code, invite link, QR code | Same page. The invite page /join/<code> has an Open the app button for each app. |
| Store links, minimum version, maintenance, per-company access | Super admin → Mobile Apps |
| Which tabs the client sees | Owner's visible modules (requests, estimates, invoices, equipment, contracts) |
The app sends X-App-Version; the website answers 426 update_required below the minimum version, 503 maintenance during maintenance and 403 app_disabled when the company's apps are switched off.
Changes in the code (then build again)
- App icon: replace
assets/icon.pngandassets/icon_foreground.png, thendart run flutter_launcher_icons. - App name under the icon:
CFBundleDisplayNameinios/Runner/Info.plist. - Default brand colour:
defaultBrandColorinlib/util/theme.dart(used until a company is chosen). - Invite links that open the app:
fsmtech://join/<code>andfsmclient://join/<code>work out of the box. To make normalhttps://your-server/join/<code>links open the app too, add the Associated Domains capability (applinks:your-server) and anapple-app-site-associationfile at/.well-known/.
Push notifications (Firebase + APNs)
Optional. Without it everything works and the in-app inbox still fills up; only the phone pop-ups are missing.
A. Apple: APNs key
Apple Developer → Certificates, Identifiers & Profiles → Keys → create a key with Apple Push Notifications service (APNs). Download the .p8 file and note the Key ID and Team ID.
B. Firebase
- In the Firebase console add two iOS apps with the bundle identifiers of the Technician and Client apps.
- Download each
GoogleService-Info.plistand add it toios/Runnerin Xcode (tick Copy items if needed). - Project settings → Cloud Messaging → upload your APNs key (.p8) with Key ID and Team ID.
C. Website
Firebase console → Project settings → Service accounts → Generate new private key. Save the JSON on the server and set in .env:
FCM_CREDENTIALS=/full/path/to/service-account.json
When users are notified
A push is sent for every inbox item: job assigned or changed, estimate or invoice created, technician arrived, job completed. Phones that no longer exist are removed automatically.
AI features
The AI features in the apps (AI plan for the day, tidy up notes, photo check) use the AI service the owner connects on the website under Settings → AI (OpenAI, Anthropic Claude, Google Gemini or any compatible service). The key is stored encrypted on the server; the app never sees it.
- AI follows the subscription plan: if the plan has no AI, the AI buttons are hidden.
- There is a daily request limit per company.
- The photo check needs an AI service that can read pictures.
Version numbers
Set the version in pubspec.yaml: version: 1.0.0+1. 1.0.0 is the version people see; +1 is the build number. Increase the build number for every upload to App Store Connect.
Create the app in App Store Connect
- Apple Developer → Identifiers: register your bundle identifiers (or let Xcode do it).
- App Store Connect → Apps → + → New App. Choose the bundle identifier, name (FSM Technician / FSM Client), language and a SKU.
Build & upload
flutter build ipa --release --dart-define=API_BASE_URL=https://your-company.example
Then open build/ios/archive/Runner.xcarchive in Xcode (Window → Organizer) and choose Distribute App → App Store Connect → Upload, or use the Transporter app with the .ipa. Do this for both apps.
TestFlight (beta testing)
After processing, the build appears in App Store Connect → TestFlight. Add internal testers (up to 100, no review) or external testers (short Apple review).
Publish on the App Store
- App information & pricing: category (Business), privacy policy URL, price (free).
- App Privacy: describe the data the app collects (see Privacy & data safety).
- Version page: description, keywords, support URL, screenshots (6.9" and 6.5" sizes; the
tool/screenshots.shscript makes sample pictures) and select the uploaded build. - App Review information: give a demo account (employee for the Technician app, client for the Client app) and the company code, so the reviewer can sign in.
- Submit for review.
Common rejection reasons and how to avoid them
- Reviewer cannot sign in: always provide a working demo account and company code.
- Missing privacy text: every permission has a description in
Info.plist; keep them accurate. - Payments: invoices are paid for a real-world service on the company's secure web page, which Apple allows.
Privacy & data safety
You publish the apps, so you are responsible for the store forms. What the apps handle:
| Data | Why |
|---|---|
| Name, email, phone, company | Account and job contact details |
| Location (Technician only) | Record GPS check-in and check-out at a job; only when the technician taps the button |
| Photos and signatures | Job evidence and estimate approval, uploaded to your website |
| Microphone and speech (Technician only) | Dictate job notes |
| Device push token | Send notifications |
All data is sent to your website over HTTPS. The apps contain no ads and no third-party analytics. Users can ask the company to delete their data.
iPhone permissions used
| Key in Info.plist | App | Text shown |
|---|---|---|
NSCameraUsageDescription | Both | Photos and scanning equipment labels |
NSPhotoLibraryUsageDescription | Both | Choose photos to attach |
NSFaceIDUsageDescription | Both | Unlock the app with Face ID |
NSLocationWhenInUseUsageDescription | Technician | Record where you check in and out |
NSMicrophoneUsageDescription, NSSpeechRecognitionUsageDescription | Technician | Dictate job notes |
Code structure
lib/
main.dart, config.dart, core.dart start-up, app settings, one import for the shared code
api/ API client, repositories and models (jobs, invoices, users ...)
state/ sign-in, offline queue, cache, connectivity, push, local database
util/ theme, formatting, GPS helper, app config
screens/ every screen (home, jobs, billing ... plus login, lock, inbox and More)
widgets/ reusable pieces (shell with bottom bar, cards, signature pad, media picker)
test/ unit and screen tests (run offline with a fake server)
tool/ screenshots for the stores (tool/screenshots.sh)
docs/ API contract (openapi.yaml) and screenshots
The Android and iPhone projects of the same app share the same lib/. If you change one, make the same change in the other. mobile_app/check-sync.sh tells you if they drifted apart. Run the tests with flutter test and the checks with flutter analyze.
Updating to a new version
- Update the website first (apps are only compatible with a website of the same or a newer version).
- Back up your own changes, unzip the new package and copy your changes back (
lib/, icon, package name,GoogleService-Info.plist, signing settings). - Run
flutter pub get, raise the build number and build again.
Troubleshooting
| Problem | What to do |
|---|---|
| "Company not found" | Check the code, and that the owner's website is reachable on HTTPS from the phone. |
| "Could not reach the server" | Check API_BASE_URL, SSL certificate and that /api/v1 opens on the website. Debug builds may use http://, release builds need HTTPS. |
| "Update required" / "Maintenance" | Super admin → Mobile Apps: lower the minimum version, or turn maintenance off. |
| "Apps are switched off for your company" | Super admin → Mobile Apps → enable the company. |
| Photos fail to upload | Raise upload_max_filesize and post_max_size in php.ini. |
| No push notifications | Check FCM_CREDENTIALS on the server and the APNs key in Firebase and the Push Notifications capability; sign in again on the phone. |
| Website error 500 after update | Run php artisan migrate on the website. |
flutter pub get fails | Update Flutter (flutter upgrade) so Dart 3.13 or newer is installed. |
pod install fails | Run cd ios && pod repo update && pod install. |
| "No signing certificate" | Choose your Team in Xcode → Signing & Capabilities. |
FAQ
Do I need to publish a separate app for each company?
No. One build of each app serves every company; people choose theirs with the company code.
Can the apps work without the website?
No. They are companions to the Smart FSM SaaS website and use its API.
Can I publish the apps under my own name?
Yes: your package name, app name, icon and store account.
Do I need a Mac?
Yes, iPhone apps can only be built with Xcode on a Mac (or a cloud Mac service).
Can I give testers the app before it is in the store?
Yes: TestFlight.
Is a payment taken inside the app?
No. The app opens the company's secure payment page in the browser; card data never passes through the app.
Support & changelog
Before contacting support, check Troubleshooting and run flutter doctor -v.
When you contact support, include: your purchase code, the app version (pubspec.yaml) and website version, the output of flutter doctor -v, the exact error message or a screenshot, and 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 but can be ordered separately.
Changelog
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | October 2026 | First release: FSM Technician and FSM Client apps. Jobs, GPS check-in, photos, signatures, time and trips, offline mode, service requests, estimate approval, online payment, equipment, push notifications and inbox, company code / QR sign-in with company branding, AI plan for the day. |