Code signing for personal accounts

How to set up code signing for personal accounts

Note: This guide is written specifically for users with Personal accounts. While these methods can certainly be applied to workflows in Team accounts, we encourage Team account users to make use of the greatly simplified iOS Code Signing, MacOS Code Signing and Android Code Signing methods.

All iOS, macOS and Android applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. This document will guide you through the necessary steps to sign your app if your workflows are configured to use the codemagic.yaml file. If you are using our Flutter Workflow Editor, please consult the relevant guides for iOS, Android or macOS.

Generating a keystore

You can create a keystore for signing your release builds with the Java Keytool utility by running the following command:

keytool -genkey -v -keystore codemagic.keystore -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic

Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called codemagic.keystore in the directory you’re in. The key is valid for 10,000 days.

Warning: Keep the keystore and the key.properties files private; do not check them into public source control.

Signing Android apps using Gradle

Modify your android/app/build.gradle as follows:

...
  android {
      ...
      defaultConfig { ... }
      signingConfigs {
          release {
              if (System.getenv()["CI"]) { // CI=true is exported by Codemagic
                  storeFile file(System.getenv()["CM_KEYSTORE_PATH"])
                  storePassword System.getenv()["CM_KEYSTORE_PASSWORD"]
                  keyAlias System.getenv()["CM_KEY_ALIAS"]
                  keyPassword System.getenv()["CM_KEY_PASSWORD"]
              } else {
                  keyAlias keystoreProperties['keyAlias']
                  keyPassword keystoreProperties['keyPassword']
                  storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
                  storePassword keystoreProperties['storePassword']
              }
          }
      }
      buildTypes {
          release {
              ...
              signingConfig signingConfigs.release
          }
      }
  }
  ...

Configuring Environment variables

The environment variables referenced by the build.gradle need to be stored in the Codemagic UI. A detailed explanation on how Environment variables and groups work can be found here.

The keystore file, like all binary files, has to be base64 encoded before storing its value.

For Linux machines, we recommend installing xclip:

sudo apt-get install xclip
cat codemagic.keystore | base64 | xclip -selection clipboard

Alternatively, you can run the following command and carefuly copy/paste the output:

openssl base64 -in codemagic.keystore
Tip: When copying file contents always include any tags. e.g. Don’t forget to copy -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- too.

On macOS, running the following command base64 encodes the file and copies the result to the clipboard:

cat codemagic.keystore | base64 | pbcopy

For Windows, the PowerShell command to base64 encode a file and copy it to the clipboard is:

[Convert]::ToBase64String([IO.File]::ReadAllBytes("codemagic.keystore")) | Set-Clipboard
  1. Open your Codemagic app settings, go to Environment variables tab.
  2. Enter CM_KEYSTORE as the Variable name.
  3. Paste the base64 encoded value of the keystore file in the Variable value field.
  4. Enter a variable group name, e.g. keystore_credentials. Click the button to create the group.
  5. Make sure the Secure option is selected so that the variable can be protected by encryption.
  6. Click the Add button to add the variable.
  7. Continue by adding CM_KEYSTORE_PASSWORD, CM_KEY_ALIAS and CM_KEY_PASSWORD
  8. Add the CM_KEYSTORE_PATH variable with the value $CM_BUILD_DIR/codemagic.keystore
Tip: Store all the keystore variables in the same group so they can be imported to codemagic.yaml workflow at once.

Environment variables have to be added to the workflow either individually or as a group. Modify your codemagic.yaml file by adding the following:

workflows:
  android-workflow:
    name: Android Workflow
    # ....
    environment:
        groups:
            - keystore_credentials

Environment variables added with the Secure option checked are tranferred to the build machine encrypted and are available only while the build is running. The build machine is destroyed at the end.

The content of the base64 encoded files needs to be decoded before it can be used. Add the following script to your codemagic.yaml scripts section:

workflows:
  android-workflow:
    # ....
    environment:
        # ....
    scripts:
      - name: Set up keystore
        script: |
          echo $CM_KEYSTORE | base64 --decode > $CM_KEYSTORE_PATH

Creating the App Store Connect API key

Signing iOS applications requires Apple Developer Program membership.

It is recommended to create a dedicated App Store Connect API key for Codemagic in App Store Connect. To do so:

  1. Log in to App Store Connect and navigate to Users and Access > Keys.
  2. Click on the + sign to generate a new API key.
  3. Enter the name for the key and select an access level. We recommend choosing App Manager access rights, read more about Apple Developer Program role permissions here.
  4. Click Generate.
  5. As soon as the key is generated, you can see it added to the list of active keys. Click Download API Key to save the private key for later. Note that the key can only be downloaded once.
Take note of the Issuer ID above the table of active keys as well as the Key ID of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI.

Obtaining the Certificate private key

To sign iOS apps, you can use the private key of an iOS Distribution certificate that has already been created in your Apple Developer Program account.

Alternatively, you can create a new private key on your Mac and the Codemagic CLI will create a new iOS Distribution certificate in your Apple Developer Program account for you.

You can create a new 2048 bit RSA key by running the command below in your terminal:

ssh-keygen -t rsa -b 2048 -m PEM -f ~/Desktop/ios_distribution_private_key -q -N ""

This new private key will be used to create a new iOS Distribution certificate in your Apple Developer Program account if there isn’t one that already matches this private key.

  1. On the Mac which created the iOS distribution certificate, open the Keychain Access, located in the Applications and Utilities folder.
  2. Select the certificate entry which should be listed as iPhone Distribution: company_name (team_id).
  3. Right-click on it to select “Export.”
  4. In the export prompt window that appears, make sure the file format is set to Personal Information Exchange (.p12)"**.
  5. Give the file a name such as “IOS_DISTRIBUTION”, choose a location and click Save.
  6. On the next prompt, leave the password empty and click OK.
  7. Use the following openssl command to export the private key:
openssl pkcs12 -in IOS_DISTRIBUTION.p12 -nodes -nocerts | openssl rsa -out ios_distribution_private_key
  1. When prompted for the import password, just press enter. The private key will be written to a file called ios_distribution_private_key in the directory where you ran the command.

Configuring environment variables

  1. Open your Codemagic app settings, and go to the Environment variables tab.
  2. Enter CERTIFICATE_PRIVATE_KEY as the Variable name.
  3. Open the file ios_distribution_private_key with a text editor and copy the entire contents of the file, including the -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- tags. Alternatively, you can run the following command on the file:
    cat ios_distribution_private_key | pbcopy
  4. Paste into the Variable value field.
  5. Enter a variable group name, e.g. appstore_credentials. Click the button to create the group.
  6. Make sure the Secure option is selected so that the variable can be protected by encryption.
  7. Click the Add button to add the variable.

  1. Run the following command on the App Store Connect API key file that you downloaded earlier (in our example saved as codemagic_api_key.p8) to copy its content to clipboard:

    cat codemagic_api_key.p8 | pbcopy

  2. Create a new Environment variable APP_STORE_CONNECT_PRIVATE_KEY and paste the value from clipboard.


  1. Create variable APP_STORE_CONNECT_KEY_IDENTIFIER. The value is the Key ID field from App Store Connect > Users and Access > Keys.
  2. Create variable APP_STORE_CONNECT_ISSUER_ID. The value is the Issuer ID field from App Store Connect > Users and Access > Keys.
Tip: Store all the of these variables in the same group so they can be imported to codemagic.yaml workflow at once.

Environment variables have to be added to the workflow either individually or as a group. Modify your codemagic.yaml file by adding the following:

workflows:
  ios-workflow:
    name: iOS Workflow
    # ....
    environment:
        groups:
            - appstore_credentials

Automatic vs Manual code signing

Signing iOS apps requires a signing certificate (App Store development or distribution certificate in .p12 format) and a provisioning profile. In manual code signing you save these files as Codemagic environment variables and manually reference them in the appropriate build steps.

In Automatic code signing, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the Certificate private key that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary.

Automatic code signing

To code sign the app, add the following commands in the scripts section of the configuration file, after all the dependencies are installed, right before the build commands.

    scripts:
      - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command
        script: keychain initialize
      - name: Fetch signing files
        script: | 
          app-store-connect fetch-signing-files "$BUNDLE_ID" \
            --type IOS_APP_STORE \
            --create
      - name: Set up signing certificate
        script: keychain add-certificates
      - name: Set up code signing settings on Xcode project
        script: xcode-project use-profiles

Instead of specifying the exact bundle-id, you can use "$(xcode-project detect-bundle-id)".

Based on the specified bundle ID and provisioning profile type set with the --type argument, Codemagic will fetch or create the relevant provisioning profile and certificate to code sign the build.

If you are publishing to the App Store or you are using TestFlight to distribute your app to test users, set the --type argument to IOS_APP_STORE.

When using a third party app distribution service such as Firebase App Distribution, set the --type argument to IOS_APP_ADHOC

Manual code signing

In order to use manual code signing, you need the following:

  • Signing certificate: Your development or distribution certificate in .P12 format.
  • Certificate password: The certificate password if the certificate is password-protected.
  • Provisioning profile: You can get it from Apple Developer Center > Certificates, Identifiers & Profiles > Profiles and select the provisioning profile you would like to export and download.
  1. Open your Codemagic app settings, and go to the Environment variables tab.
  2. Enter CM_CERTIFICATE as the Variable name.
  3. Run the following command on the certificate file to base64 encode it and copy to clipboard:
    cat ios_distribution_certificate.p12 | base64 | pbcopy
  4. Paste into the Variable value field.
  5. Enter a variable group name, e.g. appstore_credentials.
  6. Make sure the Secure option is selected so that the variable can be protected by encryption.
  7. Click the Add button to add the variable.
  8. Repeat steps 2 -7 to create the variable CM_PROVISIONING_PROFILE and paste the base64 encoded value of the provisioning profile file.
  9. Add the CM_CERTIFICATE_PASSWORD variable, make it Secure and add it to the same variable group.

Then, add the code signing configuration and the commands to code sign the build in the scripts section, after all the dependencies are installed, right before the build commands.

    scripts:
      - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command
        script: keychain initialize
      - name: Set up provisioning profiles from environment variables
        script: | 
            PROFILES_HOME="$HOME/Library/MobileDevice/Provisioning Profiles"
            mkdir -p "$PROFILES_HOME"
            PROFILE_PATH="$(mktemp "$PROFILES_HOME"/$(uuidgen).mobileprovision)"
            echo ${CM_PROVISIONING_PROFILE} | base64 --decode > "$PROFILE_PATH"
            echo "Saved provisioning profile $PROFILE_PATH"
      - name: Set up signing certificate
        script: | 
            echo $CM_CERTIFICATE | base64 --decode > /tmp/certificate.p12
            if [ -z ${CM_CERTIFICATE_PASSWORD+x} ]; then
                # when using a certificate that is not password-protected
                keychain add-certificates --certificate /tmp/certificate.p12
            else
                # when using a password-protected certificate
                keychain add-certificates --certificate /tmp/certificate.p12 --certificate-password $CM_CERTIFICATE_PASSWORD
            fi
      - name: Set up code signing settings on Xcode project
        script: xcode-project use-profiles

Using multiple provisioning profiles

To set up multiple provisioning profiles, for example, to use app extensions such as Notification Service, the easiest option is to add the provisioning profiles to your environment variables with a similar naming convention.

For example, create a provisioning_profiles environment variable group and add variables such as:

  • CM_PROVISIONING_PROFILE_BASE
  • CM_PROVISIONING_PROFILE_NOTIFICATIONSERVICE

Then, include this group in your workflow and set up provisioning profiles with a script:

environment:
  groups:
    - provisioning_profiles

# ...

scripts:
  - name: Set up Provisioning profiles from environment variables
    script: | 
      PROFILES_HOME="$HOME/Library/MobileDevice/Provisioning Profiles"
      mkdir -p "$PROFILES_HOME"
      for profile in "${!CM_PROVISIONING_PROFILE_@}"; do
        PROFILE_PATH="$(mktemp "$HOME/Library/MobileDevice/Provisioning Profiles"/ios_$(uuidgen).mobileprovision)"
        echo ${!profile} | base64 --decode > "$PROFILE_PATH"
        echo "Saved provisioning profile $PROFILE_PATH"
      done

Creating the App Store Connect API key

Signing macOS applications requires Apple Developer Program membership.

It is recommended to create a dedicated App Store Connect API key for Codemagic in App Store Connect. To do so:

  1. Log in to App Store Connect and navigate to Users and Access > Keys.
  2. Click on the + sign to generate a new API key.
  3. Enter the name for the key and select an access level. We recommend choosing App Manager access rights, read more about Apple Developer Program role permissions here.
  4. Click Generate.
  5. As soon as the key is generated, you can see it added to the list of active keys. Click Download API Key to save the private key for later. Note that the key can only be downloaded once.
Take note of the Issuer ID above the table of active keys as well as the Key ID of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI.

Obtaining the certificate private key

To sign iOS apps, you can use the private key of an iOS Distribution certificate that has already been created in your Apple Developer Program account.

Alternatively, you can create a new private key on your Mac and the Codemagic CLI will create a new iOS Distribution certificate in your Apple Developer Program account for you.

You can create a new 2048 bit RSA key by running the command below in your terminal:

ssh-keygen -t rsa -b 2048 -m PEM -f ~/Desktop/ios_distribution_private_key -q -N ""

This new private key will be used to create a new iOS Distribution certificate in your Apple Developer Program account if there isn’t one that already matches this private key.

  1. On the Mac which created the iOS distribution certificate, open the Keychain Access, located in the Applications and Utilities folder.
  2. Select the certificate entry which should be listed as iPhone Distribution: company_name (team_id).
  3. Right-click on it to select “Export.”
  4. In the export prompt window that appears, make sure the file format is set to Personal Information Exchange (.p12)"**.
  5. Give the file a name such as “IOS_DISTRIBUTION”, choose a location and click Save.
  6. On the next prompt, leave the password empty and click OK.
  7. Use the following openssl command to export the private key:
openssl pkcs12 -in IOS_DISTRIBUTION.p12 -nodes -nocerts | openssl rsa -out ios_distribution_private_key
  1. When prompted for the import password, just press enter. The private key will be written to a file called ios_distribution_private_key in the directory where you ran the command.

Automatic vs Manual code signing

Signing macOS apps requires a Signing certificate (App Store development or distribution certificate in .p12 format) and a Provisioning profile. In Manual code signing you save these files as Codemagic Environment variables and manually reference them in the appropriate build steps.

In Automatic code signing, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the certificate private key that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary.

Configuring environment variables

  1. Open your Codemagic app settings, and go to the Environment variables tab.
  2. Enter CERTIFICATE_PRIVATE_KEY as the Variable name.
  3. Open the file ios_distribution_private_key with a text editor and copy the entire contents of the file, including the -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- tags. Alternatively, you can run the following command on the file:
    cat ios_distribution_private_key | pbcopy
  4. Paste into the Variable value field.
  5. Enter a variable group name, e.g. appstore_credentials. Click the button to create the group.
  6. Make sure the Secure option is selected so that the variable can be protected by encryption.
  7. Click the Add button to add the variable.

  1. Run the following command on the App Store Connect API key file that you downloaded earlier (in our example saved as codemagic_api_key.p8) to copy its content to clipboard:

    cat codemagic_api_key.p8 | pbcopy

  2. Create a new Environment variable APP_STORE_CONNECT_PRIVATE_KEY and paste the value from clipboard.


  1. Create variable APP_STORE_CONNECT_KEY_IDENTIFIER. The value is the Key ID field from App Store Connect > Users and Access > Keys.
  2. Create variable APP_STORE_CONNECT_ISSUER_ID. The value is the Issuer ID field from App Store Connect > Users and Access > Keys.
Tip: Store all the of these variables in the same group so they can be imported to codemagic.yaml workflow at once.

Environment variables have to be added to the workflow either individually or as a group. Modify your codemagic.yaml file by adding the following:

workflows:
  ios-workflow:
    name: iOS Workflow
    # ....
    environment:
        groups:
            - appstore_credentials

Automatic code signing

To code sign the app, add the following commands in the scripts section of the configuration file, after all the dependencies are installed, right before the build commands.

    scripts:
      - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command
        script: keychain initialize
      - name: Fetch signing files
        script: | 
          app-store-connect fetch-signing-files "$BUNDLE_ID" \
            --platform MAC_OS \
            --type MAC_APP_STORE \
            --create
      - name: Fetch Mac Installer Distribution certificates
        script: | 
           # You may omit the first command if you already have the installer certificate and provided the corresponding private key
            app-store-connect create-certificate --type MAC_INSTALLER_DISTRIBUTION --save || \
            app-store-connect list-certificates --type MAC_INSTALLER_DISTRIBUTION --save
      - name: Set up signing certificate
        script: keychain add-certificates
      - name: Set up code signing settings on Xcode project
        script: xcode-project use-profiles

Instead of specifying the exact bundle ID, you can use "$(xcode-project detect-bundle-id)".

Based on the specified bundle ID and provisioning profile type, Codemagic will fetch or create the relevant provisioning profile and certificate to code sign the build.

Manual code signing

In order to use manual code signing, you need the following:

  • Signing certificate: Your development or distribution certificate in .P12 format.
  • Certificate password: The certificate password if the certificate is password-protected.
  • Provisioning profile: You can get it from Apple Developer Center > Certificates, Identifiers & Profiles > Profiles and select the provisioning profile you would like to export and download.
Note: With Manual code signing, you also have to manually Package the application into a .pkg container and Notarize it.
  1. Open your Codemagic app settings, and go to the Environment variables tab.
  2. Enter CM_CERTIFICATE as the Variable name.
  3. Run the following command on the certificate file to base64 encode it and copy to clipboard:
    cat ios_distribution_certificate.p12 | base64 | pbcopy
  4. Paste into the Variable value field.
  5. Enter a variable group name, e.g. appstore_credentials.
  6. Make sure the Secure option is selected so that the variable can be protected by encryption.
  7. Click the Add button to add the variable.
  8. Repeat steps 2 - 7 to create variables CM_PROVISIONING_PROFILE and INSTALLER_CERTIFICATE. Paste the base64 encoded values for both of these files.
  9. Add the CM_CERTIFICATE_PASSWORD and INSTALLER_CERTIFICATE_PASSWORD variables, make them Secure and add them to the same variable group.

Then, add the code signing configuration and the commands to code sign the build in the scripts section, after all the dependencies are installed, right before the build commands.

    scripts:
      - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command
        script: keychain initialize
      - name: Set up provisioning profiles from environment variables
        script: | 
            PROFILES_HOME="$HOME/Library/MobileDevice/Provisioning Profiles"
            mkdir -p "$PROFILES_HOME"
            PROFILE_PATH="$(mktemp "$PROFILES_HOME"/$(uuidgen).mobileprovision)"
            echo ${CM_PROVISIONING_PROFILE} | base64 --decode > "$PROFILE_PATH"
            echo "Saved provisioning profile $PROFILE_PATH"
      - name: Set up signing certificate
        script: | 
            echo $CM_CERTIFICATE | base64 --decode > /tmp/certificate.p12
            if [ -z ${CM_CERTIFICATE_PASSWORD+x} ]; then
                # when using a certificate that is not password-protected
                keychain add-certificates --certificate /tmp/certificate.p12
            else
                # when using a password-protected certificate
                keychain add-certificates --certificate /tmp/certificate.p12 --certificate-password $CM_CERTIFICATE_PASSWORD
            fi

            echo $INSTALLER_CERTIFICATE | base64 --decode > /tmp/installer_certificate.p12
            if [ -z ${INSTALLER_CERTIFICATE_PASSWORD+x} ]; then
                # when using a certificate that is not password-protected
                keychain add-certificates --certificate /tmp/installer_certificate.p12
            else
                # when using a password-protected certificate
                keychain add-certificates --certificate /tmp/installer_certificate.p12 --certificate-password $INSTALLER_CERTIFICATE_PASSWORD
            fi
      - name: Set up code signing settings on Xcode project
        script: xcode-project use-profiles
Packaging the application

To package your application into an .pkg Installer package and sign it with the Mac Installer Distribution certificate, use the following script:

  scripts:
    - name: Package application
      script: | 
      set -x
    
      # Command to find the path to your generated app, may be different
      APP_NAME=$(find $(pwd) -name "*.app")  
      cd $(dirname "$APP_NAME")
    
      PACKAGE_NAME=$(basename "$APP_NAME" .app).pkg
      xcrun productbuild --component "$APP_NAME" /Applications/ unsigned.pkg  # Create and unsigned package

      # Find the installer certificate commmon name in keychain
      INSTALLER_CERT_NAME=$(keychain list-certificates \
        | jq '.[]
        | select(.common_name
        | contains("Mac Developer Installer"))
        | .common_name' \
        | xargs)
      
      xcrun productsign --sign "$INSTALLER_CERT_NAME" unsigned.pkg "$PACKAGE_NAME" # Sign the package
    
      rm -f unsigned.pkg                                                       # Optionally remove the not needed unsigned package
Note: Don’t forget to specify the path to your generated package in the artifacts section.
Notarizing macOS applications

Notarization is a process where Apple verifies your application to make sure it has a Developer ID code signature and does not consist of malicious content. Notarizing an app during the Codemagic build process is possible using altool as follows:

xcrun altool --notarize-app -f <file> --primary-bundle-id <bundle_id>
           {-u <username> [-p <password>] | --apiKey <api_key> --apiIssuer <issuer_id>}
           [--asc-provider <name> | --team-id <id> | --asc-public-id <id>]