Google 致力于为黑人社区推动种族平等。查看具体举措
此页面由 Cloud Translation API 翻译。
Switch to English

Firebase iOS Codelab Swift

2efe6805ef369641.png

欢迎使用友好聊天代码实验室。在此代码实验室中,您将学习如何使用Firebase平台创建iOS应用程序。您将实现一个聊天客户端并使用Firebase监视其性能。

该代码实验室在Objective-C中也可用。

您将学到什么

  • 允许用户登录。
  • 使用Firebase实时数据库同步数据。
  • 将二进制文件存储在Firebase存储中。

你需要什么

  • Xcode
  • 可可豆
  • 具有iOS 8.0+或模拟器的测试设备

您将如何使用本教程?

仅阅读阅读并完成练习

您如何评价构建iOS应用的体验?

新手中间的精通

从命令行克隆GitHub存储库。

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

2f4c98d858c453fe.png

要构建入门应用程序:

  1. 在终端窗口中,导航到android_studio_folder.png样本代码下载中的ios-starter/swift-starter目录
  2. 运行pod install --repo-update
  3. 打开FriendlyChatSwift.xcworkspace文件以Xcode打开项目。
  4. 点击98205811bbed9d74.png运行按钮。

几秒钟后,您应该会看到“友好聊天”主屏幕出现。 UI应该出现。但是,此时您无法登录,发送或接收消息。该应用程序将异常终止,直到完成下一步。

建立专案

Firebase控制台中,选择“添加项目”

将项目FriendlyChat ,然后单击“创建项目”

2015年11月6日14:13:39.png的屏幕截图

连接您的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中使用“配置”方法,以从.plist文件配置基础Firebase服务。

AppDelegate.swift

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

使用规则限制通过身份验证的用户

现在,我们将添加一条规则,要求在读取或写入任何消息之前进行身份验证。为此,我们向消息数据对象添加以下规则。在Firebase控制台的“数据库”部分中,选择“实时数据库”,然后单击“规则”选项卡。然后更新规则,使其如下所示:

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

有关此工作原理的更多信息(包括有关“ auth”变量的文档),请参阅Firebase安全文档

配置身份验证API

在您的应用程序可以代表您的用户访问Firebase身份验证API之前,您必须先启用它

  1. 导航到Firebase控制台并选择您的项目
  2. 选择身份验证
  3. 选择登录方法选项卡
  4. Google开关切换到启用状态(蓝色)
  5. 在出现的对话框中按保存

如果稍后在此代码实验室中收到错误消息“ CONFIGURATION_NOT_FOUND”,请返回此步骤并仔细检查您的工作。

确认Firebase Auth依赖性

确认Podfile文件中存在Firebase Auth依赖关系。

播客文件

pod 'Firebase/Auth'

为Google登录设置您的Info.plist。

您需要向XCode项目中添加自定义URL方案。

  1. 打开项目配置:在左树视图中双击项目名称。从“目标”部分选择您的应用,然后选择“信息”选项卡,然后展开“ URL类型”部分。
  2. 单击+按钮,然后为您的反向客户端ID添加URL方案。要找到此值,请打开Goog​​leService-Info.plist配置文件,然后查找REVERSED_CLIENT_ID密钥。复制该键的值,然后将其粘贴到配置页上的“ URL方案”框中。将其他字段留空。
  3. 完成后,您的配置应类似于以下内容(但具有特定于应用程序的值):

1b54d5bd2f4f1448.png

设置Google登录的clientID

配置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 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. 如果一切正常,则应将您发送到消息传递屏幕。

2efe6805ef369641.png

汇入讯息

Firebase控制台的项目中,选择左侧导航栏上的“数据库”项。在数据库的溢出菜单中,选择导入JSON 。浏览到friendlychat目录中的initial_messages.json文件,选择它,然后单击“导入”按钮。这将替换数据库中当前的所有数据。您还可以直接编辑数据库,使用绿色+和红色x添加和删除项目。

20ccf4856b715b4c.png

导入数据库后,应如下所示:

f3e0367f1c9cd187.png

确认Firebase数据库依赖性

Podfile文件的依赖项块中,确认其中包括Firebase/Database

播客文件

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. 确认它们显示在Friendly-Chat UI中。

实施发送消息

将值推送到数据库。当您使用push方法将数据添加到Firebase Realtime数据库时,将添加一个自动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. 输入一条消息,然后单击发送。新消息应在应用程序用户界面和Firebase控制台中可见。

确认Firebase存储依赖性

Podfile的依赖项块中,确认其中包括Firebase/Storage

播客文件

pod 'Firebase/Storage'

在仪表板中激活Firebase存储

转到Firebase控制台,并确认已使用“ gs://PROJECTID.appspot.com”域激活了存储

b0438b37a588bcee.png

如果您看到的是激活窗口,请单击“入门”以默认规则激活它。

c290bbebff2cafa7.png

配置FirebaseStorage

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
  }

实施存储和发送图像

从用户上传图像,然后将该图像的存储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. 单击“添加照片”图标以选择照片。带有照片的新消息应在应用程序用户界面和Firebase控制台中可见。

您已使用Firebase轻松构建了实时聊天应用程序。

我们涵盖的内容

  • 实时数据库
  • 联合登录
  • 贮存

了解更多