In the mobile world, a white-label app is an app offered by someone other than the app’s creator, usually under a different brand name. In some cases, a company can offer a variety of white-label applications.

Providing white-label apps can get a bit messy, depending on the level of modularity and customizability of the apps. The big question is: how can it scale? If you only want to deliver a few customized binaries, doing it manually is manageable. But what if you want to deliver dozens, or even hundreds?

In this post we will explain how we scale the delivery of custom apps through automation of the build and delivery processes and we’ll demonstrate how we do it at Soluto.

The “Pre-build” Script

The first approach we took was to commit all the resources (images, strings, etc.) to the source code repository.

This approach was easy to start with, but we quickly discovered it had a few disadvantages:

  • It made our repository huge, slow and difficult to work with.
  • Each resource change for one of the brands (string or image) had to be committed into the repository, which made its history much less transparent and more difficult to understand because of the sheer amount of meaningless commits.

Because of all this, we decided to write a Pre-build script, which a developer or an automated build must run once before they can build the app. The script downloads all the branded resources and places them in their destination location, depending on the build type (Android / iOS).

This is an example of running a Pre-build script for iOS app for somebrand:
> npm run pre-build:ios –brand somebrand

The implementation of the Pre-build script is quite simple – the repository contains a list of key-value pairs, where the key is the name of the resource that should be downloaded and the value is the name and location of the destination resource e.g. { “brand-logo” : “path/to/logo.png” }

Android App Branding

To manage multiple Android application customizations we use Android Studio’s powerful and easy-to-use Product Flavors. Each of our brands has its own flavor with a unique applicationId as well as a unique folder with all its resources – the Pre-build script described above will populate the folder before we build the application.

To add a new brand, all we have to do is add it to the build.gradle file, under the ProductFlavors section, with its applicationId, which is a process we easily automated.

iOS App Branding

Unlike Android Studio, the standard IDE for iOS, Xcode, has no support for creating multiple customizations of the same application. To simulate this behavior we used Xcode’s Targets feature.

First we created a core target that contains all of our code. All the branded targets consumed this target as a library. Then, we created a target for each brand. Each target contained only the following: Bundle ID, code sign details, target properties (info.plist), build settings and build phases. The branded info.plist also contains the brand resources location path. The Pre-build script downloads the target’s brand resources and locates them in the specified path

Adding a new brand to the Xcode project is more complex here. We need to create a new target which includes info.plist, build settings and build phases. Luckily, there’s a Ruby library that’s good for these kinds of cases – xcodeproj. So we wrote a Ruby script that uses it to automate this process. It creates a new target and copies all the needed resources from a template target. It also modifies the new target’s dependent parameters.

Nightly Builds and Submitting to Stores

To build an Android APK, we trigger the “assembleRelease” gradle task for the brand. Then we upload the output APK to Google Play using their API.

To release an iOS app to the App Store, we use a Fastlane script with the brand name as a parameter. We’re doing some nice tricks there too, take a look at our post – How Fastlane saved us from deployment hell for more details.

Missing Parts of the Complete Architecture

This post mainly focuses on how we customize our mobile applications, but there’s a lot more to it than that. We automated most of the processes around branding lifecycle, so for example – creating an app for a new brand is a fully automated process. We also created a web interface for creating apps, manage their resources and features. And finally, we have to mention Tweek, our feature management system which provides granular control over functionality and look and feel across the different brands. These components are out of the scope of this post and probably deserve their own post.

We hope you gained something from this post! Feel free to share any thoughts or comments below.