firebase-ios-sdk icon indicating copy to clipboard operation
firebase-ios-sdk copied to clipboard

FirebaseApp.configure(options: options) not loads data when passing FirebaseOptions

Open ashhanai opened this issue 7 years ago • 55 comments

Describe your environment

  • Xcode version: 8.3.3
  • Firebase SDK version: 4.1.1
  • Library version: 4.0.6
  • Firebase Product: core

Describe the problem

In my app, I have more targets and configurations which require more GoogleServices-Info.plists. I have them all downloaded from firebase console after registering new apps.

On app launch, I am trying to load FirebaseOptions from plist at file path via FirebaseOptions(contentsOfFile: plistPath). Finding plistPath via Bundle.main.path(forResource: plistName, ofType: "plist") (every plist have different name). Although path to plist is found and init is returning FirebaseOptions instance, returned instance is empty.

FirebaseApp.configure(options: options) is then complaining about not finding plist named GoogleService-Info.plist.

Steps to reproduce:

PlistName is different than GoogleService-Info.

guard let plistPath = Bundle.main.path(forResource: plistName, ofType: "plist") else {
    fatalError()
}
         
guard let options = FirebaseOptions(contentsOfFile: plistPath) else {
    fatalError()
}
        
FirebaseApp.configure(options: options)

ashhanai avatar Sep 04 '17 20:09 ashhanai

The plist file must be named GoogleService-Info.plist.

If you have multiple, an option is to put them in different folders.

paulb777 avatar Sep 04 '17 21:09 paulb777

And is there any reason why it should be named exactly like that? The init(contentsOfFile:) could parse any plist, if given in a right path.

ashhanai avatar Sep 04 '17 22:09 ashhanai

I don't think it must be named "GoogleService-Info.plist". Can you check whether the plist file is in the correct bundle or linked properly? Can you double check with the code below? [[NSDictionary dictionaryWithContentsOfFile:plistPath]

baolocdo avatar Sep 05 '17 00:09 baolocdo

[[NSDictionary dictionaryWithContentsOfFile:plistPath] works properly. Now I noticed, that FirebaseOptions init works just fine, but FirebaseApp.configure(options: options) cannot handle the passing options and is trying to find "GoogleService-Info.plist" anyway.

So it is a different issue after all.

ashhanai avatar Sep 05 '17 08:09 ashhanai

BTW this is console output after FirebaseApp.configure(options: options) call.

<Error> [Firebase/Core][I-COR000012] Could not locate configuration file: 'GoogleService-Info.plist'.
<Error> [Firebase/Analytics][I-ACS020006] Google App ID from GoogleService-Info.plist is empty. Please, define GOOGLE_APP_ID in GoogleService-Info.plist for Analytics to work reliably.
<Error> [Firebase/Analytics][I-ACS025020] Analytics requires Google App ID from GoogleService-Info.plist. Your data may be lost. Google App ID has been changed. Original, new ID: (nil), 1:625184029135:ios:f8b3e130939c8434

ashhanai avatar Sep 05 '17 10:09 ashhanai

Currently, Firebase Analytics depends on the GoogleService-Info.plist file internally, so that's the issue you're seeing. It's something we're working on, I don't believe there's a workaround for you unfortunately.

ryanwilson avatar Sep 05 '17 12:09 ryanwilson

FirebaseCore is checking for GoogleService-Info.plist by name at https://github.com/firebase/firebase-ios-sdk/blob/master/Firebase/Core/FIROptions.m#L103

paulb777 avatar Sep 05 '17 13:09 paulb777

@paulb777 I believe that this check is executed only when you are loading default plist, than it should be named "GoogleService-Info.plist"

@ryanwilson Ok, thank you for this insight :)

ashhanai avatar Sep 05 '17 14:09 ashhanai

If it doesn't pass the Options from the plist, then the options is probably wrong. Did you rename the GoogleService-Info.plist that you downloaded from the Firebase dashboard? Did you see any logs in this init: https://github.com/firebase/firebase-ios-sdk/blob/master/Firebase/Core/FIROptions.m#L206

baolocdo avatar Sep 06 '17 04:09 baolocdo

Sorry, I have just noticed the log @ashhanai gave us:

<Error> [Firebase/Analytics][I-ACS025020] Analytics requires Google App ID from GoogleService-Info.plist. Your data may be lost. Google App ID has been changed. Original, new ID: (nil), 1:625184029135:ios:f8b3e130939c8434

So it looks like the GoogleService-Info.plist was parsed just fine. There is no problem with Firebase Core. Now, Analytics has such error message because it requires a static plist file instead of run-time options. We deliberately output the message to let you know that there could be some events very early in the app life cycle that requires the Google App ID, so you potentially miss some data. In conclusion, we recommend to have a static GoogleService-Info.plist file (https://firebase.google.com/docs/ios/setup)

baolocdo avatar Sep 07 '17 15:09 baolocdo

Does that mean we can not use multi config files in our projects (each file for an environment)?

tuantmdev avatar Sep 20 '17 03:09 tuantmdev

You can, you just may miss out on very early analytics info.

morganchen12 avatar Sep 20 '17 17:09 morganchen12

Closing due to inactivity.

morganchen12 avatar Oct 20 '17 20:10 morganchen12

please reopen this, its better to have different plist files than store same files in different folders

tedgonzalez avatar Oct 21 '17 06:10 tedgonzalez

@useeless37 you can create FIRApp instances from different plist files. Analytics in particular uses one of a specific name to capture events very early on in the app lifecycle.

morganchen12 avatar Oct 23 '17 17:10 morganchen12

Please correct me if I am wrong, but for a project with multiple build configs (dev VS prod) and targets (say Pokemon Black VS White), each config / target has its own bundle ID and Google app ID, and thus we have to have different plists for each target.

For a project with single target and multiple configs (dev VS prod), we cannot put the GoogleService-Info.plist files into different folders for each config, because if there are multiple files with the same name for the same target, Xcode randomly picks one into the bundle without keeping the folder structure. I figured it out by unzipping the .ipa file and check out the bundle, seeing all resources files from different source folders got put into just one bundle folder.

So, putting GoogleService-Info.plist files into different folders won't solve the issue, and Firebase has to support loading config plist of different names.

54lihaoxin avatar Nov 01 '17 18:11 54lihaoxin

According to the "Getting Started" guide at home page. https://firebase.google.com/docs/configure/#use_multiple_projects_in_your_application

If the builds are part of a single target, the best option is to give both configuration files unique names (e.g. GoogleService-Info-Free.plist and GoogleService-Info-Paid.plist).

But according to reply above from @ryanwilson , there is no workaround at this moment.

Please fix Google Analytics for Firebase uses runtime configuration.

sinofool avatar Dec 27 '17 01:12 sinofool

There is a warning underneath that section of the Getting Started guide mentioning:

Warning: This approach can impact Analytics collection in some circumstances, see the reliable analytics section.

That being said, I agree that we should be fixing Analytics to ensure it can handle runtime configuration changes. We're going to work with the Analytics team to find an acceptable solution that hopefully won't risk the integrity of data coming from Analytics.

ryanwilson avatar Dec 28 '17 14:12 ryanwilson

I have created following "workaround". I have 2 plist files, both correctly named GoogleService-Info.plist, but in separated folders - Debug, Release (it has nothing to do with Debug/Release Xcode scheme). Those files are not even referenced in XCode project.

Then I have file GoogleService-Info.plist - which is empty and this file is referenced in XCode. We use fastlane to configure environment (setting API URL and some other properties), and we have added copying of correct file (from appropriate folder) in place of "placeholder" file.

Sure, this only helps when you want to switch file before build - not on runtime. But then you can use simply FirebaseApp.configure()

matelo avatar Jan 25 '18 11:01 matelo

Little bit more insight on that one. I have project with Firebase and switching names in runtime using FirebaseOptions(contentsOfFile: filePath)

It was working well on Xcode 9.4.1, but after update to Xcode 10 I have an output FirebaseOptions([Firebase/Analytics][I-ACS025020] Analytics requires Google App ID from GoogleService-Info.plist. Your data may be lost. Google App ID has been changed. Original, new ID:: filePath)

And debugview at firebase panel doesn't even see the device (simulator ¯_(ツ)_/¯)

mmynarski avatar Sep 19 '18 13:09 mmynarski

I'd like to bump this, the issue seems to have been open a year ago.

We're also struggling with this, we might implement the build-script solution but imho this isn't a good solution at all.

Our goal is to be able to switch environment at runtime and even though the api looks like it's build for it

FirebaseApp.configure with multiple FIRApp instances, Analytics use a static approach.

The best case scenario I would love to see:

let application = FirebaseApp.configure(options:) -> FirApp
application.analytics.logEvent()

were the static helper would simply call

Analytics {

  static func logEvent() {
   FirebaseApp.defaultApp.analytics.logEvent()
  } 

}

I understand their could be "lost" analytics, but that's just our responsibility to call configuration as soon as possible.

  • There could be an internal pool to store the events otherwise

lifely avatar Nov 19 '18 21:11 lifely

Seems like Analytics is not the only module that does not support multiple GoogleService-Info.plistfiles. We use multiple targets, and name the file like this: GoogleService-Info-<target>.plist. This has worked fine for some time, but when we now tried to add DynamicLinks to our project, it insists on loading the API KEY from GoogleService-Info.plist (which doesn't exist), and completely ignore that we have initialised FIRApp with a custom name for the service file.

forsen avatar Nov 22 '18 13:11 forsen

@lifely thanks for the update and the clear goal. It's still an ongoing discussion and I'll update with more as it progresses, thanks!

@forsen thanks for bringing that to our attention - looks like the line in question is https://github.com/firebase/firebase-ios-sdk/blob/c724f9d1e8c3d2f7a44b8959983e1ebaa3eaa5cb/Firebase/DynamicLinks/FDLURLComponents/FIRDynamicLinkComponentsKeyProvider.m#L29

This can and should be avoided, I'll file an issue for it separately.

ryanwilson avatar Nov 22 '18 15:11 ryanwilson

Hello everyone,

We have had the same problem of Analytics not working when initializing FIR instances runtime. Is there any time frame that can be provided for the fix? We have also seen this problem on Android and will it be fixed for both platforms or just iOS?

Background: We are moving from google analytics to firebase and we need support for ability to switch firebase app runtime. More information:

https://stackoverflow.com/questions/53878190/configure-multiple-firebase-projects-runtime-in-ios-application-and-firebase-goo/53887107#53887107

Regards, Bhavik

bbhagat avatar Dec 21 '18 20:12 bbhagat

@bbhagat sorry for the delay, we're working on the docs to make it more clear.

As Paul mentioned in the stackoverflow question there's a workaround where you can have two files named GoogleService-Info.plist in different folders and include them in different targets for your application.

While this isn't exactly the ability to switch at runtime, it's the current supported setup. Unfortunately I don't have a timeline to share with you about any further resolution.

ryanwilson avatar Jan 10 '19 01:01 ryanwilson

Hey @ryanwilson Thanks a lot for providing the update.

Unfortunately, we do not have two different targets. We only have one target (IPA/APK) file which gets generated and has ability to connect to different servers (QA,STG,PROD) and hence we need an ability to switch the instance runtime. We decide where the user is logging in depending on the username and server specifier that they enter. It is strange since Firebase at core supports switching instance runtime. But just google analytics as a part of firebase does not support.

So we are not in a hurry since google analytics is not gonna be deprecated till next year. But do you think there would be a solution before that?

Once again, appreciate all the help.

Regards, Bhavik

bbhagat avatar Jan 10 '19 04:01 bbhagat

Any options of NOT using plist files? They're not the most secure way of storing keys in an app and would prefer to not use em.

rcresnik-zz avatar Feb 11 '19 09:02 rcresnik-zz

I'd just like to chime in that we are in the exact same position as others. I don't think we will be able to migrate our other apps from Fabric to Firebase until there is a resolution here.

We have currently implemented a method that configures Firebase at runtime based on the bundle ID detected at runtime, with multiple config plist files.

For us, losing early analytics is by far preferable to changing our entire environment architecture.

I'd also like to point out the following changes (within the last week) to the documentation:

On iOS, do not add GoogleService-Info.plist to your project if you are supplying different configuration at run time, as this can result in an apparent change of GOOGLE_APP_ID and result in lost Analytics.

We were using the default name for production, which made us lose all reporting for other environments. @ryanwilson the following solution for configuration is working for crash-reporting:

private func dynamicallyLoadFirebaseConfiguration() {
    let bundleId = Bundle.main.bundleIdentifier
    var configFilepath: String?
    switch bundleId {
    case Global.devId:
        configFilepath = Bundle.main.path(forResource: "GoogleService-Info-Dev", ofType: "plist")
    case Global.stagingId:
        configFilepath = Bundle.main.path(forResource: "GoogleService-Info-Staging", ofType: "plist")
    default:
        configFilepath = Bundle.main.path(forResource: "GoogleService-Info-Prod", ofType: "plist")
    }
    guard let config = FirebaseOptions(contentsOfFile: configFilepath!) else {
        assert(false, "Unable to load Firebase config file")
        return
    }
    FirebaseApp.configure(options: config)
}

oflannabhra avatar Feb 20 '19 18:02 oflannabhra

Very similar issue here, where Analytics prevents us from switching configurations in runtime. Any progress on making Analytics accept dynamic configuration?

damianun avatar Feb 27 '19 09:02 damianun

Same issue here, but I can live with losing some analytics. But what I wonder about are the messages shown after that (Xcode, iOS app):

[403:42882] 5.12.0 - [Firebase/Core][I-COR000012] Could not locate configuration file: 'GoogleService-Info.plist'.
[403:42882] 5.12.0 - [Firebase/Core][I-COR000012] Could not locate configuration file: 'GoogleService-Info.plist'.

for completeness:

var options:FirebaseOptions!
...
options = FirebaseOptions.init(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-staging", ofType: "plist")!)
FirebaseApp.configure(options: options)

When I step with my debugger over the last line, this gets printed in the console. options is not nil. According to my podfile.lock Firebase/Core is 5.12.0.

ir-fuel avatar Mar 11 '19 13:03 ir-fuel