Creating Environment Specific Configurations
Platforms: iOS, Android
Many software development teams utilize different environments during the software development lifecycle. Configuration may differ between environments, such as bundle IDs, deep-link schemes, or icons and splash screens.
The Capacitor configuration file handles high-level options for Capacitor tooling and plugin configuration. iOS schemes and Android product flavors allow developers to provide differing app values for different environments. By combining the two, developers can use the Capacitor CLI to build apps for different environments.
This guide will walk you through setting up a QA environment configuration alongside the default environment configuration provided out-of-the-box. To demonstrate differences between each environment, the app name and bundle ID will differ between the two.
Prepare a Capacitor App
You will need a Capacitor app with both iOS and Android platforms added. If you have an existing Capacitor app with both platforms added, skip this section.
Depending on your preference, you can either add Capacitor to an existing web application or create a new Capacitor application with the Ionic Framework.
The Capacitor app must use TypeScript for configuration. This guide uses capacitor.config.ts
to dynamically export different configurations.
Before adding any native platforms to the project, you must build the Capacitor App at least once.
npm run build
Once built, you can add the platforms.
npm install @capacitor/ios @capacitor/android
npx cap add ios
npx cap add android
Setup a new iOS scheme
Create a new Xcode target
Start by opening the native iOS project in Xcode: npx cap open ios
.
- Go to the project's settings in the Project Navigator panel. Under the Targets section, right-click the "App" target and select Duplicate to copy the existing target.
- Click the new "App copy" target and press the
Enter
key to rename it. Set the target's name to "App QA".
This process created an additional "App copy" scheme and added a new file called App copy-Info.plist
.
You can find additional information on iOS targets at this link.
Rename the new scheme and Plist file
- Select Manage Schemes... from the Scheme menu.
- Find the "App copy" scheme and press the
Enter
key to rename it. Set the name to "App QA" and close the dialog. - Find the "App copy-Info" file in the Project Navigator panel and press the
Enter
key to rename it. Set the file's name to "App QA-Info.plist". - Return to the project's settings. Ensuring that the "App QA" target is selected, open the Build Settings section. Scroll down to Packaging and change the Info.plist File entry to "App QA-Info.plist".
The iOS project now has two runnable schemes: "App" and "App QA". Capacitor's configuration file allows you to supply which scheme to build during the run
command.
You can find additional information on iOS schemes at this link.
Set environment-specific values
Return to the General portion of the project's settings. Ensure you have the "App QA" target selected and change the Display Name and Bundle Identifier.
Make sure these values are different than what exists for the default "App" target. Target-specific values get stored in the target's associated Info.plist
file. Following this guide, that file is App QA-Info.plist
.
Update the Podfile and sync the App
Exit Xcode; you can use your preferred IDE going forward.
Open /ios/App/Podfile
and duplicate the code block for the "App" target, replacing "App" with "App QA" for the duplicate entry like so:
...snip...
target 'App' do
capacitor_pods
# Add your Pods here
end
target 'App QA' do
capacitor_pods
# Add your Pods here
end
Run npx cap sync
to sync plugins with the "App QA" target.
Add iOS-specific Capacitor configuration
With the target and scheme for the QA environment created, the Capacitor configuration needs to be updated to use them.
Add the property below to the configuration object in capacitor.config.ts
:
ios: {
scheme: 'App QA',
}
The scheme
property tells Capacitor which iOS scheme to use for the run
command. Test this out; run npx cap run ios
and you'll see that the app name is different.
Setup Android product flavors
Modify the App's Gradle file
Android projects contain multiple build.gradle
files; the one to modify to set up product flavors resides in the /android/app
folder.
Open /android/app/build.gradle
and add the following code within the android
block:
flavorDimensions "environment"
productFlavors {
dev {
dimension "environment"
manifestPlaceholders = [displayName:"My App"]
}
qa {
dimension "environment"
applicationIdSuffix ".qa"
manifestPlaceholders = [displayName:"My App - QA"]
}
}
This code requires some explanation:
- Android does not provide a "default" flavor. In this guide, the non-QA environment is called "dev".
applicationIdSuffix
will append.qa
to the end of the bundle ID.manifestPlaceholders
are values that are usable inAndroidManifest.xml
.
Note: You are free to modify the bundle ID and display name values to your liking.
You can find additional information on Android product flavors at this link.
Update the Android manifest
In the last section, you created a placeholder, displayName
. Open AndroidManifest.xml
and change the value of android:label
to ${displayName}
within the application
and activity
nodes.
<application
...snip...
android:label="${displayName}">
<activity
...snip...
android:label="${displayName}">
Add Android-specific Capacitor configuration
Like iOS, you must update the Capacitor configuration to use the QA product flavor.
Add the property below to the configuration object in capacitor.config.ts
:
android: {
flavor: "qa",
},
Test this out; run npx cap run android
and you'll see that the app name is different.
Dynamically build for different environments
Export environment-specific Capacitor configuration
All the pieces in place, now capacitor.config.ts
can be written such that it exports a different configuration object based on a particular value.
Open capacitor.config.ts
and modify the code like so:
import { CapacitorConfig } from '@capacitor/cli';
let config: CapacitorConfig;
const baseConfig: CapacitorConfig = {
appId: 'io.ionic.starter',
appName: 'My App',
webDir: 'build',
bundledWebRuntime: false,
};
switch (process.env.NODE_ENV) {
case 'qa':
config = {
...baseConfig,
ios: {
scheme: 'App QA',
},
android: {
flavor: 'qa',
},
};
break;
default:
config = {
...baseConfig,
ios: {
scheme: 'App',
},
android: {
flavor: 'dev',
},
};
break;
}
export default config;