SwiftUI 與 Firebase 認證整合:自訂 Google 登入的完整指南


摘要

本文將深入探討如何將 SwiftUI 與 Firebase 認證整合,以實現自訂 Google 登入,提升使用者體驗安全性。 歸納要點:

  • 無縫使用者體驗:SwiftUI 的介面設計結合 Firebase 認證,讓開發者輕鬆打造直觀的登入流程。
  • 強大的安全機制:Firebase 提供密碼加密和即時身分驗證,保護應用程式免受未經授權存取的威脅。
  • 自訂 Google 登入:開發者可以根據需求調整 Google 登入按鈕,提高使用者介面的一致性與品牌形象
這篇指南提供了關於如何有效整合 SwiftUI 和 Firebase 的重要資訊,幫助開發者創造更安全、便捷的登入體驗。

透過 SwiftUI 提升使用者體驗

Firebase Authentication 是一個強大的工具,讓您能夠實時儲存和同步資料。SwiftUI 則是一個現代化的 UI 框架,使得建立美觀且互動性強的使用者介面變得簡單。在本文中,我們將向您展示如何結合這兩項技術,以使用 Google 登入,若要使用 Apple 登入請點選此處。如果您想了解 Firebase 實時資料庫,請點選此處;如果您想學習如何使用 Firebase 建立網站,請點選此處。我們將從建立一個簡單的 SwiftUI 專案並新增 Firebase SDK 開始。接著,我們將建立一個模型來表示我們的自定義文字。我們會建立一個顯示 Google 登入按鈕的檢視。在本文結束時,您將知道如何利用 Firebase Authentication 和 SwiftUI 顯示 Google 登入介面。這些知識對於為任何應用程式建立身份驗證檢視非常有用,同時也簡化了檢視設計。

**1. 使用 SwiftUI 建立更直覺的 UI**:Firebase 驗證與 SwiftUI 的結合,不僅讓開發者可以使用直覺的 API 編寫 UI 程式碼,也讓他們能夠更加專注於提升使用者體驗的設計,從而簡化開發流程並增進介面的易用性和美觀性。

Firebase:無痛開發應用程式的後端即服務 (BaaS)

什麼是 Firebase?Firebase 是一個後端即服務(Backend-as-a-Service, BaaS)平台,為移動應用程式開發提供託管的後端服務。它擁有廣泛的功能,包括實時資料庫、雲端儲存、身份驗證、崩潰報告、機器學習、遠端配置以及靜態檔案的託管等。Firebase 使得開發和擴充套件應用變得簡單,而無需擔心基礎設施問題。您可以在這裡了解更多關於 Firebase 的資訊。

建立 Firebase 帳戶是一個簡單的過程。只需前往 Firebase 網站並點選「登入」按鈕。您可以使用電子郵件地址登入,也可以透過點選「註冊」按鈕建立新帳戶,然後按照相應的註冊步驟進行操作。

完成上述步驟後,您可以點選「前往控制檯」,這將帶您到以下頁面。在此之後,您就能夠開始利用 Firebase 提供的各項功能來開發您的應用程式了。

值得一提的是,**Firebase 雲端訊息 (Cloud Messaging)** 讓開發人員能夠安全地向裝置傳送訊息,而無需管理裝置憑證或協調多個平台。**Firebase ML Kit** 則提供了一系列機器學習模型,使得將機器學習功能整合至應用中變得輕而易舉,助力開發者打造更智慧、更具互動性的應用程式。
我們在研究許多文章後,彙整重點如下
網路文章觀點與我們總結
  • 保持良好的作息能提升生活品質和工作效率。
  • 運動有助於減壓,增強身體健康。
  • 飲食均衡對於精神狀態和體能表現至關重要。
  • 學習新技能可以激發大腦活力,提高自我滿足感。
  • 社交活動有助於建立人際關係,增加幸福感。
  • 定期自我反思有助於了解自己的需求與目標。

在日常生活中,我們經常忽視一些小細節,但這些卻是影響我們整體幸福感的重要因素。良好的作息、適度的運動以及均衡的飲食,不僅能提高我們的身心狀態,還能讓我們在繁忙的生活中找到平衡。此外,持續學習和參加社交活動也能帶來意想不到的快樂與成就感。透過定期反思,我們更能把握自己的方向,朝著理想生活邁進。

觀點延伸比較:
主題最新趨勢權威觀點實用建議
良好作息越來越多人關注睡眠質量,使用科技產品追蹤睡眠數據根據美國睡眠協會,成年人每晚應至少獲得7小時的高質量睡眠以提高工作效率和生活品質建立固定的作息時間,避免臨睡前使用電子產品。
運動居家健身與線上課程受歡迎,特別是瑜伽和高強度間歇訓練(HIIT)專業健身教練指出,每週至少150分鐘中等強度有氧運動能顯著減輕壓力並增強免疫系統設定每周運動計劃,結合不同類型的運動以保持新鮮感。
飲食均衡植物性飲食和超級食品逐漸成為健康飲食的新潮流,如藜麥、奇亞籽等被廣泛推崇營養學家建議攝取豐富色彩的蔬菜水果,以確保獲得必要的維生素及礦物質,提高精神狀態和體能表現準備一週餐計劃,選擇當季新鮮食材並嘗試製作健康美味的餐點。
學習新技能線上學習平台如Coursera、Udemy持續興起,使得技能提升變得更加便利心理學研究顯示,不斷挑戰自己可以促進大腦神經可塑性,有助於長期記憶與創造力發展定期參加工作坊或社區課程,在互動中激發靈感與創意。
社交活動虛擬社交工具如Zoom和Discord讓人們即使遠距離也能保持聯繫人際關係專家強調,良好的社交支持系統對心理健康至關重要,有助於減少焦慮與抑鬱症狀制定每月社交日曆,包括聚會、志願者活動或家庭聚餐等,加強人際連結。


建立專案頁面要建立一個新的應用程式,請點選「建立專案」按鈕。第一步是為您的專案命名並同意 Firebase 的使用條款。


第二步是選擇是否希望將 Google Analytics 連線到您的應用程式。


步驟二:Google Analytics 第三步是配置你的 Google Analytics。


配置 Google Analytics 等待 Firebase 建立您的專案時請稍候。


按下繼續這是專案概覽頁面。恭喜您成功設定 Firebase!本文將重點介紹 Firebase 最強大的功能之一:實時資料庫(Realtime Database)。


專案概述 要將 Firebase 加入 iOS 應用程式,您可以按下 iOS 按鈕,這將帶您進入此頁面。請依照所有步驟操作,然後點選繼續到控制檯。


將 Firebase 新增到您的 Apple 應用程式中。在您完成所有五個步驟後,我們可以開始建立資料庫。前往所有產品頁面,然後點選即時資料庫(Realtime Database)選項。


點選認證後,您將進入這個頁面。然後,按下「開始使用」按鈕。


一旦您點選了「開始」按鈕,您將會被帶到這裡。


現在點選 Google 按鈕。


翻轉啟用開關,並新增電子郵件。


點選儲存按鈕以啟用 Google 作為選項。


在使用 Xcode 時,您需要新增這個套件,這可以透過選擇檔案 -> 新增套件來完成,然後輸入以下連結,點選確切版本: https://github.com/firebase/firebase-ios-sdk。 接下來,新增 Google Service Info plist。從 Firebase 設定中下載它,在您新增應用程式之後。然後將反向客戶端 ID 放置在此處的資訊和 URL 連結下方。


第一步是對你的應用程式進行 Firebase 的配置。這個配置是在 App 結構中完成的,Firebase 在此被初始化:

import Firebase import FirebaseAuth import FirebaseCore import Foundation import GoogleSignIn import SwiftUI @main struct Firebase_Test_CodeApp: App {     init() {         FirebaseApp.configure()     } var body: some Scene {         WindowGroup {             ContentView().onOpenURL { url in                 GIDSignIn.sharedInstance.handle(url)             }         }     } }

FirebaseApp.configure(): 在應用程式啟動時初始化 Firebase。onOpenURL: 處理應用程式開啟的 URL,用於管理 Google 登入過程。Authentication 結構負責處理 Google 登入過程並管理身份驗證狀態。

struct Authentication {     func googleOauth() async throws {         guard let clientID = FirebaseApp.app()?.options.clientID else {             fatalError("No Firebase clientID found")         } let config = GIDConfiguration(clientID: clientID)         GIDSignIn.sharedInstance.configuration = config         let scene = await UIApplication.shared.connectedScenes.first as? UIWindowScene         guard let rootViewController = await scene?.windows.first?.rootViewController else {             fatalError("There is no root view controller!")         }         let result = try await GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController)         let user = result.user         guard let idToken = user.idToken?.tokenString else {             throw "Unexpected error occurred, please retry"         }         let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: user.accessToken.tokenString)         try await Auth.auth().signIn(with: credential)     }     func logout() async throws {         GIDSignIn.sharedInstance.signOut()         try Auth.auth().signOut()     } }

googleOauth: 處理 Google OAuth 流程。配置使用來自 Firebase 的客戶端 ID 進行 Google 登入。檢索根檢視控制器以呈現登入介面。使用 Google 登入使用者並獲取 ID 令牌。利用 ID 令牌與 Firebase 認證。logout: 從 Google 和 Firebase 同時登出使用者。一個擴充套件,使 String 符合 Error,簡化錯誤處理。

extension String: Error {}

應用程式的主要檢視管理身份驗證狀態,並根據使用者是否已登入來顯示登入畫面或主畫面。

struct ContentView: View {     @State private var userLoggedIn = (Auth.auth().currentUser != nil) var body: some View {         VStack {             if userLoggedIn {                 Home()             } else {                 Login()             }         }.onAppear {             Auth.auth().addStateDidChangeListener { auth, user in                 userLoggedIn = (user != nil)             }         }     } }

@State private var userLoggedIn: 一個狀態變數,用來追蹤使用者是否已登入。Auth.auth().addStateDidChangeListener: 一個監聽器,用於在認證狀態改變時更新登入狀態。登入檢視顯示 Google 登入按鈕並處理登入過程:

struct Login: View {     @State private var err: String = "" var body: some View {         Text("Login")         Button {             Task {                 do {                     try await Authentication().googleOauth()                 } catch let e {                     err = e.localizedDescription                 }             }         } label: {             HStack {                 Image(systemName: "person.badge.key.fill")                 Text("Sign in with Google")             }.padding(8)         }.buttonStyle(.borderedProminent)         Text(err).foregroundColor(.red).font(.caption)     } }

@State private var err: 一個狀態變數,用於儲存和顯示錯誤訊息。Button:啟動使用 Authentication 結構的 Google 登入流程。Home 檢視為已登入的使用者顯示問候語及登出按鈕。

struct Home: View {     @State private var err: String = "" var body: some View {         HStack {             Image(systemName: "hand.wave.fill")             Text("Hello " + (Auth.auth().currentUser!.displayName ?? "Username not found"))         }         Button {             Task {                 do {                     try await Authentication().logout()                 } catch let e {                     err = e.localizedDescription                 }             }         } label: {             Text("Log Out").padding(8)         }.buttonStyle(.borderedProminent)         Text(err).foregroundColor(.red).font(.caption)     } }

如果可用,顯示使用者的顯示名稱;若無則顯示預設訊息。按鈕:使用 Authentication 結構登出使用者。登入和主頁檢視均包含預覽,以幫助在 Xcode 的畫布中進行視覺化:這完成了在 SwiftUI 應用程式中整合 Google 登入和 Firebase 認證的過程。按照這些步驟,您可以無縫管理使用者認證,為您的應用程式提供流暢的使用者體驗。完整程式碼如下。

import Firebase import FirebaseAuth import FirebaseCore import Foundation import GoogleSignIn import SwiftUI  @main struct Firebase_Test_CodeApp: App {   init() {     FirebaseApp.configure()   }    var body: some Scene {     WindowGroup {       ContentView().onOpenURL { url in         GIDSignIn.sharedInstance.handle(url)       }     }   } }  struct Authentication {   func googleOauth() async throws {     // google sign in     guard let clientID = FirebaseApp.app()?.options.clientID else {       fatalError("no firbase clientID found")     }      // Create Google Sign In configuration object.     let config = GIDConfiguration(clientID: clientID)     GIDSignIn.sharedInstance.configuration = config      //get rootView     let scene = await UIApplication.shared.connectedScenes.first as? UIWindowScene     guard let rootViewController = await scene?.windows.first?.rootViewController     else {       fatalError("There is no root view controller!")     }      //google sign in authentication response     let result = try await GIDSignIn.sharedInstance.signIn(       withPresenting: rootViewController     )     let user = result.user     guard let idToken = user.idToken?.tokenString else {       throw "Unexpected error occurred, please retry"     }      //Firebase auth     let credential = GoogleAuthProvider.credential(       withIDToken: idToken, accessToken: user.accessToken.tokenString     )     try await Auth.auth().signIn(with: credential)   }    func logout() async throws {     GIDSignIn.sharedInstance.signOut()     try Auth.auth().signOut()   } }  extension String: Error {}  struct ContentView: View {   @State private var userLoggedIn = (Auth.auth().currentUser != nil)    var body: some View {     VStack {       if userLoggedIn {         Home()       } else {         Login()       }     }.onAppear {       Auth.auth().addStateDidChangeListener { auth, user in         if user != nil {           userLoggedIn = true         } else {           userLoggedIn = false         }       }     }   } }  struct Login: View {   @State private var err: String = ""    var body: some View {     Text("Login")     Button {       Task {         do {           try await Authentication().googleOauth()         } catch let e {           err = e.localizedDescription         }       }     } label: {       HStack {         Image(systemName: "person.badge.key.fill")         Text("Sign in with Google")       }.padding(8)     }.buttonStyle(.borderedProminent)      Text(err).foregroundColor(.red).font(.caption)   } }  #Preview {   Login() }  struct Home: View {   @State private var err: String = ""    var body: some View {     HStack {       Image(systemName: "hand.wave.fill")       Text(         "Hello " + (Auth.auth().currentUser!.displayName ?? "Username not found")       )     }     Button {       Task {         do {           try await Authentication().logout()         } catch let e {           err = e.localizedDescription         }       }     } label: {       Text("Log Out").padding(8)     }.buttonStyle(.borderedProminent)      Text(err).foregroundColor(.red).font(.caption)   } }  #Preview {   Home() }

如果你讀到這裡,請鼓掌。

參考來源


MZ

專家

相關討論

❖ 相關專欄