'trainer' - the simplest way to generate a JUnit report of your iOS tests

If you're running tests for your iOS code base on some kind of Continuous Integration, you usually have to generate a JUnit file to report the test results, including error information, to your CI system. Until now, the easiest solution was to use the amazing xcpretty, which parses the xcodebuild output and converts it to something more readable, additionally to generating the JUnit report.

Since there were some difficulties with the new Xcode 8, Peter Steinberger and me had the idea to parse the test results the same way Xcode server does it: using the Xcode plist logs

trainer is a simple standalone tool (that also contains a fastlane plugin), which does exactly that: Convert the plist files to JUnit reports.

By using trainer, the Twitter iOS code base now generates JUnit reports 10 times faster.

To start using trainer, just add the following to your Fastfile:

By combining trainer with danger, you can automatically show the failed tests right in your pull request, without having to open the actual output

For more information about when to use trainer, check out the full blog article on PSPDFKit.

Introducing fastlane device grid, one-click installation, 2FA, more APK management features, and emoji deployment

In May, we focused on making pull requests more powerful and introduced enhanced deployment options. For more details, check out the full blog post on fabric.io/blog.


fastlane device grid

Tired of locally compiling your app just to test and preview a change? From now on, you can test your app straight on GitHub from the pull request using device grid.

One-click installation via the Fabric Mac app

Want to install fastlane with one quick click? You can do it directly from the Fabric Mac app. 

Two-step verification

Looking to take advantage of two-step verification for stronger security? All fastlane tools now support two factor authentication. 

APK expansion file upload and APK promote to track capability

Last but not least, thanks to awesome contributions from the community, it’s easier than ever to upload APK expansion files and promote existing beta builds to production on Google Play. 

Read the full blog post on fabric.io/blog

Be a 10x Mac user by using custom shortcuts for every application you use

One of the most common activities when using a computer is switching between applications and their windows. Unfortunately Mac OS X is optimised for casual computer users (Mission Control, using the Mouse, etc.).

Using the dock

This approach requires the mouse and wastes either screen space, or has a slow animation when using auto-hide.

Using CMD + Tab


This approach is keyboard based, however the order of the application is sorted by most recently used, which is only nice to quickly switch between 2 applications.

Additionally this technique doesn't allow you to launch a new application, but only switch between running ones.

Using Spotlight or Alfred


Great to quickly launch any application, however it's not as fast as other approaches, as it requires you to type in multiple letters.


New: Launch every application using a shortcut

When people watch me use my computer I get asked a lot how I can switch between my applications so quickly.

I'm not kidding, I have a custom keyboard shortcut for every single application I use frequently.

This way I can always switch to any application just using one keyboard shortcut. 

I use the excellent tool called BetterTouchTool, which was originally built to use custom gestures for the trackpad and mouse, however I use it mostly for my shortcuts. 

Using BetterTouchTool, it will either switch to a running application or launch it otherwise.

Some tricks:

  • ALT + [letter]: Open a specific application (e.g. ALT + n launches Notes)
  • Alt + 2: Open the screenshots directory (use this for any directory you use often)
  • Ctrl + CMD + Arrow: Move window to next monitor

Do you have other ideas for useful shortcuts? Please feel free to add them as a comment

Automatically download and upload dSYM symbolication files from iTunes Connect for Bitcode iOS apps using fastlane

When submitting iOS apps to the App Store with Bitcode enabled, your app gets recompiled by Apple, to be optimized for specific devices and architectures. While Bitcode is optional, it's more and more encouraged by Apple, and even required for watchOS and tvOS apps.

Due to the fact that recompiling happens on Apple's servers, third party crash reporters don't have access to the symbolication files, which are required to properly associate the crash stack trace with the exact files and line numbers in your source code.

The current solution to solve this for Bitcode enabled apps is to manually download the dSYM files from Apple and upload them to your crash reporting service. Downloading the files can be done either using Xcode or iTunes Connect. 

Download dSYM symbolication files using the Xcode Organizer

Download dSYM symbolication files from iTunes Connect

The problem with this approach is not only the time you spend doing this manually for every single release, but also the lack of automation. There was no way to automatically do this process after every release, or just periodically on every day, so you end up spending a lot of engineering time on repetitive tasks.

Introducing automatic fastlane dSYM download

With the latest version of fastlane, you can now easily download all available dSYM symbolication files from iTunes Connect and upload them straight to the crash reporting service of your choice.

All you have to do is define a lane (as seen above) and run:

           $ fastlane refresh_dsyms

It's easy to just run this task on your existing CI infrastructure every day or so, however you're totally free to trigger it whenever and wherever you want. 

dSYM download in action - click on the gif to start it from the beginning

You can find more information about the available options in the fastlane docs.

Currently the dSYM upload is supported by Crashlytics, Sentry and HockeyApp. If your service is still missing and they provide an API, feel free to submit a PR to add it to fastlane.

Open Source

As always, everything described in this article is completely open source under the MIT license, check out the following source files:

Getting started

If you're already using fastlane, just update your existing Fastfile and add the new refresh_dsyms lane to it.

Step 1: Install fastlane

If you haven't yet had the change to try fastlane, now is the perfect time. To quickly get started:

           $ [sudo] gem install fastlane --verbose
           $ cd your/project
           $ mkdir fastlane && touch fastlane/Fastfile fastlane/Appfile

Step 2: Update Appfile

Edit your Appfile to include your bundle identifier and iTunes Connect Apple ID.

Step 3: Update Fastfile

Update your Fastfile to include the refresh_dsyms lane (seen above). You're all set, now you can run 

Step 4: Enjoy fastlane

           $ fastlane refresh_dsyms

On the first run you'll be asked for your password, which will be stored in your local Keychain. 

You wonder what else you can add to your Fastfile? Check out the available actions to see all 170 built-in fastlane integrations, you can already use today. 

Our goal to unify fastlane tools

I’ve been working as an iOS developer for over 5 years for various companies around the world. During that time it became clear there was lots of room for improvements around mobile developer tools, and in particular, the deployment of apps. Because of that, I started implementing little tools to help me automate tedious tasks like uploading metadata for release builds or generating screenshots. Each of those tools had no connection with each other and ran as standalone commands. About 4 months after the initial release of deliver, snapshot and frameit, I noticed one common theme: All users of those tools developed their own shell scripts to trigger different deployment steps, pass on information, and ensure every step was successful.

I wanted to help developers connect all the tools they use into one simple workflow. That’s why I created fastlane.

But as the community grew and the architecture became more complex, I needed to think about how we could best build the foundation of fastlane to continue to be a tool you love to use. 

In its current setup, we ran into these problems:

  • When releasing a spaceship bugfix, it required us to do at least five releases just to roll out the change to all users
  • fastlane has its own repo just to manage the other repos called “countdown
  • The fastlane organization has over 30 GitHub repositories
  • I added 360 commits whose only purpose was to update internal dependencies between fastlane tools
  • We ended up with a lot of duplicate issues across multiple repos
  • Having 20 different travis builds to keep green, instead of just one
  • Working on a new feature or big change required us to switch to a separate branch on three different repos, which all depended on each other. Not only is it very time consuming to work on three different repo’s feature branches, but also the release takes longer: You have to merge the first PR, then do a release, before you can update the dependency of the other tool, to turn the build green and merge the next one.
  • It’s hard to decide when to release an update for each of the tools, so we built a script to show which tool has the highest number of outstanding changes to be released. Switching to a mono repo allows us to switch to a more regular release cycle

Our goal to unify fastlane tools

To solve a lot of these problems, our team decided to move all fastlane tools into one main repository. Each tool will be in a subfolder enabling you easy access to its source code.

I wanted to make this change as seamless and hassle-free as possible for everyone. With this migration, you can still use all tools directly, so your setup will continue to work as normal. This should not break any existing setups and doesn’t require any action from your side. 

Unifying fastlane means having one place for everything you need. Now, there will be one place to submit and search for issues on GitHub, one place for the documentation, one place to contribute to fastlane, and one tool to install :)

We’ll be making this move within the next couple of weeks.

Technical Details

I’d like to share some more technical information on how the switch will work and the challenges I faced.

The requirements:

  • All individual tools (like deliver, snapshot, etc.) have to be moved into the main fastlane repo
  • We want to preserve the complete history, meaning all commits across all repositories
  • All existing issues on the repositories need to be migrated to the main repo, both open and closed ones
  • I wanted to be sure that every person who contributed to fastlane in the past shows up in the Contribution Graph. fastlane wouldn’t be possible without the great community around it.

To implement all this I created a new repo (ironically) that contains all the scripts used to make the switch. You can find all the source code on fastlane/monorepo.

Moving the tools to the main repo

To move all source code to the main repo and still preserve the history with all commits, we used standard git features. You can check out the full source code on GitHub. Using this technique, all previous commits are still available, and the Contribution Graph shows all developers who ever contributed to fastlane.

Copying the GitHub issues to the main repo

There is no built-in way to migrate or merge issues to another repo. GitHub provides a great API which we used to copy over all existing issues. However the newly copied issues are not created by the original author, but by our fastlane bot instead. On the newly created issue we always mention the original authors, resulting in them being subscribed to the new issue. 
You can check out the full source code on GitHub. With this we worked on a lot of little tricks to make sure users are subscribed to the newly migrated issue and the original author is still visible. The GitHub API doesn’t allow us to post issues as the original author (for good reasons), so we solved this problem by posting the user’s information right inside the actual issue.

Ruby Gems

There are no changes with the way you install fastlane, you can still install tools e.g. using gem install deliver.

What happens to the other GitHub repositories

For SEO reasons we will keep the other repositories around, however the long term plan is to remove them and have everything in the main repo. The old repos will link to the new mono repo, therefore all issues and pull requests will be closed and moved over to the fastlane main repo.

Upgrading fastlane support to the next level 🚀

We took this opportunity to also improve the way we handle issues as a team. Our goal is to be faster and better at responding to all incoming GitHub issues and reviewing pull requests. 

Up until a few months ago, I was managing everything alone, resulting in my not responding to everyone in a timely matter. Thanks to Twitter & Fabric, the fastlane team has grown tremendously in the last few weeks, allowing us to offer world-class help for our thriving community. We want to treat support as a first class citizen and provide the best experience possible.

We’re just getting started: being part of Fabric means a passionate dedicated team to offer the best support & future experience for fastlane customers.

With that in mind, we have a lot of inactive issues and pull requests spanning the last year when I was still working on this project in my free-time. Out of the 829 open issues across all repos, 273 issues haven’t had any activity within the last 3 months. 

After the migration, we will be constantly looking at all issues to make sure the process is improving. We’ll also be commenting on those inactive issues to see if the problem is still happening for those of you who submitted pull requests. This enables us to be much more responsive to new issues and have a better overview on what to focus our time on. 

The Future

This is one of the most impactful changes to fastlane yet. While there’s a lot of information, it’s very important to the entire team to communicate what we are up to. This migration shows our commitment to innovation and creating the future of fastlane .

I’m confident that this change will make yours and our lives much easier and will save us all a ton of time in the future. We’d love your feedback on this, Tweet at us at any time! :) 

Thoughts on iOS build tools

Up until now you had 2 good ways to build and sign your application from the command line:

  • Use the built-in xcodebuild command
  • Use the third party tool shenzhen

Both approaches have their problems


When using xcodebuild you have to fiddle around with a long list of available parameters:

That's not something you remember and just enter every time you want to build an ipa file. The command above will generate a huge amount terminal output (talking > 10MB). For every source file that gets complied xcodebuild prints out around 60 lines of information you don't really care about:

The best way to fix the output annoyance is to use xcpretty in which you can pipe the xcodebuild ouput.


shenzhen was the easiest way to build your iOS application: It took care of generating the xcodebuild commands to build your application. But instead of showing a clean output while building, it omitted the complete output of the whole process. 

The main issue with shenzhen was the information you received when you run into an error: 

You know what you'd need to do to solve this issue? No, it's not clear, you don't get any information that helps you fix this issue. That's a simple code signing issue, in which the project defines a provisioning profiles that doesn't exist.

shenzhen is a great tool, but hasn't received any updates recently. With fastlane I used a fork of shenzhen to fix some bugs. After a time I decided to build 'gym', a tool which should replace the building part of shenzhen. (shenzhen also does distribution to beta testing services)

Improving the process

In my opinion it's really important a tool does different things depending on the outcome:

  • When the tool succeeded, the user doesn't need a lot of output/information, except that everything worked fine
  • When something went wrong while building, the user should get as much relevant information as possible to make it easy to quickly fix the issue.

Tools should actively help the user resolve common issues. By showing as much useful information as possible and even telling the user how to fix it, a tool automatically becomes much more useful.

Tools can automatically detect all kinds of issues and help the user fix them really fast:

When gym succeeds the terminal output is minimalistic but still shows relevant and useful information while processing

Another important point is being compatible with existing technologies. With gym for example I want the user to still be able to use the Xcode Organiser to distribute the archive or dSYM file


When writing about developer tools I don't want to forget the famous "Fix Issue" button. 

 How can we improve it? 

The most important things a developer tool should do

  • Expose information about what Xcode is going to try when you click "Fix Issue"
  • Show a log of what was tried and what failed
  • If possible show the user how to fix an issue manually

In the example of gym you get every shell command that is being executed printed out so you can manually try fixing something in case the build process fails.

If you need even more information, the you can use --verbose flag.


Besides standard features like sensible defaults and convention over configuration, I think it's important the user knows what's going on with the tool. This allows the users to debug issues themselves. By being transparent you build up trust. Developer see what the tool is doing.

You can check out gym on GitHub: https://github.com/fastlane/gym