# White label apps

> How to white-label your application using codemagic.yaml



These are the steps you need to get started white labeling your application using Codemagic.

1. [Add your base app to Codemagic](#1-add-your-base-app-to-codemagic)
2. [Storing client’s assets somewhere Codemagic can access](#1-storing-clients-assets)
3. [Create a unique environment variable group for each client (via UI or API)](#3-create-a-new-unique-environment-variables-group-for-each-client-via-ui-or-api)
4. [Setup your `codemagic.yaml` workflows to dynamically build for all clients](#4-setup-your-codemagicyaml-workflows-to-dynamically-build-for-all-clients)
5. [Start new builds via API, passing the client Id, and the environment variable group name](#5-start-new-builds-via-api)

## 1. Add your base app to Codemagic
You don’t have to create a Codemagic application for each client you want to white-label for, only one application linked with your base code is required.

The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app.

1. If you have more than one team configured in Codemagic, select the team you wish to add the app to.
2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps).
3. Select the repository from the list of available repositories. Select the appropriate project type.
4. Click **Finish: Add application**


## 2. Storing client assets

Instead of adding each customer's assets to the base app repository, you should store the assets required for rebranding the app somewhere accessible by Codemagic. This could be an encrypted S3 or GCP storage bucket or a headless CMS. Each customer should be assigned a unique identifier which can be passed to the white-label workflow when the build is started.

You should create a zip archive for each client that uses their unique identifier in the file name, e.g. `assets_001.zip` for client `001`. When a build is started for a specific customer's app, this unique identifier will be sent in the API request payload and the correct asset archive will be downloaded and used to rebrand the app. 



> 
> 💡 The zip archive typically contains these folders:
> 
> - **`android_assets/`**. This folder contains the Android icons from `/android/app/src/main/res/`.
> - **`ios_assets/`**. This folder contains the iOS icons from `/ios/Runner/Assets.xcassets/AppIcon.appiconset/`.
> 
> Other assets such as fonts, images, etc. can also be added to this zip archive. 
> 
> Avoid adding any sensitive files such as certificates, profiles, key stores, or other sensitive data in this archive.
> 
> 



## 3. Create a unique environment variable group for each client
During the white-label build, Codemagic uses client-specific data to set or replace various values in the base code and to sign and publish the app to the stores. 

You should create a uniquely named environment variable group for each of your clients that contains secret environment variables for items such as certificates, profiles, API keys, or other client-specific credentials.

This group might contain the following environment variables:
- Android package name. `PACKAGE_NAME`.
- Android Keystore information. `CM_KEYSTORE` (base64 encoded), `CM_KEY_ALIAS`, `CM_KEY_PASSWORD`, `CM_KEYSTORE_PASSWORD`, `CM_KEYSTORE_PATH`.
- The content of the Google Cloud service JSON file to publish to Play Store. `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`, learn how to get it [here](../yaml-publishing/google-play/#configure-google-play-api-access).
- iOS app details. `APP_STORE_ID`, `BUNDLE_ID`.
- App Store Connect API key. `APP_STORE_CONNECT_KEY_IDENTIFIER`, `APP_STORE_CONNECT_ISSUER_ID`, `APP_STORE_CONNECT_PRIVATE_KEY`, learn how to create create a new key [here](../yaml-code-signing/alternative-code-signing-methods/#:~:text=Creating%20the%20App%20Store%20Connect%20API%20key).
- iOS Distribution certificate private key. `CERTIFICATE_PRIVATE_KEY`, learn how to obtain it [here](../yaml-code-signing/alternative-code-signing-methods/#:~:text=Obtaining%20the%20Certificate%20private%20key).
- **.env** file if your app uses some secrets at runtime. `DOTENV_FILE` (base64 encoded).


To add these values you can either use the [Codemagic UI](https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/#configuring-environment-variables) or use the [Codemagic REST API](https://codemagic.io/api/v3/schema#/) to add these groups and values programmatically, which could be advantageous if you have a large number of clients or wish to add these values from your own backend system or client dashboard.


To add an environment variable using the Codemagic REST API, you need your API access token, the application id, the client group unique name, and the variable name and value. 

- The access token is available in the Codemagic UI in **Account settings > API token**. You can then store this as an environment variable if you are calling the REST API from other workflows.
- Once you have added your app in Codemagic, open its settings and copy the **application id** from the browser address bar - `https://codemagic.io/app/<APP_ID>/settings`
- The client group name is the group that holds all variables for this client e.g. `WL_001`, `WL_002`.

An example of adding a secret variable to an application group looks like this:


```bash

curl --request POST \
  --url https://codemagic.io/api/v3/variable-groups/{variable_group_id}/variables \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'x-auth-token: $CODEMAGIC_AUTH_TOKEN' \
  --data '{
  "secure": true,
  "variables": [
    {
      "name": "string",
      "value": "string"
    }
  ]
}'

```




> 
> 💡 To find **{variable_group_id}**, a group needs to be created before uploading variables. More information can be found [here](https://codemagic.io/api/v3/schema#/) under the Secrets and Environment Vars dropdown.
> 
> 





> 
> 💡
> Files such as **Android keystores**, or **.env** files should be base64 encoded and can be passed like this:
> 
>   `{ "name": "<variable-name>", "value":`**`$(cat fileName | base64) ...`**
> 
>   And then decode it during the build like this:
> 
>   `echo $VAR | base64 --decode > /path`
> 
> 



## 4. Setup your codemagic.yaml workflows to dynamically build for all clients

Your codemagic.yaml file contains various workflows for building your app for all clients e.g. `android-qa-workflow`, `ios-release-workflow`.

In most cases, white label automation is done using shell scripts to perform tasks such as downloading assets, copying files such as logos, images, fonts, etc. to a new location, or changing string values in projects. Here you will find some common script samples we are using in our final [sample project](https://github.com/codemagic-ci-cd/white-label-demo-project/blob/main/codemagic.yaml).

### Downloading assets from Amazon S3

The Amazon CLI tools are pre-installed on Codemagic’s machines which makes it easy to store assets such as images, fonts, logos, etc. in an encrypted S3 bucket and then download these to the build machine when building each white label version. 

The following is an example of downloading a zip archive from Amazon S3 during the build where the `CLIENT_ID` variable is provided when the build is triggered using the Codemagic REST API:


```yaml

environment:
  groups:
    - aws_credentials
  vars:
    S3_BUCKET_NAME: cmwhitelabel 
    CLIENT_ASSETS_FOLDER: client_assets
  ...    
scripts:
  - name: Get assets from AWS S3 bucket
    script: | 
      aws s3 cp s3://$S3_BUCKET_NAME/assets_${CLIENT_ID}.zip assets.zip
      unzip assets.zip -d $CLIENT_ASSETS_FOLDER

```




> 
> Use this script if you're using a headless CMS instead:
> 
> ```yaml
> 
> scripts:
>   - name: Get assets from Contentful CMS
>     script: | 
>       FILE_URL=$(curl --request GET --header "Authorization: Bearer $CONTENTFUL_API_TOKEN" "https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/master/assets" | jq '.items[].fields' | jq -r --arg id "assets_$CLIENT_ID" '. | select (.title==$id) | .file.url' | cut -c 3-) 
>       curl -H "Authorization: Bearer $CONTENTFUL_API_TOKEN" $FILE_URL --output assets.zip
> 
> 
> ```
> 
> 
> 
> 



### Changing the Android package name
To natively change the Android package name, we can utilize a build automation tool like Gradle to modify the necessary files.

In this example, we're first creating a file called `changePackage.gradle` in the root directory of the Android project, which updates the `applicationId` property of the defaultConfig block in your app's build configuration, then adding this line to the `app/build.gradle` file to apply the `changePackage.gradle` script during the build process.


```yaml

- name: Change Android package name
  script: | 
    echo "android {  defaultConfig { applicationId '${PACKAGE_NAME}' }  }" > android/changePackage.gradle
    echo "apply from: rootProject.file('changePackage.gradle')" >> android/app/build.gradle

```

### Changing the iOS bundle ID

The automation scripts used in a white label workflow will often need to modify the content of a configuration file. This can be achieved using the `sed` stream editor utility, which can perform basic text transformations such as replacing or adding text in a file. 

For example, if you want to change the bundle identifier used in the Xcode project by modifying the `project.pbxproj` file, the following script will set the `PRODUCT_BUNDLE_IDENTIFIER` with a value stored in the environment variable called `$BUNDLE_ID`.


```yaml

- name: Set bundle id
  script: sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER \= [^\;]*\;/PRODUCT_BUNDLE_IDENTIFIER = '${BUNDLE_ID}';/' ios/Runner.xcodeproj/project.pbxproj

```


### Changing app name




### Option: Android


Using `sed`, the following script will replace the line in the `AndroidManifest.xml` that starts with `android:label=` with a new line contains the new app name `$APP_NAME`.


```yaml

- name: Change Android app name
  script: sed -i.bak "s/android:label=.*/android:label=\"$APP_NAME\"/g" android/app/src/main/AndroidManifest.xml

```






### Option: iOS



**PlistBuddy** is a utility on macOS that can be used to perform operations on plist files. This approach can be used with native Swift/Objective-C apps, but please note that setting values directly in a Flutter project may cause problems with your project and you should consider using `sed` instead.


```yaml

- name: Change iOS app name
  script: /usr/libexec/PlistBuddy -c "Set :CFBundleName $APP_NAME" -c "Set :CFBundleDisplayName $APP_NAME" ios/${XCODE_SCHEME}/Info.plist

```






### Changing app icons




### Option: Android



For Android apps, you should run a script to update the icons located in `android/app/src/main/res` where you will find a number of directories that contain an icon for specific resolutions such as `drawable-hdpi`, `drawable-mdpi`, `drawable-xhdpi`, `drawable-xxhdpi`, `drawable-xxxhdpi`. Your script to update the icons in your Android project might look something like this:


```yaml

name: Change Android app icons
script: cp -r ./$CLIENT_ASSETS_FOLDER/android_assets/* ./android/app/src/main/res

```






### Option: iOS



For iOS apps, if you look at an Xcode project using Finder, you will see that the icons added in Xcode are located in `<project-name>/<scheme-name>/Assets.xcassets/AppIcon.appiconset`. This means that after downloading icon assets for a specific client’s build, you can change them on disk by simply deleting the existing `AppIcon.appiconset` directory, and then copying the assets into the `Assets.xcassets` directory. 


```yaml

name: Change iOS app icons
script: cp -r ./$CLIENT_ASSETS_FOLDER/ios_assets ios/Runner/Assets.xcassets/

```





<br>


> 
> 💡 You can also use the [flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons) package to generate the icons.
> 
> 



### Automatic build versioning

Each new app version that is published to Google Play or the Apple App Store needs to have a unique build number. You can use Codemagic’s CLI tools to retrieve the previous build number and then increment this for each new build. For example, the following shows how to increment the build number when building Flutter apps:



### Option: Android




```yaml

name: Flutter build aab with automatic versioning
script: | 
  flutter build appbundle --release \
    --build-name=1.0.0 \
    --build-number=$(($(google-play get-latest-build-number --package-name "$PACKAGE_NAME" --tracks="$GOOGLE_PLAY_TRACK") + 1))


```






### Option: iOS




```yaml

name: Flutter build ipa with automatic versioning
script: | 
  flutter build ipa --release \
    --build-name=1.0.0 \
    --build-number=$(($(app-store-connect get-latest-testflight-build-number "$APP_STORE_ID") + 1)) \
    --export-options-plist=/Users/builder/export_options.plist

```






### Publishing to customer stores
You can automate the process of publishing each client’s app to their store account with Codemagic.





### Option: Play Store



Make sure you add each client’s service account JSON key file to their environment variables group so Codemagic can authenticate and publish the app to their store.

```yaml

publishing:
  google_play:
    credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS
    track: <your-track>

```


Read more on this [here](https://docs.codemagic.io/yaml-publishing/google-play/).






### Option: App Store



If you’re using the automatic iOS code signing method, then each client’s environment group already has their App Store Connect account credentials, and they’ll be used to publish the app to this account.


```yaml

publishing:      
  app_store_connect:
    api_key: $APP_STORE_CONNECT_PRIVATE_KEY
    key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER
    issuer_id: $APP_STORE_CONNECT_ISSUER_ID

```


Read more on this [here](https://docs.codemagic.io/yaml-publishing/app-store-connect/).






<br>


> 
> 
> ⚠️ Neither Apple nor Google provides APIs that programmatically allow an app to be created. Therefore, you will need to create and upload the first version of each app manually. After that Codemagic can fully automate the white-label process.
> 



### Full YAML sample
Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to download client assets from AWS S3 bucket, chaning app name and icons, replacing exciting package name and bundle Id, build, code sign, automatically version and publish to each customer stores accounts.

Your final `codemagic.yaml` file should look something like this:





### Option: Android

%!s(<nil>)