【在 iOS 开发路上的大小事-Day18】透过 Firebase 来管理使用者 (Sign in with Google 篇) Part2

昨天我们已经将前置作业,也就是 URL Types、AppDelegate.swift 完成了,今天我们要来把剩下的帐号登入以及帐号登出功能来实作完成

画面设计

我们先在 Storyboard/Xib 上拉出一个 UIView,然後将他的 class 改为「GIDSignInButton」,然後再拉出一个 UIButton,用来帐号登出

两个 Button 元件的 IBOutlet 如下

@IBOutlet weak var signInWithGoogleBtn: GIDSignInButton!
@IBOutlet weak var signOutBtn: UIButton!

Sign in with Google 功能实作

在 GIDSignInButton 这个 Button 的 IBAction 加入下面这段
我们透过 GIDSignIn 这个物件来进行 Google 帐号登入
首先,先宣告一个 clientID 常数,这个我们可以透过 Firebase 来取得
然後再宣告一个 config 常数,用来储存 clientID 的资讯
然後就可以透过 GIDSignIn.sharedInstance.signIn() 来进行 Google 帐号登入
登入成功後,Google 会回传使用者的 idToken 跟 accessToken
接着就可以用 GoogleAuthProivder.credential() 来产生该使用者的 Credential (凭证)
後面就可以透过这个凭证来与 Firebase 串接在一起了

@IBAction func signInWithGoogle(_ sender: Any) {
    self.signInWithGoogle()
}

// 登入帐号
func signInWithGoogle() {
    guard let clientID = FirebaseApp.app()?.options.clientID else { return }
    let config = GIDConfiguration(clientID: clientID) // 创建 Google Sign In Config 物件
    GIDSignIn.sharedInstance.signIn(with: config, presenting: self) { [unowned self] user, error in
        guard error == nil else {
            CustomFunc.customAlert(title: "", message: "\(String(describing: error!.localizedDescription))", vc: self, actionHandler: nil)
            return
        }
        guard let authentication = user?.authentication, let idToken = authentication.idToken else { return }
        let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: authentication.accessToken)
        self.firebaseSignInWithGoogle(credential: credential)
    }
}

// 将上面从 Google 登入後的资讯,告诉 Firebase
func firebaseSignInWithGoogle(credential: AuthCredential) {
    Auth.auth().signIn(with: credential) { authResult, error in
        guard error == nil else {
            CustomFunc.customAlert(title: "", message: "\(String(describing: error!.localizedDescription))", vc: self, actionHandler: nil)
            return
        }
        CustomFunc.customAlert(title: "登入成功!", message: "", vc: self, actionHandler: self.getFirebaseUserInfo)
    }
}

然後帐号登出的部分如下,直接透过 Firebase 提供的 signOut() API 和 GIDSignIn 提供的 signOut() API 就可以轻松实作了

@IBAction func googleAccountSignOut(_ sender: UIButton) {
    self.googleAccountSignOut()
}

// 登出帐号
func googleAccountSignOut() {
    do {
        try Auth.auth().signOut()
        GIDSignIn.sharedInstance.signOut()
        CustomFunc.customAlert(title: "帐号已登出!", message: "", vc: self, actionHandler: nil)
        self.isSignIn = false
    } catch let error as NSError {
        CustomFunc.customAlert(title: "", message: "\(String(describing: error.localizedDescription))", vc: self, actionHandler: nil)
    }
}

如果要取得已登入使用者的资讯,也很简单,只要加入下面这段就可以了

// MARK: - Firebase 取得登入使用者的资讯
func getFirebaseUserInfo() {
    let currentUser = Auth.auth().currentUser
    guard let user = currentUser else {
        CustomFunc.customAlert(title: "使用者资讯", message: "无法取得使用者资料", vc: self, actionHandler: nil)
        return
    }
    let uid = user.uid
    let email = user.email
    let name = user.displayName
    CustomFunc.customAlert(title: "使用者资讯", message: "User Name:\(name!)\nUID:\(uid)\nEmail:\(email!)", vc: self, actionHandler: nil)
}

成果

本篇的范例程序码:Github


<<:  DAY15-EXCEL统计分析:Z检定介绍

>>:  虹语岚访仲夏夜-16(打杂的Allen篇)

伸缩自如的Flask [day 27] Supervisor

像gunicorn 及docker 有着执行时timeout的防止错误发生的机制, 但是要是超过了 ...

OK集#29-白话文Excel-公式现形记

话说,我曾经教过大家,如何让整个工作表的公式们现形 但有的时候,在文件交接或说明时,我们不需要把整张...

【C++】Binary Search Tree

Binary Search Tree的优势在於寻找、插入的时间复杂度较低,它只需要O(log n)~...

[Day 21] 测试的型态调整,谈单元测试与整合测试

我们测试过了几个案例,像是 测试更新标签时如过滤Admin,结果应不出现Admin 和 测试更新标签...

Tailwind CSS 中的样式渲染顺序

如果你 tailwind 已经写一段时间了,相信你有时候也会想把因为 tailwind 语法而变的很...