Suppose we have an iOS app with a free version (basic features) and a paid version (additional features). The app may have development and production environment settings e.g. local and cloud server URL. Also, the app source code is maintained in a single Xcode project.
How to manage these multiple configurations when running or archiving the app?
Actually, there is no single way to answer this question. Me… I chose to use multiple targets. I used as many targets as the number of the different configurations.
Next, we shall:
1 — create two targets for free and paid configurations.
2 —add app icon for each target.
3 — add bundle identifier for each target.
4 — add code that depend on a target.
Source Code: https://github.com/bel3arabyapps/iOS-App-Variants
I assume you have a Mac computer running Xcode and you know how to create a new project and build basic UI.
Good! me, I have Xcode version 12.4 and I have just created a new project with name Awesomeness.
1. Setup paid and free targets
Every project contains at least one target by default. In my project it is Awesomeness, and I will keep it for the paid version.
Next, add a target for the free version by duplicating the Awesomeness target:
1 — Right-click the Awesomeness target and select duplicate.
2 — Rename the new target to Awesomeness-free instead of Awesomeness copy.
3 — When duplicating a target:
3.1 — A new scheme is added to the project schemes. Rename it to Awesomeness-free instead of Awesomeness copy.
3.2 — An Info.plist is duplicated too. Rename it to Info-free.plist instead of Awesomeness copy-Info.plist and update the target build settings with the new name.
4 - Duplicate the Awesomeness target again and repeat the same steps to add as much targets as you need.
At this point, I can select Awesomeness or Awesomeness-free scheme and run it, but there will be no difference so far.
2. Setup the App Icon for each target
OK, let’s make some difference. I shall use a red app icon for the free version and a blue app icon for the paid version.
1 — Remove the default app icon from Assets.xcassets (the default Asset Catalog).
2 — Add a new Asset Catalog, keep the default name and make sure to select the Awesomeness checkbox in the Targets section.
3 — Add a new app icon to the new Asset Catalog and fill it with the blue images.
4 — Add a new Asset Catalog, add -free to the default name and make sure to select the Awesomeness-free checkbox in the Targets section.
5 — Add a new app icon to the new Asset Catalog and fill it with the red images.
6 — Select the Awesomeness and run and note the app icon. Select the Awsomeness-free and run and note the app icon.
Nice! the app icon changes each time we change the scheme and run.
3. Setup the Bundle Identifier for each target
In fact, both free and paid versions will be sent to the AppStore and both can exist on the same iPhone. But till now, they replace each other each time we change the scheme and run. Let’s fix that.
Each app on the AppStore must have a unique Bundle Identifier. To send both free and paid versions to the AppStore, they must have different identifiers.
1 — Select Awsomeness-free target.
2 — Add .free to the end of the Bundle Identifier.
3 — Run.
4 — Change scheme and run again.
Great! now both free and paid versions can exist on an iPhone.
4. Code that depends on a target
One more thing… the source code. Part of Awesomeness source code will be the same in both free and paid versions. But another part will be different.
While the common code files are added to all targets, we need version dependent code files to be added to their specific target(s).
1 — Add a new Swift File, rename it to Constants and make sure to select the Awesomeness checkbox in the Targets section.
2 — Add a new Swift File, rename it to Constants-free and make sure to select the Awesomeness-free checkbox in the Targets section.
3 — Open Constants.swift and add a line of code:
let Website = “https://www.apple.com"
4 — Open Constants-free.swift and add a line of code
let Website = “https://www.google.com"
5 — Add a UILabel to the existing ViewController and set its text to Website
label.text = Website
7 — Run
8 — Change scheme and run again and see the result.