Module 3, Lessons 1-2 : Firebase Authentication

Lesson 1 : Introduction

In the introduction to the Firebase Authentication module from the CWC+ iOS Database course, Chris takes us through the familiar steps of setting up a new Xcode / Firebase project while introducing us to the extra steps needed to enable authentication.

With Google making it fairly straightforward to use their services, it’s no wonder it’s popular with app developers. For me, I can’t wait until I know enough of this stuff that I won’t need such reliance on Google’s products.

We’re only going to be dealing with simple email / password authentication in this module, so we just need these additional pods in our Podfile, re:

pod 'Firebase/Auth'
pod 'FirebaseUI/Auth'
pod 'FirebaseUI/Email'

The FirebaseUI lines there are needed because we’ll be using Google‘s “drop in” methods first, before going ahead and coding our own.

Lesson 2 : Firebase Drop In Auth UI

Lesson 2 takes us through the methods that Google offers up to allow us to use their “drop in UI” for authentication. It should be easy enough, only it isn’t.

Since the tutorial video was made, Firebase changed. There’s a note appended to the lesson stating that where the video says to import FirebaseUI, we should now use import FirebaseEmailAuthUI.

Okay, that’s not a deal breaker but Xcode continually flags up a warning error that reads thus:

Firebase Authentication/xcode/Firebase Auth Demo/Pods/FirebaseEmailAuthUI/FirebaseEmailAuthUI/Sources/FUIEmailAuth.m:715:41: 'archivedDataWithRootObject:' is deprecated: first deprecated in iOS 12.0 - Use +archivedDataWithRootObject:requiringSecureCoding:error: instead

This is linked to the FirebaseEmailAuthUI that we’ve just been told to use because we shouldn’t use FirebaseUI any more.

This highlights the very real problem of using third-party sources to cut corners and “make things easy” for us – they can change on a whim. In the time I’ve been learning iOS Application Development, we’ve had numerous updates to Xcode which have caused errors in the lesson tutorials, the infamous “missing info.plist” for example, and now we’re using Firebase which not only seems to have moved away from CocoaPods that the tutorials use, but also the code used is deprecated on a whim.

When I wrote my own web applications using PHP & MySQL / MariaDB, I hosted everything on my own virtual server(s). I knew exactly which versions of PHP & MySQL / MariaDB I was using, and my PHP code didn’t require third-party “help” to talk to the database. PHP & MySQL / MariaDB would only be updated when I decided to update it, and when I was ready to update my code.

Here we’re relying on third-party solutions that change on a whim and have the potential to cripple your app without you even knowing it’s done it, what it’s done, or how to fix it. This doesn’t sit comfortably with me.

Anyway, the essential code for using the drop-in authenticaiton solution uses this fairly convoluted method of calling the login:

import Foundation
import SwiftUI
import FirebaseEmailAuthUI

struct LoginForm: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> UINavigationController {
        let authUI = FUIAuth.defaultAuthUI()
        guard authUI != nil else {
            return UINavigationController()
        }
        let providers = [FUIEmailAuth()]
        authUI!.providers = providers
        return authUI!.authViewController()
    }

    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
        
    }
}

I’m at a loss to offer any insight into how it works, I just know from the tutorial that it does and that both methods need to be present. All this notwithstanding the Xcode warning mentioned above, of course.

This code allows us to throw up a “Sign In” text button and then use the drop-in solution to either log the user in, or create a new user:

import SwiftUI
import FirebaseEmailAuthUI

struct LaunchView: View {
    @State var loggedIn = false
    @State var loginFormShowing = false
    var body: some View {
        if !loggedIn {
            Button {
                loginFormShowing = true
            } label: {
                Text("Sign In")
            }
            .sheet(isPresented: $loginFormShowing, onDismiss: checkLogin) {
                LoginForm()
            }
            .onAppear {
                checkLogin()
            }
        }
        else {
            ContentView(loggedIn: $loggedIn)
        }
    }
    
    func checkLogin() {
        loggedIn = FUIAuth.defaultAuthUI()?.auth?.currentUser == nil ? false : true
    }
}

We have a straightforward ContentView file that just contains a message and an option to log-out:

import SwiftUI
import FirebaseEmailAuthUI

struct ContentView: View {
    @Binding var loggedIn: Bool
    var body: some View {
        Text("Welcome!")
        Button {
            try! FUIAuth.defaultAuthUI()?.signOut()
            loggedIn = false
        } label: {
            Text("Sign out!")
        }
    }
}

And, the main file that kicks it all off:

import SwiftUI
import Firebase

@main
struct Firebase_Auth_DemoApp: App {
    init() {
        FirebaseApp.configure() 
    }
    var body: some Scene {
        WindowGroup {
            LaunchView()
        }
    }
}

I shall be rereading this a few times to get my head around as much of what Firebase requires us to do as I can.