NoMacSign in
← Blog

Build a Flutter iOS app on Windows or Linux

Develop Flutter on Windows or Linux, prepare a reproducible iOS project, build it remotely with Xcode, and send the signed app to TestFlight.

· 10 min read


You can develop a Flutter app on Windows or Linux and publish its iOS version without owning a Mac. Dart, widgets, tests, Android, web, and desktop targets run locally. The iOS Runner, native plugins, Xcode archive, code signing, and TestFlight release still need macOS.

Keep the complete Flutter application in a reproducible repository, send it to a cloud Mac, and let the remote environment reconstruct the iOS configuration before building.

Push the Flutter application root containing both pubspec.yaml and ios/. Pushing only the iOS directory omits the Dart packages and Flutter tooling inputs required to create the native build.

What works outside macOS?

TaskWindows / LinuxRemote Mac
Write Dart and Flutter widgetsYesCan build again
Run analysis and Flutter testsYesOptional repeat
Run Android, web, or supported desktop targetYesNot required
Compile the iOS Runner and native pluginsNo XcodeRequired
Run iOS SimulatorNoRequires interactive Mac
Sign and upload to TestFlightCan requestRequired

Flutter's official iOS setup guide installs Xcode before running on an iOS device or Simulator. Flutter shares a large part of the application, but its iOS output is still a native Apple target.

Prepare a complete Flutter repository

MyApp/
├── pubspec.yaml
├── pubspec.lock
├── .fvmrc                 # recommended exact Flutter version
├── lib/
├── test/
├── assets/
└── ios/
    ├── Runner.xcodeproj/
    ├── Runner.xcworkspace/
    ├── Runner/
    └── Podfile            # when the project still uses CocoaPods
  • ·Commit pubspec.lock for an application.
  • ·Pin an exact Flutter SDK version in .fvmrc when reproducibility matters.
  • ·Declare every asset in pubspec.yaml and preserve filename case.
  • ·Commit the complete ios/ Runner project and its bundle settings.
  • ·Keep generated build directories and local signing data out of Git.
  • ·Review plugin versions and their minimum iOS deployment targets.

NoMac can select a tested Flutter version when there is no exact pin, but an exact project pin gives the clearest repeatability. The declared Dart and Flutter constraints must agree with the lockfile.

Check the iOS Runner before the first build

Set a unique bundle identifier matching the App Store Connect record. Confirm the product name, deployment target, version, build number, app icon, launch screen, supported orientations, capabilities, and permission descriptions.

Flutter plugins can bring native Swift, Objective-C, CocoaPods, or Swift Package Manager dependencies into the build. A package that works on Android can still require a newer iOS target or an Apple capability.

Run the fast checks locally

flutter pub get
flutter analyze
flutter test

Also run the app on an Android device, web browser, or supported desktop target when useful. These checks validate Dart and much of the shared interface. They do not prove that the iOS Runner, native plugins, Pods, entitlements, or signing are correct.

Connect Flutter to the cloud build

From the directory containing pubspec.yaml, authenticate:

npx @nomac/cli login

Register npx @nomac/cli mcp with your agent, then push from the same root. NoMac detects the Flutter project, restores its dependencies, prepares the iOS build configuration, and selects the workspace.

Run flutter analyze and flutter test. Confirm pubspec.lock is committed and
the Flutter version is exact. Push the complete root containing pubspec.yaml
and ios/, then run a NoMac smoke build. On failure, distinguish Dart package,
Flutter toolchain, plugin, CocoaPods, Xcode, and signing errors.

The Flutter-to-TestFlight loop

1. Smoke-build the iOS target

Call push_project and run workflow=smoke. Poll status until the build finishes. Use get_failure to retrieve the first actionable diagnosis.

2. Fix the owning layer

  • ·Dart solver failures belong to constraints and pubspec.lock.
  • ·Missing generated configuration means the Flutter preparation step did not complete.
  • ·Plugin deployment-target conflicts need compatible plugin or iOS target choices.
  • ·CocoaPods or Swift package failures belong to native dependency configuration.
  • ·Bundle ID, capability, and profile mismatches belong to signing setup.

3. Build the signed release

After the smoke build passes, run workflow=release. NoMac creates the signed archive and uploads it to App Store Connect. Wait for processing, then install through TestFlight.

4. Test the iOS-specific behavior

Verify startup, text input, safe areas, scrolling, back gestures, dark mode, Dynamic Type, permission dialogs, notifications, deep links, backgrounding, restoration, and every native plugin. Compare the behavior with Android only where the product should genuinely match.

Important limitation: Flutter add-to-app

NoMac's automatic Flutter path is for a complete Flutter application with its iOS Runner. Flutter add-to-app modules embedded inside a separate native host need a project-specific integration and are not supported by this automatic path. Use an interactive Mac or a custom CI workflow for that architecture.

Flutter's current iOS add-to-app documentation also shows that this is a separate integration flow, now moving toward Swift Package Manager for current Flutter releases.

Common mistakes

  • ·Pushing ios/ without the Flutter application root.
  • ·Omitting pubspec.lock or using a floating Flutter channel.
  • ·Depending on generated local files that a clean build cannot reconstruct.
  • ·Assuming an Android pass proves iOS plugin compatibility.
  • ·Changing the iOS deployment target to silence one package without checking user impact.
  • ·Testing only Flutter's debug behavior and never the signed release build.

Publish the Flutter app

Run review_lint, inspect privacy manifests and data collection for every plugin, prepare screenshots from the processed TestFlight build, and verify the App Store metadata. Provide review credentials if the app has login. Stage the exact build and require human confirmation before submission.

Follow the complete 2026 publishing guide for the store steps. Windows or Linux remains the Flutter development machine; the cloud Mac performs the Apple-specific part.

Ship it without a Mac.

Signed builds, TestFlight and App Store submission — driven by your agent.

Start shipping