Skip to content

Firebase Authentication with SwiftUI App Lifecycle

📅 2021-01-06

Introduction

What is the SwiftUI App lifecycle?

Apple introduced the SwiftUI App Lifecycle in iOS 14 as an alternative the UIKit App Delegate. SwiftUI App Lifecycle reduces a lot of boilerplate code but is not well documented.

Libraries that hook into the app lifecycle like Firebase authentication need to bridge between the AppDelegate and App Lifecycle.

For the full code, see the github project:

https://github.com/SmoothMaverick/SwiftUIFirebaseAuthDemo

Requirements

  • XCode 12 or later
  • CocoaPods

Tutorial

This tutorial will guide you on how to implement email authentication with the SwiftUI App lifecycle.

1. Create a Firebase project

Create a Firebase project and enable email and anonymous authentication.

https://firebase.google.com/docs/ios/setup

Make sure to enable email and anonymous authentication.

2. Create SwiftUI project

a. Create a new project on XCode: - Select the "App" template

b. Enter the following: - Product Name: DemoAuthFirebase - Organization Identifier: com.demoAuthFirebase - Inteface: SwiftUI interface - Lifecycle: SwiftUI App - Language: Swift

3. Add Firebase dependencies

a. Initialize the Podfile with pod init

b. Add pods to Podfile:

# Podfile

pod 'Firebase/Auth'

c. Install pods with pod install

4. Configure Firebase

a. Add the GoogleService-Info configuration file

b. Create an AppDelegate adapter file. This will access App Delegate functions that are not available in the SwiftUI App lifecycle.

// AppDelegate.swift

class AppDelegate: NSObject, UIApplicationDelegate{
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -> Bool {

        return true
    }

    func application(
        _ application: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey : Any]
    ) -> Bool {

        return true
    }
}

c. Initialize Firebase configuration when the app launches

// AppDelegate.swift

import Firebase

...

func application(
	_ application: UIApplication,
	didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
) -> Bool {
	FirebaseApp.configure()
	
	return true
}

...

d. Use the UIApplicationDelegateAdaptor to access the App Delegate with our adapter.

// DemoFirebaseApp.swift

import SwiftUI

@main
struct DemoFirebaseApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

5. Create sign-up and sign-in buttons

Add the buttons for sign-up and sign-in. Also include fields to enter the email address and password.

// CustomAuthView.swift

import SwiftUI
import Firebase

struct CustomAuthView: View {
    @State var email : String = ""
    @State var password : String = ""
    
    var body: some View {
        VStack {
            VStack {
                TextField("Email", text: $email)
                SecureField("Password", text: $password)
            }.padding(20)

            Button(
                action: {
                    Auth.auth().createUser(withEmail: email, password: password) { (result, error) in
                        if error != nil {
                            print(error!)
                        } else {
                            print("signUp with email")
                        }
                    }
                }
            ) {
                Text("Email SignUp")
            }


            Button(
                action: {
                    Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
                        if error != nil {
                            print(error!)
                        } else {
                            print("signIn with email")
                        }
                    }
                }
            ) {
                Text("Email SignIn")
            }
        }
    }
}
  1. Create navigation link from the home view
/// ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(
                    destination: CustomAuthView()
                ) {
                    Text("Custom Authentication")
                }
            }
        }
    }
}

Check the Firebase console when testing user sign-up.

Conclusion

The app has basic functionality of authenticating and creating accounts. A more developer app should be have sign-out and handle sessions after a user authenticates.

Using libraries like Firebase authentication requires implementing both the SwiftUI App and the UIKit App Delegate lifecycles. This introduces more complexity to a project, than simply using the App Delegate lifecycle. So new projects should consider this trade-offs when deciding on which lifecycle to use.