CircleCI 2.0 and the iOS Code Signing
without the Fastlane Match
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.