【iOS】#10 訂飲料APP|Part.4 註冊、登入、設定使用者名稱 — Firebase Authentication

前情提要 — 可不可飲料訂購APP為系列文章,初步規劃分為四篇文章介紹以下四大頁面及功能:

・註冊登入頁面:使用者註冊登入及訪客登入|Firebase 身份驗證
・Menu菜單頁面:串接 Airtable API 呈現飲料菜單|GET
・飲料訂購頁面:新增飲料訂單|POST
・訂購清單頁面:編輯、刪除訂單|PATCH、DELETE

本篇為註冊登入頁面

🌟 本篇重點功能

  1. 主頁設置、訪客登入、避免鍵盤遮擋內容
  2. Firebase 登入、登出
  3. Firebase 註冊、設定使用者名稱
不同登入方式,顯示訂購者名稱(訪客登入、帳密登入、註冊登入)

功能介紹

(AutoLaout 畫面的程式碼較多,以下皆省略,完整程式碼可參考文章最後附上的 GitHub 連結)

① 主頁設置、訪客登入、避免鍵盤遮擋內容

訪客登入,訂單顯示訪客名稱

1. 主頁設置

MainLoginViewController — 設置 UITextField

用於輸入訪客名稱

import UIKit

class MainLoginViewController: UIViewController {

// 訪客名稱輸入框
let guestLoginTextField = UITextField()

override func viewDidLoad() {
super.viewDidLoad()

// 設置UITextField的delegate為self
guestLoginTextField.delegate = self
}

}

// MARK: - UITextFieldDelegate方法
extension MainLoginViewController: UITextFieldDelegate {

// 用戶點擊Return鍵時被調用
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// 關閉鍵盤
textField.resignFirstResponder()
return true
}

}

MainLoginViewController — 設置 UIButton

用於訪客登入、顯示登入頁面、顯示註冊頁面

class MainLoginViewController: UIViewController {

// 訪客登入、帳密登入、註冊按鈕
let guestLoginButton = UIButton()
let loginButton = UIButton()
let registerButton = UIButton()

override func viewDidLoad() {
super.viewDidLoad()

// 綁定按鈕功能
guestLoginButton.addTarget(self, action: #selector(guestLogin), for: .touchUpInside)
loginButton.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
registerButton.addTarget(self, action: #selector(registerButtonTapped), for: .touchUpInside)
}

// 帳密登入
@objc func loginButtonTapped() {
let loginViewController = LoginViewController()
present(loginViewController, animated: true)
}

// 註冊
@objc func registerButtonTapped() {
let registerViewController = RegisterViewController()
present(registerViewController, animated: true)
}

}
主頁設置(UITextField、UIButton

2. 訪客登入功能

MainLoginViewController — guestLogin

用於訂單顯示訪客名稱

class MainLoginViewController: UIViewController {   

// 錯誤訊息
let errorMessage = UILabel()

// 在訪客登入成功時調用,執行後續操作
var onLoginSuccess: ((String) -> Void)?

@objc func guestLogin() {

// 檢查訪客名稱不為空值
let userName = guestLoginTextField.text ?? ""
if userName == "" {
errorMessage.text = "請輸入訪客名稱" // 訪客名稱為空,顯示錯誤訊息
} else {

// 訪客登入成功時傳入訪客名稱
onLoginSuccess?(userName)

// 關閉視窗
self.dismiss(animated: true)
}
}

}
訪客登入,訂單顯示訪客名稱

3. 避免鍵盤遮擋內容

RegisterViewController — Keyboard

使用文字輸入框時,避免鍵盤擋住螢幕 (畫面需搭配scrollView)

(因註冊頁面文字輸入框較多,以註冊頁面為例)

class RegisterViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// 添加點擊手勢
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
view.addGestureRecognizer(tapGesture)

// 訂閱鍵盤彈出和隱藏的通知
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

deinit {
// 在視圖控制器銷毀時取消訂閱通知
NotificationCenter.default.removeObserver(self)
}

// 點擊手勢觸發
@objc func hideKeyboard() {
view.endEditing(true) // 收起所有正在編輯的元素的鍵盤
}

// 鍵盤彈出觸發
@objc func keyboardWillShow(_ notification: Notification) {

// 獲取鍵盤的高度
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
return
}
// 設置 scrollView 的內容偏移量,使文本字段在鍵盤上方可見
scrollView.contentInset.bottom = keyboardSize.height
}

// 鍵盤隱藏觸發
@objc func keyboardWillHide(_ notification: Notification) {

// 隱藏鍵盤時重置 scrollView 的內容偏移量
scrollView.contentInset = .zero
}

}
避免鍵盤遮擋內容

② FireBase 登入、登出

FireBase 登入、登出

1. FireBase 登入

LoginViewController — login

import FirebaseAuth

class LoginViewController: UIViewController {

@objc func login() {

// 獲取用戶輸入的帳號、密碼
let email = accountTextField.text!
let password = passwordTextField.text!

// Firebase登入
Auth.auth().signIn(withEmail: email, password: password) { result, error in
guard error == nil else {

// 登入失敗,顯示錯誤訊息
self.errorMessage.text = "\(error!.localizedDescription)"
return
}

// 登入成功,關閉視窗
self.dismiss(animated: true) {
NotificationCenter.default.post(name: Notification.Name("dismissMainLoginView"), object: nil)
}
}
}

}
FireBase 登入

2. FireBase 登出

MenuViewController — logout

class MenuViewController: UIViewController {

@objc func logout() {
// Firebase登出
do {
try Auth.auth().signOut()
} catch {
print(error)
}
}

}
FireBase 登出

③ FireBase 註冊、設定使用者名稱

註冊成功後自動登入 APP,訂單顯示使用者名稱

1. FireBase 註冊

RegisterViewController — register

import FirebaseAuth

class RegisterViewController: UIViewController {

// 錯誤訊息
let errorMessage = UILabel()
// 註冊按鈕
let registerButton = UIButton()

override func viewDidLoad() {
super.viewDidLoad()
// 綁定註冊按鈕功能
registerButton.addTarget(self, action: #selector(register), for: .touchUpInside)
}

@objc func register() {

// 獲取用戶輸入的帳號、密碼、暱稱
let email = accountTextField.text!
let password = passwordTextField.text!
let userName = userNameTextField.text

// 檢查暱稱不為空值
if userName == "" {
errorMessage.text = "請輸入您的暱稱" // 暱稱為空,顯示錯誤訊息
} else {

// Firebase註冊
Auth.auth().createUser(withEmail: email, password: password) { result, error in
guard let user = result?.user, error == nil else {

// 註冊失敗,顯示錯誤訊息
self.errorMessage.text = "\(error!.localizedDescription)"
return
}

// 註冊成功
print("success")

// 關閉視窗
self.dismiss(animated: true) {
NotificationCenter.default.post(name: Notification.Name("dismissMainLoginView"), object: nil)
}
}
}

}

}
FireBase 註冊(註冊成功後自動登入 APP)

2. FireBase 設定使用者名稱

RegisterViewController — register

import FirebaseAuth

class RegisterViewController: UIViewController {

@objc func register() {

// ...

// Firebase註冊
Auth.auth().createUser(withEmail: email, password: password) { result, error in

// 註冊失敗,顯示錯誤訊息...

// 註冊成功,設定使用者名稱(暱稱)
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = userName
changeRequest?.commitChanges(completion: { error in
guard error == nil else {

// 設定使用者名稱失敗,顯示錯誤訊息
self.errorMessage.text = "\(error!.localizedDescription)"
return
}

// 設定使用者成功,註冊完成後關閉視窗
self.dismiss(animated: true) {
NotificationCenter.default.post(name: Notification.Name("dismissMainLoginView"), object: nil)
}
})
}
}

}

}

FireBase 取得使用者名稱

(以加入購物車功能為例)

@objc func addToCart() {

// 檢查是否為帳號登入,取得使用者名稱
if let user = Auth.auth().currentUser {
userName = user.displayName!
}

// 設置訂單內容、POST...
}
FireBase 取得使用者名稱,於訂單顯示

註冊、設定使用者名稱 — 完整程式碼

import FirebaseAuth

class RegisterViewController: UIViewController {

// 錯誤訊息
let errorMessage = UILabel()
// 註冊按鈕
let registerButton = UIButton()

override func viewDidLoad() {
super.viewDidLoad()
// 綁定註冊按鈕功能
registerButton.addTarget(self, action: #selector(register), for: .touchUpInside)
}

@objc func register() {

// 獲取用戶輸入的帳號、密碼、暱稱
let email = accountTextField.text!
let password = passwordTextField.text!
let userName = userNameTextField.text

// 檢查暱稱不為空值
if userName == "" {
errorMessage.text = "請輸入您的暱稱" // 暱稱為空,顯示錯誤訊息
} else {

// Firebase註冊
Auth.auth().createUser(withEmail: email, password: password) { result, error in
guard let user = result?.user, error == nil else {
// 註冊失敗,顯示錯誤訊息
self.errorMessage.text = "\(error!.localizedDescription)"
return
}
// 註冊成功,設定使用者名稱(暱稱)
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = userName
changeRequest?.commitChanges(completion: { error in
guard error == nil else {
// 設定使用者名稱失敗,顯示錯誤訊息
self.errorMessage.text = "\(error!.localizedDescription)"
return
}
// 設定使用者成功,註冊完成後關閉視窗
self.dismiss(animated: true) {
NotificationCenter.default.post(name: Notification.Name("dismissMainLoginView"), object: nil)
}
})
}
}

}

}

--

--