App Crashing When Using Firebase Auth, Reason: 'Default App Has Already Been Configured.'

FirebaseApp.configure() crashes app on launch

To answer my own question. I have solved this issue basically by removing Firebase/Core pod from every project/target in Podfile and add everything Firebase related to the main app target including Firebase/Analytics pod (that means removing it from every other project/target).

After running pod install I moved all files that used FirebaseAnalytics from custom framework to the main project (target). Now everything works as expected and calling [FIRApp configure]; does not crash the application.

Podfile now looks something like this:

target 'TheApp' do
platform :ios, '11.0'
project 'TheApp/TheApp.xcodeproj'
use_frameworks!
pod 'Firebase/Analytics'
pod 'Firebase/Auth'
pod 'Firebase/Messaging'
pod 'Firebase/RemoteConfig'
end

target 'TheCustomFramework' do
platform :ios, '11.0'
project 'TheCustomFramework/TheCustomFramework.xcodeproj'
use_frameworks!
end

The default app has not been configured yet

Here's the answer to your problem:

To configure Firebase you have to execute FIRApp.configure() somewhere. After this is done you can use let firebaseDatabaseReference = FIRDatabase.database().reference() to get a reference to that database and start using it. The problem isn't with Firebase "per se" but with how Swift behaves.

If you put FIRApp.configure() in your AppDelegate func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool and then in the MyDatabase class you use let firebaseDatabaseReference = FIRDatabase.database().reference() outside of your declared functions sometimes the code FIRDatabase.database().reference() executes before the application didFinishLaunchingWithOptions function is executed.

Essentially your class is trying to get a reference to the Firebase database before it has a chance to configure itself, generating the error in the console "The default app has not been configured yet."

Note: This doesn't happen all the time, sometimes the application is slow to start, in iOS Simulator for example, and it doesn't have a chance to finish before MyDatabase "let" executes and tries to get a reference.

That is why moving the FIRApp.configure() code to override init() in AppDelegate works, essentially it makes sure the configure code gets executed when AppDelegate is initialised (in this and most cases, before MyDatabase is initialised)

override init() {
super.init()
FIRApp.configure()
// not really needed unless you really need it FIRDatabase.database().persistenceEnabled = true
}

Also make sure you super.init() (so you super classes get the "message") so you override doesn't do more harm than good.

Firebase Auth user is outdated when using shared user access group

The documentation states:

Note: Shared keychain does not automatically update users across apps in real time. If you make a change to a user in one app, the user must be reloaded in any other shared keychain apps before the changes will be visible.

Here's some code to get you started:

func refreshUser() {
do {
let currentUser = Auth.auth().currentUser
let sharedUser = try Auth.auth().getStoredUser(forAccessGroup: accessGroup)
print("Current user: \(String(describing: currentUser)), shared User: \(sharedUser.uid)")
if currentUser != sharedUser {
updateUser(user: sharedUser)
}
}
catch {
do {
try Auth.auth().signOut()
}
catch {
print("Error when trying to sign out: \(error.localizedDescription)")
}
}
}

func updateUser(user: User) {
Auth.auth().updateCurrentUser(user) { error in
if let error = error {
print("Error when trying to update the user: \(error.localizedDescription)")
}
}
}

The following code shows how to use this in your main SwiftUI app, but can be easily adapted to a Widget:

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(authenticationService)
}
.onChange(of: scenePhase) { phase in
print("Current phase \(phase)")
if let user = Auth.auth().currentUser {
print("User: \(user.uid)")
}
else {
print("No user present")
}

if phase == .active {
// Uncomment this to refresh the user once the app becomes active
authenticationService.refreshUser()
}
}
}


Related Topics



Leave a reply



Submit