CircleCI 2.0 and the iOS Code Signing

without the Fastlane Match

Marat Saytakov
Feb 7, 2018 · 3 min read

In TechOps we use CircleCI to test and deploy iOS apps. The original CircleCI 1.0 is pretty good, but they rolled out version 2.0, and stopped support for future Xcode releases on 1.0.

When I started migrating to 2.0, I faced with this note:

On CircleCI 2.0 the only supported way to do CodeSigning is to use Fastlane Match as described in the above documentation.

I was so surprised. Are you surprised?

I like Fastlane. This is a good thing happened to iOS dev tools. But I don’t want to use Match on CI, because:

  • it needs a separate repo with encrypted certificates. Ok. But the passphrase still should be stored in CI environment variable settings. So why the identities shouldn’t?
  • an unnecessary step relying on the Internet connection
  • this is an unpredictable dependency on a Google product; we don’t know how long it will live or die

One can say, if we move to Match, then we’re not dependent on a CI provider anymore. But that’s not true, migration docs suggest to use a special action:

While other fastlane actions are easily interchangeable with a set of xcodebuild commands, a Match step provides a concept of dealing with signing identities and provisioning profiles, that may become outdated at some point.

Anyway, I’ve figured out how to use code code signing without Match.

Solution

TL;DR: It’s hard to say, but you have to encode your certificates and provisioning profiles to a base64 representation, set them to the env, and then decode them back to files.

macOS Keychain

Export the certificate and the private key as p12 file, set a certificate password.

Get Provisioning Profile (signed with that identity) from Apple Dev Center.

Encode Files

In macOS Terminal to encode Certificates.p12 to base64, and copy the result to the Clipboard:

$ base64 -i Certificates.p12 | pbcopy

And use the same command to decode `.mobileprovision` file.

CircleCI Contexts

To store env values in 2.0 we have to use Contexts. Go to Org Settings → Contexts → Resources → Add a Resource.

Add variable with some name (e.g. Certificates) and paste previously copied value to a Value field.

CircleCI Config YAML

Now, we need to get these files back.

In .circleci/config.yml use the following steps:

Now we have certificates and profiles in a right place.

Import Certificate

Now we need to add signing identity into the CI Keychain, that doesn’t exist on CircleCI anymore.

I mentioned a setup_circle_ci special action, and we’ll use that to create a keychain, as we know from its source code. We have to add the following before_all lane:

Line 4 sets up a local keychain. Line 5 imports certificates into the keychain. Make sure to set CERTIFICATE_PASSWORD environment variable in CircleCI project settings. Other variables (lines 6 and 7) are already set after line 4.

Conclusion

Whew. Finally we’ve gotten rid of next error anymore:

Code Signing Error: No profile for team 'ABC' matching 'App Store' found: Xcode couldn't find any provisioning profiles matching 'ABC/App Store'
Code Signing Error: Code signing is required for product type 'Application' in SDK 'iOS 11.2'

It was so hard to realize that the last approach from 1.0 doesn’t work anymore and to made up all those workarounds. I hope CircleCI team would introduce a better solution soon.

P.S. Please find me on twitter.com/m4rr if you have any questions.

Marat Saytakov

Written by

iOS developer && traveler, https://m4rr.ru

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade