2 iOS Apps, 1 Codebase with XCode Scheme

Back to Blog Home

2 iOS Apps, 1 Codebase with XCode Scheme

Imagine that you’ve been developing an app for some time and then you’ve realized that you want to monetize the app by creating a pro version or you’re developing an app that has the same codebase but you want to differentiate the app and its features for admin and for members. Copy and pasting your codebase between pro & lite version will waste your time because, in the end, you need to modify each codebase and end up with 2 codebases to be maintained. The solution is XCode Scheme, an XCode feature that’s lesser modified but can help us in this case by maintaining only 1 codebase for 2 or more apps. In this tutorial, we’re going to create 2 apps, pro and lite app version using XCode Scheme.

Project Configuration

To create a new scheme. First, we need to duplicate Project configuration. Open app setting, select your project and duplicate Debug and Release to Debug Pro and Release Pro. We need debug & release configuration for every scheme, debug will be used for running, debugging, testing and analyzing while release will be used for profiling and archiving.

Build Settings

Next, still inside the app setting, select your app target and choose Build Settings tab. Press + and choose Add User-Defined Setting.

Name a new setting BUNDLE_ID_SUFFIX. Fill the value for Debug Pro and Release Pro with .pro. We’ll append this setting into the existing Product Bundle Identifier to create 2 apps, one for regular/lite and one for pro.

Add another User-Defined Setting and name it BUNDLE_DISPLAY_NAME. Fill the value for Debug and Release with your app name. And fill the value for Debug Pro and Release pro with your app name pro or whatever name that you want. We will use this setting for our app name.

Now scroll to top, find Product Bundle Identifier and change its value into <your_app_id>$(BUNDLE_ID_SUFFIX). Press Enter and your product bundle identifiers should change into your_app_id appended with BUNDLE_ID_SUFFIX that we defined above.

Below Product Bundle Identifier you’ll find Product Name, double-click in the value and change it into $(BUNDLE_DISPLAY_NAME). All product names will change to BUNDLE_DISPLAY_NAME that we defined above.

Next, we want a different icon between Regular version and Pro version. To achieve this, select Asset Catalog App Icon Set Name and change its value into AppIcon$(BUNDLE_ID_SUFFIX), press enter and your app icon value for each configuration will be changed into AppIcon and AppIcon.pro

Manage Schemes

Next, click on the active scheme beside Stop Button and choose Manage Schemes.

Select the default scheme, click on gear button at the bottom and choose Duplicate.

Name the new scheme with <app_name> Pro for clarity purpose or any name that you want. Inside Run, Test and Analyze, change the build configuration to Debug Pro. While inside Profile and Analyze, change the build configuration to Release Pro. Check the Shared checkbox at the bottom of the dialog. The final scheme configuration should look like this:

Now you should see 2 schemes when clicking on an active scheme button.

To differentiate the app icon, open Assets.xcassets and add a new iconset named AppIcon.pro . After you added the pro iconset, the xcassets icons should look like this:

Getting User-Defined Settings in Code

For the next step, if you’re using Cocoapods as dependency manager, run pod install to build & integrate the new schemes with Cocoapods libraries. Now, inside our app, we need a way to distinguish features between regular and pro version. One solution to do this is using our app bundle identifier and using enum class with our bundle identifier as its raw value.

enum AppType: String {
    case pro = "com.projectbox.bookinglayout.pro"
    case lite = "com.projectbox.bookinglayout"
}

Next, create a global variable and initialized it inside didFinishLaunchingWithOptions in AppDelegate.swift

var appType: AppType = .lite

class AppDelegate: UIResponder, UIApplicationDelegate {
    ...
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        if let productId = Bundle.main.bundleIdentifier { 
            appType = AppType(rawValue: productId.lowercased()) ?? .lite 
        }
        return true
    }
}

Now, whenever you run your app using a pro scheme, it also creates new app inside your device/simulator.

To archive this app in XCode, select a scheme that you want to archive and use Product → Archive. If you’re using Fastlane gym to archive your app, use this configuration:
gym(scheme: "MyApp Pro", output_name: "MyApp Pro", export_xcargs: "-allowProvisioningUpdates")

You can clone this XCode workspace to learn how to use XCode scheme.