Long story about continuous delivery for Flutter: Build and upload iOS Artifacts on Pipelines Nikolay Dymura Follow Mar 4 · 7 min read

In this article, we are going to talk about how we can complete all our previous work about providing iOS assemblies and move everything to GitLab pipelines.

We have one major issue here — it’s impossible to build iOS applications somewhere else except macOS. So what options do we have to solve it? You could buy a Mac Mini and use it for build purposes. If you can afford it, it may be the simplest variant.

But you may ask, what if I have a lack of money or just don’t want to buy a computer? You can use a virtual machine on your host machine or you can just rent it online. There are a lot of services that allow you to rent a dedicated computer with macOS and use it till you need it. It’s a good option if you want to save money. In general, the price can be from $30 and up to $100 per month, so if you find out that you don’t need it anymore you can just close the subscription. Look at HostMyApple or MacInCloud.

I’m going to show you set up on a local computer, but be sure that everything will be the same for hosted-one. As you can guess you need Xcode installed on this computer. You could easily do it using AppStore. Moreover, you need to install the Flutter SDK. What else do you need?

You need all the command-line tools for Xcode to be installed.

xcode-select --install

I recommend you to create a new flutter project and run it on an iPhone simulator on this computer. Only after that, you can be sure your setup is successful and keep going.

We need to create our custom runner, that we can use to run our jobs. You need to install GitLab runner on the current computer and connect it with your account. I’m going to use brew to install it, but you can do it also manually as in the official guide.

brew install gitlab-runner

brew services start gitlab-runner

Now we need to register our build machine. Go to your repository settings, find CI/CD option and expand Runners.

By default, you have no active runners there, but you have a short guide with three steps on how to add a new one. And as you can see, we’ve already done the first step.

To register GitLab runner you can use the interactive shell, and pass value by value but I prefer to do it in one command. First, we export the TOKEN variable to store token value from step 3 there. GitLab chooses runner for the job by matching tags, that's why it is good to define some. I’ve defined three tags, you should use a comma to separate them.

export TOKEN= gitlab-runner register --non-interactive --executor shell --shell bash --url 'https://gitlab.com/' --registration-token ${TOKEN} --description 'Runner to build Flutter apps' --tag-list demo-fastlane-mac-os,demo-ios-flutter,demo-ci-cd-flutter

If you use interactive, you could see the next message:

Please enter the executor: virtualbox, docker+machine, kubernetes, docker, shell, ssh, docker-ssh+machine, custom, docker-ssh, parallels.

In my case, as you can notice, I’ve chosen shell. Nevertheless, you can select something else, like ssh or virtualbox.

Now you need to install and run runner, it’s required only if you do it for the first time. If you receive error message ‘Failed to install gitlab-runner: Init already exists’ you can ignore it and keep going.

gitlab-runner install

gitlab-runner start

Here is a very important thing that you have to do: activate a runner. If you see that your runner has a gray icon, you can fix it running this command. Of course, it will help only if all previous steps were completed successfully.

gitlab-runner verify

Now you must see that your project has one activated runner. We are going to use it by setting tags for our jobs. Every runner is locked to a single project, you can change it in the future by pressing edit on the image below and unselect this option.

Next, we need to define environment variables. Fastlane needs them to download profiles and upload assembly. You need to define four new variables: CODE_SIGN_IDENTITY, TEAM_ID, FASTLANE_USER, FASTLANE_PASSWORD.