Firebase iOS Codelab Swift

1. 概述

2efe6805ef369641.png

歡迎來到友善聊天代碼實驗室。在此 Codelab 中,您將學習如何使用 Firebase 平台建立 iOS 應用程式。您將實作一個聊天用戶端並使用 Firebase 監控其效能。

你將學到什麼

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

你需要什麼

  • Xcode
  • 可可豆莢
  • iOS 8.0+ 或模擬器的測試設備

您將如何使用本教學?

僅通讀一遍閱讀並完成練習

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

新手中間的精通

2. 取得範例程式碼

從命令列克隆 GitHub 儲存庫。

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

3. 建立入門應用程式

2f4c98d858c453fe.png

要建立入門應用程式:

  1. 在終端機視窗中,導航到android_studio_folder.png範例程式碼下載中的ios-starter/swift-starter目錄
  2. 運行pod install --repo-update
  3. 開啟FriendlyChatSwift.xcworkspace 檔案以在Xcode 中開啟專案。
  4. 點選98205811bbed9d74.png運行按鈕。

幾秒鐘後,您應該會看到友善聊天主畫面出現。使用者介面應該會出現。但是,此時您無法登入、傳送或接收訊息。應用程式將異常中止,直到您完成下一步。

4.建立Firebase控制台項目

創建專案

Firebase 控制台中選擇「新增項目」

將該項目命名為FriendlyChat ,然後按一下「建立專案」

截圖自 2015-11-06 14:13:39.png

連接您的 iOS 應用程式

  1. 在新專案的「專案概述」畫面中,按一下「將 Firebase 新增至您的 iOS 應用程式」
  2. 輸入捆綁包 ID,如「 com.google.firebase.codelab.FriendlyChatSwift 」。
  3. 輸入 App Store ID「 123456 」。
  4. 點擊註冊應用程式

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

在第二個畫面上,按一下「下載 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 之前,您必須啟用它

  1. 導航至Firebase 控制台並選擇您的項目
  2. 選擇身份驗證
  3. 選擇登入方法標籤
  4. Google開關切換為啟用(藍色)
  5. 在出現的對話方塊中按“儲存”

如果您稍後在此 Codelab 中遇到錯誤並顯示訊息“CONFIGURATION_NOT_FOUND”,請返回此步驟並仔細檢查您的工作。

確認 Firebase 身份驗證依賴項

確認Podfile檔案中存在 Firebase Auth 依賴項。

Podfile

pod 'Firebase/Auth'

設定您的 Info.plist 以進行 Google 登入。

您需要將自訂 URL 方案新增至您的 XCode 專案。

  1. 開啟專案配置:雙擊左側樹視圖中的專案名稱。從“目標”部分選擇您的應用程序,然後選擇“資訊”選項卡,並展開“URL 類型”部分。
  2. 點選 + 按鈕,並為反向客戶端 ID 新增 URL 方案。若要尋找此值,請開啟 GoogleService-Info.plist 設定文件,然後尋找 REVERSED_CLIENT_ID 鍵。複製該鍵的值,並將其貼上到設定頁面上的 URL 方案框中。將其他欄位留空。
  3. 完成後,您的配置應類似於以下內容(但具有特定於應用程式的值):

1b54d5bd2f4f1448.png

設定 Google 登入的 clientID

配置 Firebase 後,我們可以使用 clientID 在「didFinishLaunchingWithOptions:」方法中設定 Google Sign In。

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 Auth 中新增一個監聽器,讓使用者在成功登入後進入應用程式。並在 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. 點選98205811bbed9d74.png運行按鈕。
  2. 您應該立即轉到登入畫面。點擊 Google 登入按鈕。
  3. 如果一切順利,您應該會被發送到訊息螢幕。

6. 啟動即時資料庫

2efe6805ef369641.png

導入訊息

Firebase 控制台的專案中,選擇左側導覽列上的資料庫項目。在資料庫的溢位選單中選擇Import JSON 。瀏覽到Friendlychat 目錄中的initial_messages.json文件,選擇它,然後按一下「匯入」按鈕。這將替換資料庫中當前的所有資料。您也可以直接編輯資料庫,使用綠色 + 和紅色 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. 點選98205811bbed9d74.png運行按鈕。
  2. 按一下「登入以開始」按鈕前往訊息視窗。
  3. 透過點擊「訊息」條目旁邊的綠色 + 符號並新增如下所示的對象,直接在 Firebase 控制台中新增訊息: f9876ffc8b316b14.png
  4. 確認它們出現在友善聊天使用者介面中。

7. 發送訊息

實施發送訊息

將值推送到資料庫。當您使用推送方法將資料新增至 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. 點選98205811bbed9d74.png運行按鈕。
  2. 按一下登入轉至訊息視窗。
  3. 輸入一則訊息並點擊發送。新訊息應該在應用程式 UI 和 Firebase 控制台中可見。

8. 儲存和接收影像

確認 Firebase 儲存依賴性

Podfile的依賴項區塊中,確認包含Firebase/Storage

Podfile

pod 'Firebase/Storage'

在儀表板中啟動 Firebase 存儲

前往 Firebase 控制台並確認已使用“gs://PROJECTID.appspot.com”網域啟動存儲

b0438b37a588bcee.png

如果您看到的是啟動窗口,請按一下「開始」以使用預設規則啟動它。

c290bbebff2cafa7.png

配置 Firebase 存儲

FCViewController.swift

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

接收現有訊息中的影像

新增從 Firebase 儲存下載映像的程式碼。

修改你的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. 發送圖像訊息

實施儲存和發送影像

上傳使用者的圖像,然後將該圖像的儲存 URL 同步到資料庫,以便該圖像在訊息中發送。

修改你的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. 點選98205811bbed9d74.png運行按鈕。
  2. 按一下登入轉至訊息視窗。
  3. 點擊“新增照片”圖示來選擇照片。帶有照片的新訊息應該在應用程式 UI 和 Firebase 控制台中可見。

10. 恭喜!

您已使用 Firebase 輕鬆建立了即時聊天應用程式。

我們涵蓋的內容

  • 即時資料庫
  • 聯合登入
  • 貯存

了解更多