Firebase iOS 程式碼研究室 Swift

Firebase iOS Codelab Swift

程式碼研究室簡介

subject上次更新時間:11月 1, 2024
account_circle作者:Google 員工

1. 總覽

2efe6805ef369641.png

歡迎使用 Friendly Chat 程式碼研究室。在本程式碼研究室中,您將瞭解如何使用 Firebase 平台建立 iOS 應用程式。您將實作即時通訊用戶端,並使用 Firebase 監控其效能。

課程內容

  • 允許使用者登入。
  • 使用 Firebase 即時資料庫同步處理資料。
  • 將二進位檔案儲存在 Firebase Storage 中。

事前準備

  • Xcode
  • CocoaPods
  • 搭載 iOS 8.0 以上版本的測試裝置或模擬器

您要如何使用這個教學課程?

您對建構 iOS 應用程式的體驗評價如何?

2. 取得程式碼範例

從指令列複製 GitHub 存放區。

$ git clone https://github.com/firebase/codelab-friendlychat-ios

3. 建構範例應用程式

2f4c98d858c453fe.png

如要建構範例應用程式,請按照下列步驟操作:

  1. 在終端機視窗中,前往您下載的範例程式碼中的 android_studio_folder.pngios-starter/swift-starter 目錄
  2. 執行 pod install --repo-update
  3. 開啟 FriendlyChatSwift.xcworkspace 檔案,即可在 Xcode 中開啟專案。
  4. 按一下「Run」按鈕。98205811bbed9d74.png

幾秒後,你應該會看到 Friendly Chat 主畫面。畫面上應會顯示 UI。不過,你目前無法登入、傳送或接收訊息。在您完成下一個步驟之前,應用程式會中止並顯示例外狀況。

4. 在 Firebase 主控台中建立專案

建立專案

Firebase 主控台中,選取「新增專案」

呼叫專案 FriendlyChat,然後按一下「Create Project」

Screenshot from 2015-11-06 14:13:39.png

升級 Firebase 定價方案

如要使用 Cloud Storage for Firebase,您的 Firebase 專案必須採用即付即用 (Blaze) 定價方案,也就是說已連結至 Cloud Billing 帳戶

  • 您必須提供付款方式 (例如信用卡),才能建立 Cloud Billing 帳戶。
  • 如果您是 Firebase 和 Google Cloud 的新手,請確認您是否符合$300 美元的抵免額和免費試用 Cloud Billing 帳戶的資格。
  • 如果您是為了參加活動而進行這個程式碼研究室,請向活動主辦單位詢問是否有任何 Cloud 抵用金。

如要將專案升級至 Blaze 方案,請按照下列步驟操作:

  1. 在 Firebase 控制台中,選取「升級方案」
  2. 選取 Blaze 方案。按照畫面上的指示將 Cloud Billing 帳戶連結至專案。
    如果您需要在升級過程中建立 Cloud Billing 帳戶,可能需要返回 Firebase 控制台的升級流程,才能完成升級。

連結 iOS 應用程式

  1. 在新專案的「專案總覽」畫面中,按一下「將 Firebase 加入您的 iOS 應用程式」
  2. 輸入套件 ID,例如「com.google.firebase.codelab.FriendlyChatSwift」。
  3. 將 App Store ID 輸入為「123456」。
  4. 按一下「註冊應用程式」

將 GoogleService-Info.plist 檔案新增至應用程式

在第二個畫面中,按一下「Download GoogleService-Info.plist」,下載包含應用程式所有必要 Firebase 中繼資料的設定檔。將該檔案複製到應用程式,然後新增至 FriendlyChatSwift 目標。

您現在可以按一下彈出式視窗右上角的「x」關閉視窗,並略過步驟 3 和 4,因為您會在本頁面執行這兩個步驟。

19d59efb213ddbdc.png

匯入 Firebase 模組

首先,請確認已匯入 Firebase 模組。

AppDelegate.swiftFCViewController.swift

import Firebase

在 AppDelegate 中設定 Firebase

請在 application:didFinishLaunchingWithOptions 函式內使用 FirebaseApp 中的「configure」方法,從 .plist 檔案設定基礎 Firebase 服務。

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions
: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
 
FirebaseApp.configure()
 
GIDSignIn.sharedInstance().delegate = self
 
return true
}

5. 找出使用者

使用規則限制已驗證的使用者

我們現在會新增規則,要求使用者在讀取或寫入任何訊息前先進行驗證。為此,我們在訊息資料物件中新增下列規則。在 Firebase 主控台的「資料庫」區段中,選取「即時資料庫」,然後按一下「規則」分頁標籤。然後更新規則,使其如下所示:

{
 
"rules": {
   
"messages": {
     
".read": "auth != null",
     
".write": "auth != null"
   
}
 
}
}

如要進一步瞭解這項功能的運作方式 (包括「auth」變數的說明文件),請參閱 Firebase 安全性說明文件

設定驗證 API

您必須先啟用 Firebase 驗證 API,應用程式才能代表使用者存取這些 API

  1. 前往 Firebase 主控台,然後選取所需專案
  2. 選取「驗證」
  3. 選取「Sign In Method」分頁標籤
  4. 將「Google」切換鈕切換為啟用 (藍色)
  5. 在隨即顯示的對話方塊中按下「儲存」

如果您在稍後的程式碼研究室中收到「CONFIGURATION_NOT_FOUND」錯誤訊息,請返回這個步驟,仔細檢查您的工作。

確認 Firebase Auth 依附元件

確認 Podfile 檔案中含有 Firebase Auth 依附元件。

Podfile

pod 'Firebase/Auth'

設定 Google 登入的 Info.plist。

您需要在 XCode 專案中新增自訂網址配置。

  1. 開啟專案設定:在左側樹狀檢視畫面中,按兩下專案名稱。在「TARGETS」(目標) 部分選取應用程式,然後選取「Info」(資訊) 分頁,並展開「URL Types」(網址類型) 部分。
  2. 按一下 + 按鈕,然後為已反轉的客戶端 ID 新增網址配置。如要找出這個值,請開啟 GoogleService-Info.plist 設定檔,然後尋找 REVERSED_CLIENT_ID 鍵。複製該鍵的值,然後貼到設定頁面中的「網址配置」方塊。將其他欄位留空。
  3. 完成後,設定應類似於以下內容 (但會顯示應用程式專屬的值):

1b54d5bd2f4f1448.png

為 Google 登入設定用戶端 ID

設定 Firebase 後,我們可以使用 clientID 在「didFinishLaunchingWithOptions:」方法中設定 Google 登入功能。

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions
: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
 
FirebaseApp.configure()
 
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
 
GIDSignIn.sharedInstance().delegate = self
 
return true
}

新增登入處理常式

Google 登入結果成功後,請使用該帳戶透過 Firebase 進行驗證。

AppDelegate.swift

  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
   
if let error = error {
     
print("Error \(error)")
     
return
   
}

    guard let authentication
= user.authentication else { return }
    let credential
= GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                      accessToken
: authentication.accessToken)
   
Auth.auth().signIn(with: credential) { (user, error) in
     
if let error = error {
       
print("Error \(error)")
       
return
     
}
   
}
 
}

自動登入使用者。接著,請在 Firebase 驗證中新增監聽器,讓使用者在成功登入後進入應用程式。並在 deinit 時移除事件監聽器。

SignInViewController.swift

  override func viewDidLoad() {
   
super.viewDidLoad()
   
GIDSignIn.sharedInstance().uiDelegate = self
   
GIDSignIn.sharedInstance().signInSilently()
    handle
= Auth.auth().addStateDidChangeListener() { (auth, user) in
     
if user != nil {
       
MeasurementHelper.sendLoginEvent()
       
self.performSegue(withIdentifier: Constants.Segues.SignInToFp, sender: nil)
     
}
   
}
 
}

  deinit
{
   
if let handle = handle {
     
Auth.auth().removeStateDidChangeListener(handle)
   
}
 
}

登出

新增登出方法

FCViewController.swift

  @IBAction func signOut(_ sender: UIButton) {
    let firebaseAuth
= Auth.auth()
   
do {
     
try firebaseAuth.signOut()
      dismiss
(animated: true, completion: nil)
   
} catch let signOutError as NSError {
     
print ("Error signing out: \(signOutError.localizedDescription)")
   
}
 
}

以已登入使用者的身分測試讀取訊息

  1. 按一下「Run」按鈕。98205811bbed9d74.png
  2. 系統應會立即將您導向登入畫面。輕觸「Google 登入」按鈕。
  3. 如果一切順利,系統就會將你導向訊息畫面。

6. 啟用即時資料庫

2efe6805ef369641.png

匯入訊息

Firebase 主控台的專案中,選取左側導覽列的「資料庫」項目。在資料庫的溢位選單中,選取「Import JSON」。瀏覽 friendlychat 目錄中的 initial_messages.json 檔案,選取該檔案,然後按一下「Import」按鈕。這麼做會取代資料庫中目前的所有資料。您也可以直接編輯資料庫,使用綠色 + 和紅色 x 新增及移除項目。

20ccf4856b715b4c.png

匯入後,資料庫應如下所示:

f3e0367f1c9cd187.png

確認 Firebase 資料庫依附元件

Podfile 檔案的依附元件區塊中,確認是否已納入 Firebase/Database

Podfile

pod 'Firebase/Database'

同步處理現有訊息

新增程式碼,將新加入的訊息同步至應用程式 UI。

您在本節中新增的程式碼會執行以下操作:

  • 初始化 Firebase 資料庫,並新增事件監聽器來處理資料庫的變更。
  • 更新 DataSnapshot,即可顯示新訊息。

修改 FCViewController 的「deinit」、「configureDatabase」和「tableView:cellForRow indexPath:」方法,並替換為下方定義的程式碼:

FCViewController.swift

  deinit {
   
if let refHandle = _refHandle {
     
self.ref.child("messages").removeObserver(withHandle: _refHandle)
   
}
 
}


  func configureDatabase
() {
   
ref = Database.database().reference()
   
// Listen for new messages in the Firebase database
    _refHandle
= self.ref.child("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
      guard let strongSelf
= self else { return }
      strongSelf
.messages.append(snapshot)
      strongSelf
.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
   
})
 
}


  func tableView
(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   
// Dequeue cell
    let cell
= self.clientTable.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
   
// Unpack message from Firebase DataSnapshot
    let messageSnapshot
= self.messages[indexPath.row]
    guard let message
= messageSnapshot.value as? [String: String] else { return cell }
    let name
= message[Constants.MessageFields.name] ?? ""
    let text
= message[Constants.MessageFields.text] ?? ""
    cell
.textLabel?.text = name + ": " + text
    cell
.imageView?.image = UIImage(named: "ic_account_circle")
   
if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
        let data
= try? Data(contentsOf: URL) {
      cell
.imageView?.image = UIImage(data: data)
   
}
   
return cell
 
}

測試訊息同步功能

  1. 按一下「Run」按鈕。98205811bbed9d74.png
  2. 按一下「登入並開始使用」按鈕,前往訊息視窗。
  3. 如要直接在 Firebase 主控台中新增訊息,請按一下「messages」項目旁的綠色 + 符號,然後新增下列類似的物件:f9876ffc8b316b14.png
  4. 確認 Friendly-Chat UI 中是否顯示這些內容。

7. 可傳送訊息

實作 Send Message

將值推送至資料庫。使用推送方法將資料新增至 Firebase 即時資料庫時,系統會自動新增 ID。這些自動產生的 ID 是依序排列,可確保新訊息會以正確的順序加入。

修改 FCViewController 的「sendMessage:」方法,並替換為下方定義的程式碼:

FCViewController.swift

  func sendMessage(withData data: [String: String]) {
   
var mdata = data
    mdata
[Constants.MessageFields.name] = Auth.auth().currentUser?.displayName
   
if let photoURL = Auth.auth().currentUser?.photoURL {
      mdata
[Constants.MessageFields.photoURL] = photoURL.absoluteString
   
}

   
// Push data to Firebase Database
   
self.ref.child("messages").childByAutoId().setValue(mdata)
 
}

測試傳送訊息

  1. 按一下「Run」按鈕。98205811bbed9d74.png
  2. 按一下「登入」即可前往訊息視窗。
  3. 輸入訊息內容,然後按下「傳送」。新的訊息應會顯示在應用程式 UI 和 Firebase 主控台中。

8. 儲存及接收圖片

確認 Firebase 儲存空間依附元件

Podfile 的依附元件區塊中,確認已納入 Firebase/Storage

Podfile

pod 'Firebase/Storage'

設定 Cloud Storage for Firebase

以下說明如何在 Firebase 專案中設定 Cloud Storage for Firebase:

  1. 在 Firebase 主控台的左側面板中,展開「Build」,然後選取「Storage」
  2. 按一下「開始使用」
  3. 選取預設儲存體值區的位置。
    US-WEST1US-CENTRAL1US-EAST1 中的值區可使用 Google Cloud Storage 的「永遠免費」方案。其他所有位置的值區都會遵循 Google Cloud Storage 的定價和用量
  4. 按一下「以測試模式啟動」。請詳閱安全性規則免責事項。
    在本程式碼研究室的後續部分,您將新增安全性規則來保護資料。請勿發布或公開應用程式,否則請為儲存空間值區新增安全規則。
  5. 按一下「建立」

設定 FirebaseStorage

FCViewController.swift

  func configureStorage() {
    storageRef
= Storage.storage().reference()
 
}

在現有訊息中接收圖片

新增從 Firebase Storage 下載圖片的程式碼。

修改 FCViewController 的「tableView: cellForRowAt indexPath:」方法,並替換為下方定義的程式碼:

FCViewController.swift

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   
// Dequeue cell
    let cell
= self.clientTable .dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
   
// Unpack message from Firebase DataSnapshot
    let messageSnapshot
: DataSnapshot! = self.messages[indexPath.row]
    guard let message
= messageSnapshot.value as? [String:String] else { return cell }
    let name
= message[Constants.MessageFields.name] ?? ""
   
if let imageURL = message[Constants.MessageFields.imageURL] {
     
if imageURL.hasPrefix("gs://") {
       
Storage.storage().reference(forURL: imageURL).getData(maxSize: INT64_MAX) {(data, error) in
         
if let error = error {
           
print("Error downloading: \(error)")
           
return
         
}
         
DispatchQueue.main.async {
            cell
.imageView?.image = UIImage.init(data: data!)
            cell
.setNeedsLayout()
         
}
       
}
     
} else if let URL = URL(string: imageURL), let data = try? Data(contentsOf: URL) {
        cell
.imageView?.image = UIImage.init(data: data)
     
}
      cell
.textLabel?.text = "sent by: \(name)"
   
} else {
      let text
= message[Constants.MessageFields.text] ?? ""
      cell
.textLabel?.text = name + ": " + text
      cell
.imageView?.image = UIImage(named: "ic_account_circle")
     
if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
          let data
= try? Data(contentsOf: URL) {
        cell
.imageView?.image = UIImage(data: data)
     
}
   
}
   
return cell
 
}

9. 傳送圖片訊息

實作儲存及傳送圖片功能

從使用者上傳圖片,然後將此圖片的儲存網址同步處理至資料庫,以便在訊息中傳送此圖片。

修改 FCViewController 的「imagePickerController: didFinishPickingMediaWithInfo:」方法,並替換為下方定義的程式碼:

FCViewController.swift

  func imagePickerController(_ picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info
: [String : Any]) {
      picker
.dismiss(animated: true, completion:nil)
    guard let uid
= Auth.auth().currentUser?.uid else { return }

   
// if it's a photo from the library, not an image from the camera
   
if #available(iOS 8.0, *), let referenceURL = info[UIImagePickerControllerReferenceURL] as? URL {
      let assets
= PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
      let asset
= assets.firstObject
      asset
?.requestContentEditingInput(with: nil, completionHandler: { [weak self] (contentEditingInput, info) in
        let imageFile
= contentEditingInput?.fullSizeImageURL
        let filePath
= "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000))/\((referenceURL as AnyObject).lastPathComponent!)"
        guard let strongSelf
= self else { return }
        strongSelf
.storageRef.child(filePath)
         
.putFile(from: imageFile!, metadata: nil) { (metadata, error) in
           
if let error = error {
              let nsError
= error as NSError
             
print("Error uploading: \(nsError.localizedDescription)")
             
return
           
}
            strongSelf
.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
         
}
     
})
   
} else {
      guard let image
= info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
      let imageData
= UIImageJPEGRepresentation(image, 0.8)
      let imagePath
= "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000)).jpg"
      let metadata
= StorageMetadata()
      metadata
.contentType = "image/jpeg"
     
self.storageRef.child(imagePath)
       
.putData(imageData!, metadata: metadata) { [weak self] (metadata, error) in
         
if let error = error {
           
print("Error uploading: \(error)")
           
return
         
}
          guard let strongSelf
= self else { return }
          strongSelf
.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
     
}
   
}
 
}

測試傳送及接收圖片訊息

  1. 按一下「Run」按鈕。98205811bbed9d74.png
  2. 按一下「登入」即可前往訊息視窗。
  3. 按一下「新增相片」圖示,選擇相片。應用程式 UI 和 Firebase 控制台應會顯示含有相片的新訊息。

10. 恭喜!

您已使用 Firebase 輕鬆建構即時通訊應用程式。

涵蓋內容

  • 即時資料庫
  • 聯合登入
  • 儲存空間

瞭解詳情