I am new to iOS development (historically a full-stack guy) and I'm hoping some of you out there can share with me the best practice for setting up an Xcode project that will support a "dev", and a "prod" Firebase configuration.
I use Firebase as my backend and I have a project for each of the three environments.
Each environment has a GoogleService-Info.plist
configuration file which I've renamed to GoogleService-Info-Dev.plist
and GoogleService-Info-Prod.plist
.
I use Xcode Cloud to build my app and deploy to TestFlight right now.
This is what I think should happen:
For DEV
- Trigger build when a
feature-x
branch is merged into todev
- Set a value
Google-Config-File
in theinfo.plist
toGoogleService-Info-Dev.plist
- Use
FirebaseOptions
to initialize Firebase with the plist file defined in step 2 - Deploy app to the internal TestFlight group
For PROD
- Trigger build when a
dev
branch is merged into tomain
- Set a value
Google-Config-File
in theinfo.plist
toGoogleService-Info-Pro.plist
- Use
FirebaseOptions
to initialize Firebase with the plist file defined in step 2 - Deploy app to the external TestFlight group
NOTE I did read this suggested approach but I don't want to have two targets. I would rather have one target and have the configuration set during the CI/CD (Xcode Cloud) process.
NOTE If you are curious how I configure Firebase at runtime based on a config property in the info.plist
file here is how I do it ...
init() {
// Lookup the value of the Google-Config-File from the info.plist
guard let configFilename = Bundle.main.object(
forInfoDictionaryKey: "Google-Config-File") as? String
else { assert(false, "Couldn't find Google-Config-File in info.plist") }
// Load the specified GoogleService-Info file.
let filePath = Bundle.main.path(forResource: configFilename, ofType: "plist")
// Setup the Firebase options using the GoogleService-Info data
guard let fileopts = FirebaseOptions(contentsOfFile: filePath!)
else { assert(false, "Couldn't load \(String(describing: configFilename)).plist") }
FirebaseApp.configure(options: fileopts)
}
Am I approaching this the right way? Are there any steps I should change?