问题
I have a single project but with 4 different environments (Dev,Stagging,QA,Production). I have given their (environment's webservice url) paths from mobile's setting. Now I want to use different GoogleService-info.plist for all these different environments. Like when I select Dev from backend the project should take GoogleService-Info.plist of Dev project only. These GoogleService-Info.plists are created on 4 different accounts. Project should take the path of GoogleService-info.plist programmatically. I have tried the following code
1] By taking reference from this url , I have created two folders Dev and QA (for now) and tried to given their paths by programmaically
#if DEV
print("[FIREBASE] Development mode.")
filePath = Bundle.main.path(forResource: "GoogleService-Info",
ofType: "plist", inDirectory: "Dev")
#elseif QA
print("[FIREBASE] QA mode.")
filePath = Bundle.main.path(forResource: "GoogleService-Info",
ofType: "plist", inDirectory: "QA")
#endif
let options = FirebaseOptions.init(contentsOfFile: filePath)!
FirebaseApp.configure(options: options)
But it throws an error
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
on
let options = FirebaseOptions.init(contentsOfFile: filePath)!
this line
2] Second I changed name of GoogleService-Info.plist by GoogleService-Info-QA.plist and tried to access this file programmatically
private func configureFirebase() {
guard let plistPath = Bundle.main.path(forResource:
"GoogleService-Info-QA", ofType: "plist"),
let options = FirebaseOptions(contentsOfFile: plistPath)
else { return }
FirebaseApp.configure(options: options)
}
But it throws an error
Terminating app due to uncaught exception 'FIRAppNotConfigured',
reason: 'Failed to get default Firebase Database instance. Must
call `[FIRApp configure]` (`FirebaseApp.configure()` in Swift)
before using Firebase Database.
回答1:
Place this code snippet in your AppDelegate.swift in the application's didFinishLaunchingWithOptions
delegate function, somewhere before the return true
//Configure Firebase based on the app's environment
#if DEV
guard let filePath = Bundle.main.path(forResource: "GoogleService-Info-DEV", ofType: "plist") else { return }
let options = FIROptions(contentsOfFile: filePath)
FIRApp.configure(with: options!)
#elseif QA
guard let filePath = Bundle.main.path(forResource: "GoogleService-Info-QA", ofType: "plist") else { return }
let options = FIROptions(contentsOfFile: filePath)
FIRApp.configure(with: options!)
#endif
You need to make sure your plist files are named accordingly, and also make sure they are part of your target:
- Select the GoogleService-Info-DEV file and on the right, in the FileInspector make sure the checkbox is ticked for your app's target. Do the same with the GoogleService-Info-QA file.
Your files should be placed inside the main folder, as you would place a normal Google-Info.plist file.
回答2:
For this confirmation you have to follow following steps:
- Goto Project Setting
- Select you Dev Target
- Goto Build Phase
- Click on icon and create new run script with name GOOGLESERVICE_INFO_PLIST
- use following script
//Name of the resource we're selectively copying
GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist
//Get references to dev and prod versions of the GoogleService-Info.plist
//NOTE: These should only live on the file system and should NOT be part of the target (since we'll be adding them to the target manually)
GOOGLESERVICE_INFO_DEV=${PROJECT_DIR}/projectFolder/Firebase/Dev/${GOOGLESERVICE_INFO_PLIST}
GOOGLESERVICE_INFO_PROD=${PROJECT_DIR}/projectFolder/Firebase/Prod/${GOOGLESERVICE_INFO_PLIST}
//Make sure the dev version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_DEV}"
if [ ! -f $GOOGLESERVICE_INFO_DEV ]
then
echo "No Development GoogleService-Info.plist found. Please ensure it's in the proper directory."
exit 1
fi
//Make sure the prod version of GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_PROD}"
if [ ! -f $GOOGLESERVICE_INFO_PROD ]
then
echo "No Production GoogleService-Info.plist found. Please ensure it's in the proper directory."
exit 1
fi
//Get a reference to the destination location for the GoogleService-Info.plist
PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${PLIST_DESTINATION}"
//Copy over the prod GoogleService-Info.plist for Release builds
if [ "${CONFIGURATION}" == "Release" ]
then
echo "Using ${GOOGLESERVICE_INFO_PROD}"
cp "${GOOGLESERVICE_INFO_PROD}" "${PLIST_DESTINATION}"
else
echo "Using ${GOOGLESERVICE_INFO_DEV}"
cp "${GOOGLESERVICE_INFO_DEV}" "${PLIST_DESTINATION}"
fi
- Final Step: Make sure you have placed GoogleService-Info.plist at correct location path in the project, You can find the attached image for reference.
GOOGLESERVICE_INFO_DEV=${PROJECT_DIR}/projectFolder/Firebase/Dev/${GOOGLESERVICE_INFO_PLIST} GOOGLESERVICE_INFO_PROD=${PROJECT_DIR}/projectFolder/Firebase/Prod/${GOOGLESERVICE_INFO_PLIST}
projectFolder is your current project folder
回答3:
I got the solution. I renamed GoogleService-Info.plists files by its respective environments. And Added those files in Build Phases -> Copy Bundle Resources. Then added the following code as per the environment selected
guard let plistPath = Bundle.main.path(forResource: "nameOfTheGoogleService-Info.plistFileAsPerTheEnvironment", ofType: "plist"),
let options = FirebaseOptions(contentsOfFile: plistPath)
else { return }
if FirebaseApp.app() == nil{
FirebaseApp.configure(options: options)
}
Minor change is that, when user changes the app's environment, then he should remove app from background and open it again. Then the AppDeleagte takes the path of respective GoogleService-Info.plist as per its environment selected
来源:https://stackoverflow.com/questions/56626467/use-different-googleservice-info-plist-for-single-project-in-xcode-using-swift4