Developing and debugging Flutter apps for iOS without a Mac

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 Travis CI — completely free! (as long as your project is on a public GitHub repository).

Building the app with Travis CI

First, you need to get your project on a public GitHub repository or create a new one and get it on GitHub.

You’ll need to create an account on Travis CI and let it access your GitHub account.

Then, create .travis.yml on the root of your project with the following contents:

os: osx 
language: generic
before_script:
- 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
script:
- flutter/bin/flutter build ios --debug --no-codesign
cache:
directories:
- $HOME/.pub-cache
before_deploy:
- pushd build/ios/iphoneos
- mkdir Payload
- cd Payload
- ln -s ../Runner.app
- cd ..
- zip -r app.ipa Payload
- popd

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 build/ios/iphoneos/app.ipa.

Make sure your .travis.yml ends like this:

deploy:
provider: releases
api_key:
secure: #your api key will be here
file: build/ios/iphoneos/app.ipa
skip_cleanup: true #important or your built app would be deleted
on:
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 .ipa file you can add draft: true to 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).

  • Plug in your iOS device to your computer
  • Run the Impactor executable
  • Click “Xcode”, then “Revoke Certificates
  • Now, drag app.ipa to the Cydia Impactor window (or use Device > Install Package…)
  • 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

Install dependencies

Make sure libimobiledevice and ideviceinstaller are installed (the latter isn’t used but Flutter will complain if it isn’t present):

On Windows, download libimobiledevice here, and ideviceinstaller here. (Click on the latest commit under History, then artifacts, binaries are located under win7-x64\bin). You also need a “which” binary, which you can download here. Add these binaries to flutter\bin, or any other location, but make sure it’s in your PATH.

On Arch/Manjaro/Antergos:

$ pacaur -S libimobiledevice ideviceinstaller-git

On Ubuntu/Mint/etc:

$ sudo apt install libimobiledevice ideviceinstaller

Modify Flutter

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.

We’ll apply these changes to Flutter

Download this file to your flutter folder (Click on “View raw” and press Ctrl+S). Then apply it: (this was tested with the beta branch)

$ cd flutter
$ git apply ios.diff

Then rebuild the Flutter tool:

Linux:

$ bin/cache/dart-sdk/bin/dart --snapshot=./bin/cache/flutter_tools.snapshot --packages=./packages/flutter_tools/.packages ./packages/flutter_tools/bin/flutter_tools.dart

Windows:

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:

  • Run flutter attach. This will wait until the app is launched and start debugging as if we’d used flutter run.
  • Open the app, and wait for Flutter to sync files.
  • You can now hot reload by pressing r and hot restart by pressing R!

Credits

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!