Developing and debugging Flutter apps for iOS without a Mac
It is now possible to use a macOS VM to run and debug Flutter apps on iOS devices, thanks to
usbfluxdwhich is a useful tool that redirects iOS devices connected via USB from the host to the guest (or any two machines). I wrote a script that automates all commands needed to do this. I then use VSCode directly on the VM.
However, since using a VM requires beefier computers with enough RAM for both the host and guest, I don’t think this is a replacement for what this former tutorial achieved, which worked on 4 GB of RAM and maybe even 2.
On Linux, I like using OSX-KVM, because I prefer Virt Manager, and my script is written for that specific setup (if you have a different setup, you’ll need to change the IP addresses). Sosumi is a snap package that automates all VM setup, if you use Ubuntu or like Snaps. Docker-OSX is another option, and has a good Discord community so it’s probably the easiest one to get support to troubleshoot any issues.
As for Windows, I don’t have any VM recommendations. I’m not sure if usbfluxd runs on Windows to begin with, so this may only be possible on Linux now.
If these instructions aren’t specific enough to you, or you think it would be of value to write a tutorial to replicate my setup, please let me know in the comments section of https://gist.github.com/gabrc52/2960d9905b835bdf750fc54f983d0412
Update: Flutter 1.17.0 now uses XCode instead of libimobiledevice to list devices. At the moment, you can downgrade to
Flutter 1.12.13+hotfix.9, or use the new Codemagic feature that allows you to remote control a Mac VM, and run a virtual device there (https://blog.codemagic.io/remote-access-to-virtual-mac-build-machine/)
— — —
This tutorial is now outdated, but it is still available for reference purposes, since you can still build apps this way and install them on iOS devices. What won’t work anymore from here is debugging on iOS. It’s still technically possible to debug (hot reload and hot restart) without ever touching macOS. If you are interested in working on making a new method to do exactly this, there are 2 ways I can think of:
- if anyone makes a pull request to Flutter that makes it use libimobiledevice tools instead of XCode tools (see https://github.com/flutter/flutter/issues/56511)
- maybe you could manually forward the ports via
iproxyand manually flutter attach to the port.
What is more, Flutter doesn’t allow launching a debug app from the home screen on iOS 14+ so this would be another change to fix to achieve what used to be achievable.
I don’t have the availability to do this, since what I now use is OSX-KVM and usbfluxd, so I do touch a Mac now, even if it’s not a bare metal one (see the 2022 update at the top of this post).
— — —
It is possible to hot reload and hot restart your Flutter app on your iOS devices without having to use a Mac just like you can with Android devices! Here’s how:
Get a debug build of your app running on your iOS device
You could do that with a Mac (or Hackintosh, or VM), but since we don’t have access to a macOS machine we can use one remotely via Codemagic or Travis CI — completely free! (as long as your project is on a GitHub, Bitbucket or GitLab repository).
Recommended: Building the app with Codemagic
Codemagic is recommended as it requires less setup and builds pretty fast
First, create an account or sign in to codemagic.io.
Codemagic - CI/CD for Flutter
Boost your Flutter app development with continuous integration and delivery for Flutter projects. As the only CI/CD…
Then, click the settings (gear) icon next to your app. Scroll down and click on “Build”. Make sure Mode is set to Debug, and select iOS under Build for platforms.
By default, Codemagic will test your app. Disable this feature unless you want to use it. (Thanks to Near Cz for the feedback!)
After that, build the app (Start your first build).
New: now Codemagic lets you remote control the macOS virtual machine it uses to build your app. From there, you can run a simulator, test your app, and configure it from XCode. See https://blog.codemagic.io/remote-access-to-virtual-mac-build-machine/
Codemagic will send you an
.app file via email.
Rename it so that it ends with
Extract it, and you’ll get a folder called
Create a folder called
Payload and place
Finally, compress the folder called
Payload — this will be your IPA file (you may rename it to
To continue, skip to Installing and running the app.
Alternative: Building the app with Travis CI
Note: the free version of Travis CI only supports public GitHub repositories.
You’ll need to create an account on Travis CI and let it access your GitHub account.
.travis.yml on the root of your project with the following contents:
- brew update
- brew install --HEAD usbmuxd
- brew unlink usbmuxd
- brew link usbmuxd
- brew install --HEAD libimobiledevice
- brew install ideviceinstaller
- brew install ios-deploy
- git clone https://github.com/flutter/flutter.git -b beta --depth 1
- flutter/bin/flutter build ios --debug --no-codesign
- pushd build/ios/iphoneos
- mkdir Payload
- cd Payload
- ln -s ../Runner.app
- cd ..
- zip -r app.ipa Payload
You’ll need to have the Travis command-line tools installed: (if the command below isn’t found, install RubyGems from https://rubygems.org/)
$ gem install travis # Makes sure to have the Travis CLI installed
Then, setup deploying to GitHub releases:
$ cd your_project
$ travis setup releases
When prompted for a file to upload, type
Make sure your
.travis.yml ends like this:
secure: #your api key will be here
skip_cleanup: true #important or your built app would be deleted
repo: #your repo will be here
Now, push the changes to your GitHub repo:
$ git add .travis.yml
$ git commit
$ git push
Now, your app will be built and it will be added to your GitHub releases. Wait a bit for Travis to notice that you’ve added
.travis.yml; when it starts you can track the progress of your build. When it’s done, download your
app.ipa from your project’s GitHub releases.
Note: If you don’t want to publish your
.ipafile you can add
deploy:, and it will be published as a draft on GitHub instead.
Installing and running the app
To install the IPA file, you need to download Cydia Impactor from the link below.
If you are running Windows, you need to install iTunes first. (Make sure to install the non-Microsoft store version: under “Looking for other versions?” select Windows, then scroll up and download).
Edit: a previous version of this article suggested installing the drivers bypassing iTunes installation. Apparently, that doesn’t work. (thanks to Andreas Opferkuch for pointing it out)
Cydia Impactor is a GUI for working with mobile devices. You can use this tool to install IPA files on iOS.
Update: Cydia Impactor seems to be broken at the moment. If you have a developer account, you may follow Weisser Zwerg’s tutorial (thanks for sharing!) to sign and install the app. If you have a jailbroken device, you may use AppSync unified and ideviceinstaller. There are alternative tools to Cydia Impactor, but I can’t guarantee they’re malware-free, so use them at your own risk.
- Plug in your iOS device to your computer
- Run the Impactor executable
- Click “Xcode”, then “Revoke Certificates”
- Now, drag
app.ipa(or the ZIP file you created) to the Cydia Impactor window (or use Device > Install Package…)
- You will be prompted to enter your Apple ID email and password. If it’s protected with two-factor authentication or you get an error message, you will need to create an app-specific password and use it instead of your password. See https://support.apple.com/en-us/HT204397. (thanks to Near Cz for pointing it out!)
- On your iOS device, go to Settings > General > Device Management (or Profiles & Device Management), tap your Apple ID email you just used to sign in, then Trust.
- Hooray! Our app is now installed.
Preparing your machine
ideviceinstaller are installed (the latter isn’t used but Flutter will complain if it isn’t present):
The previous link didn’t have binaries anymore, thanks to Andreas Opferkuch for sharing an alternative one!
$ pacaur -S libimobiledevice ideviceinstaller-git
$ sudo apt install libimobiledevice6 ideviceinstaller
You might also need to install these packages (thanks João Matheus):
$ sudo apt install libimobiledevice-utils libusbmuxd-tools
When detecting devices, Flutter checks whether you’re running macOS before searching for iOS devices. It also checks for XCode. Let’s remove those checks.
Note: it’s not working with the current stable (1.17.0) version. In the meantime, you can use Flutter 1.12.13+hotfix.9 instead.
Apparently, now Flutter uses XCode utilities instead of libimobiledevice, so the patch will not be as straight-forward. In the meantime, use an older version, or help contribute with the patch or another solution (fork, or a way of undoing the specific commits with the changes). I’ll update the article once this gets solved.
Download this file to your
flutter folder (Click on “View raw” and press Ctrl+S). Then apply it: (this was tested with the stable branch on late April to early May)
$ cd flutter
$ git apply ios.diff
Then rebuild the Flutter tool:
$ bin/cache/dart-sdk/bin/dart --snapshot=./bin/cache/flutter_tools.snapshot --packages=./packages/flutter_tools/.packages ./packages/flutter_tools/bin/flutter_tools.dart
bin\cache\dart-sdk\bin\dart --snapshot=.\bin\cache\flutter_tools.snapshot --packages=.\packages\flutter_tools\.packages .\packages\flutter_tools\bin\flutter_tools.dart
Preparing your project(s)
Make sure there’s a folder inside your project called
build. If it’s not present, create it!
Running and debugging
Here comes the good part!
Using an IDE (VS Code):
- Open the command palette (Ctrl+Shift+P), and select “Debug: Attach to Flutter process”.
- Open the app, and wait for Flutter to sync files.
- You can now hot reload and hot restart as usual!
Tip: If hot reload doesn’t work, hot restart first!
Using the command-line:
flutter attach. This will wait until the app is launched and start debugging as if we’d used
- Open the app, and wait for Flutter to sync files.
- You can now hot reload by pressing r and hot restart by pressing R!
Thanks to Yegor Jbanov for their post:
Have any questions or feedback? Please leave a comment!
If you liked this, don’t forget to clap, it’ll be greatly appreciated!