iOS Build

iOS builds require macOS with Xcode and an Apple Developer Program membership ($99/year) for App Store distribution.

One-time setup

  1. Install Xcode from the Mac App Store, open it once to finish component setup.
  2. sudo xcode-select --switch /Applications/Xcode.app
  3. flutter doctor should show a green iOS toolchain.

Configure signing

  1. Open the project in Xcode:
   open ios/Runner.xcworkspace
  1. Select the Runner target → Signing & Capabilities.
  2. Choose your Team. The bundle identifier is already set by tool/apply_config.dart to the value from your admin panel.
  3. If you use push notifications: add the Push Notifications capability and enable Background Modes → Remote notifications.
  4. If you use deep links: add the Associated Domains capability with applinks:yourdomain.com for each deep-link domain.

Build & upload

Test on a device/simulator:

flutter run

Release build + upload:

flutter build ipa --release

Then open build/ios/archive/Runner.xcarchive in Xcode → Distribute App → App Store Connect (or upload the .ipa from build/ios/ipa/ with the Transporter app).

Push notifications on iOS

FCM needs an APNs key: Apple Developer → Certificates → Keys → create an APNs Auth Key (.p8), then upload it in Firebase Console → Project Settings → Cloud Messaging → Apple app configuration. Without this step iOS pushes will not arrive even though Android works.

Enter your Apple Team ID (Developer account → Membership) on the admin Applications page, re-download the configuration package and upload the generated website/.well-known/apple-app-site-association file to your website — served over HTTPS, Content-Type: application/json, no file extension.

Permissions compiled into the binary

ios/Podfile ships with a # --- appforge:permissions --- block that decides which permission handlers are compiled in. tool/apply_config.dart rewrites it from your admin panel's Permissions page, so the binary only references the APIs your app actually uses.

This matters: with every handler compiled in, App Store review sees references to contacts, calendar, health and similar frameworks that have no usage description, and rejects the upload with ITMS-90683: Missing Purpose String.

Keep the marker comments intact, and re-run dart run tool/apply_config.dart after changing permissions in the panel. If you edit the Podfile by hand, run pod install from the ios/ folder afterwards.

Usage descriptions

Info.plist usage texts (camera, microphone, location, photos, Face ID) are inserted automatically from the admin Permissions page — App Store review rejects apps with missing or generic texts, so write honest, specific sentences.