Flutter Community
Published in

Flutter Community

Developing and debugging Flutter apps for iOS without a Mac

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/)

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.

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 .zip.

Extract it, and you’ll get a folder called Runner.app.

Create a folder called Payload and place Runner.app there.

Finally, compress the folder called Payload — this will be your IPA file (you may rename it to .ipa).

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.

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).

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)

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

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:

The previous link didn’t have binaries anymore, thanks to Andreas Opferkuch for sharing an alternative one!

Download imobiledevice binaries from here. 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 libimobiledevice6 ideviceinstaller

You might also need to install these packages (thanks João Matheus):

$ sudo apt install libimobiledevice-utils libusbmuxd-tools

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.

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.

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 stable branch on late April to early May)

$ 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!

--

--

--

Articles and Stories from the Flutter Community

Recommended from Medium

Too Many Redirects Error While Enabling SSL In Wordpress

Finding the sum of digits of a number until the sum becomes a single digit.

Java Nested For Loop with Simple Example — Simple Way to Learn

CSS Weekly Issue 22

Unit testing in Python: Part 2

The end of Journey “Kingdom of Lore”

Lambda function in python:

The Self Driving Product — Part 3: Autonomous Products

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Gabriel Rodríguez

Gabriel Rodríguez

More from Medium

Flutter bloc for beginners

Flutter environment

Change App Launcher Icon and Name in Flutter (Android & iOS)

Flutter Testing— Understand Unit, Widget, and Integration Testing