当前位置:主页 > 资料 >

Firebase Tutorial: Real-time Chat
栏目分类:资料   发布日期:2018-08-02   浏览次数:

导读:本文为去找网小编(www.7zhao.net)为您推荐的Firebase Tutorial: Real-time Chat,希望对您有所帮助,谢谢! Update note : Ryan Ackermann updated this tutorial to iOS 12, Swift 4.2, Xcode 10, MessageKit, and Cloud Firestor

本文为去找网小编(www.7zhao.net)为您推荐的Firebase Tutorial: Real-time Chat,希望对您有所帮助,谢谢! 内容来自www.7zhao.net



Update note : Ryan Ackermann updated this tutorial to iOS 12, Swift 4.2, Xcode 10, MessageKit, and Cloud Firestore. Tom Elliott wrote the original tutorial. You can safely ignore the warnings about updating to Swift 4.2 since MessageKit is not yet updated. 本文来自去找www.7zhao.net

本文来自去找www.7zhao.net

It seems like every major app out there has a chat feature — and yours should be no different! This Firebase tutorial will show you how. 内容来自www.7zhao.net

However, creating a chat tool can seem like a daunting task. There’s no native UIKit controls designed specifically for chat, and you’ll need a server to coordinate the messages and conversations between users.

本文来自去找www.7zhao.net

Fortunately, there are some great frameworks out there to help you: lets you synchronize real time data without writing a line of server code, while gives you a messaging UI that’s on par with the native Messages app.

欢迎访问www.7zhao.net

In this Firebase tutorial, you’ll build RWRC (Ray Wenderlich Relay Chat) — an anonymous chat application. If you’ve used IRC or Slack, this sort of application should already be familiar to you. 欢迎访问www.7zhao.net

本文来自去找www.7zhao.net

Along the way, you’ll learn how to do the following: www.7zhao.net

  • Set up the Firebase SDK and MessageKit with CocoaPods.
  • Synchronize data in real time with the Cloud Firestore .
  • Authenticate anonymously with Firebase.
  • Leverage MessageKit for a complete chat UI.
  • Create multiple message threads.
  • Use Firebase Storage to send pictures.

Getting Started

Use the Download Materials button at the top or bottom of this tutorial to download the starter project. To get you started the project contains a simple dummy login screen, where the credentials are saved to User Defaults.

本文来自去找www.7zhao.net

The starter project has a few helper classes that handle sending data to Firebase and saving data to User Defaults. Feel free to browse the starter project a bit to get familiar with the code.

copyright www.7zhao.net

In the starter project you’ll find ChannelsViewController.swift which listens to changes in a Firebase Firestore database and updates a table view whenever the user adds a new channel. You’ll build a similar implementation for displaying chat messages instead of channels.

去找(www.7zhao.net欢迎您

You’ll use CocoaPods to install both the Firebase SDK and MessageKit . If you’re new to CocoaPods, check out our to get up and running.

www.7zhao.net

Open Terminal at the project’s folder location and run the following command to install your dependencies: copyright www.7zhao.net

pod install 去找(www.7zhao.net欢迎您 

This may take a few minutes, but once the packages have installed, open RWRC.xcworkspace in Xcode. Before you can run the app, you’ll need to configure Firebase. www.7zhao.net

If you’re new to Firebase you’ll need to create an account. Don’t worry — this is easy and totally free. 去找(www.7zhao.net欢迎您

Note : For a detailed walkthrough on setting up Firebase, see the . 欢迎访问www.7zhao.net

Create a Firebase Account

Head to , create an account, and then create a new Firebase project. 去找(www.7zhao.net欢迎您

In Xcode , click on the target and change the Bundle Identifier to any value you like, and select a Team in the Signing section. www.7zhao.net

Follow Steps 1 and 2 of the instructions to add Firebase to an iOS app, starting here:

www.7zhao.net

www.7zhao.net

Next, enter in the app’s bundle ID into the form, after which you will download and add the GoogleService-Info.plist config file to your project under the Supporting Files group as shown in the Firebase instructions. This .plist file contains the configuration information needed for Firebase integration with your app. 内容来自www.7zhao.net

Warning : Do only Steps 1 and 2 of the instructions. The rest is already done in the starter project and your app will crash if you duplicate the steps. www.7zhao.net

Now build and run the app. You should see the following:

去找(www.7zhao.net欢迎您

去找(www.7zhao.net欢迎您

Enabling Anonymous Authentication

Firebase lets users log in through email or social accounts, but it can also authenticate users anonymously, giving you a unique identifier for a user without knowing any information about them. www.7zhao.net

To set up anonymous authentication, open the Firebase App Dashboard , select the Authentication option on the left, click Set Up Sign-In Method , then select the Anonymous option, switch Enable so that it’s on, then click Save . 内容来自www.7zhao.net

copyright www.7zhao.net

Just like that, you’ve enabled super secret stealth mode ! Okay, so it’s really just anonymous authentication, but hey — it’s still cool. :]

欢迎访问www.7zhao.net

Super secret stealth mode achieved! 去找(www.7zhao.net欢迎您

Logging In

Open LoginViewController.swift and add the following underneath import UIKit :

copyright www.7zhao.net

import FirebaseAuth 内容来自www.7zhao.net 

To log in to chat, the app will need to authenticate using the Firebase authentication service. Add the following code to the bottom of signIn :

本文来自去找www.7zhao.net

Auth.auth().signInAnonymously(completion: nil) copyright www.7zhao.net 

That line of code from the FirebaseAuth framework will post the Notification.Name.AuthStateDidChange notification that AppController is listening for. Once the notification is fired AppController will update the root view controller for you. 欢迎访问www.7zhao.net

Build and run your app, enter a display name and tap Get Started .

去找(www.7zhao.net欢迎您

copyright www.7zhao.net

Once the user signs in, they navigate to the ChannelsViewController , whose job it is to show the user a list of current channels and allow creating new channels. The table has a single section to display all available channels. There is a toolbar at the bottom with a sign out button, a label displaying your name, and an add button. www.7zhao.net

Firebase Data Structure

Before you dive into sending messages in realtime, take a moment and think about the data structure first. 本文来自去找www.7zhao.net

Cloud Firestore is a NoSQL JSON data store. Essentially, everything in the Cloud Firestore is a JSON object, and each key of this JSON object has its own URL. 本文来自去找www.7zhao.net

Here’s a sample of how your data could look as a JSON object: 内容来自www.7zhao.net

{
  "channels": [{
    "MOuL1sdbrnh0x1zGuXn7": { // channel id
      "name": "Puppies",
      "thread": [{
        "3a6Fo5rrUcBqhUJcLsP0": { // message id
          "content": "Wow, that's so cute!",
          "created": "May 12, 2018 at 10:44:11 PM UTC-5",
          "senderID": "YCrPJF3shzWSHagmr0Zl2WZFBgT2",
          "senderName": "naturaln0va",
        },
        "4LXlVnWnoqyZEuKiiubh": { // message id
          "content": "Yes he is.",
          "created": "May 12, 2018 at 10:40:05 PM UTC-5",
          "senderID": "f84PFeGl2yaqUDaSiTVeqe9gHfD3",
          "senderName": "lumberjack16",
        },
      }]
    },
  }]
} 

www.7zhao.net

Cloud Firestore , so it’s okay to include senderId and senderName for each message item. A denormalized data structure means you’ll duplicate a lot of data, but the upside is faster data retrieval. Tradeoffs — we haz them! :]

copyright www.7zhao.net

Chat Interface Setup

MessageKit is a souped-up UICollectionViewController that’s customized for chat, so you don’t have to create your own! :] www.7zhao.net

In this section of the tutorial, you’ll focus on four things: www.7zhao.net

  1. Handling input from the message bar.
  2. Creating message data.
  3. Styling message bubbles.
  4. Removing avatar support.

Almost everything you’ll need to do requires that you override methods. MessageKit provides the MessagesDisplayDelegate , MessagesLayoutDelegate , and MessagesDataSource protocols, so you only need to override the default implementations.

本文来自去找www.7zhao.net

Note : For more information on customizing and working with MessagesViewController , check out the full the documentation .

内容来自www.7zhao.net

Open ChatViewController.swift and, at the top of ChatViewController , define the following properties:

欢迎访问www.7zhao.net

private var messages: [Message] = []
private var messageListener: ListenerRegistration? 

欢迎访问www.7zhao.net

These properties are similar to those added to the channels view controller. The messages array is the data model and the listener handles clean up. 内容来自www.7zhao.net

Now you can start configuring the data source. Above the MessageInputBarDelegate section, add the following:

欢迎访问www.7zhao.net

// MARK: - MessagesDataSource

extension ChatViewController: MessagesDataSource {

  // 1
  func currentSender() -> Sender {
    return Sender(id: user.uid, displayName: AppSettings.displayName)
  }

  // 2
  func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int {
    return messages.count
  }

  // 3
  func messageForItem(at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> MessageType {

    return messages[indexPath.section]
  }

  // 4
  func cellTopLabelAttributedText(for message: MessageType, 
    at indexPath: IndexPath) -> NSAttributedString? {

    let name = message.sender.displayName
    return NSAttributedString(
      string: name,
      attributes: [
        .font: UIFont.preferredFont(forTextStyle: .caption1),
        .foregroundColor: UIColor(white: 0.3, alpha: 1)
      ]
    )
  }
} 欢迎访问www.7zhao.net 

There’s a bit going on here:

内容来自www.7zhao.net

  1. A sender is a simple struct that has an id and name property. You create an instance of a sender from the anonymous Firebase user id and the chosen display name.
  2. The number of messages in the collection view will be equal to the local array of messages.
  3. Your Message model object conforms to MessageType so you can just return the message for the given index path.
  4. The last method returns the attributed text for the name above each message bubble. You can modify the text you’re returning here to your liking, but these are some good defaults.

Build and run the app, add a channel named Cooking and then navigate to it. It should now look like:

内容来自www.7zhao.net

copyright www.7zhao.net

So far, so good. Next, you’ll need to implement a few more delegates before you start sending messages. 去找(www.7zhao.net欢迎您

Setting Up the Display and Layout Delegates

Now that you’ve seen your new awesome chat UI, you probably want to start displaying messages. But before you do that, you have to take care of a few more things. 去找(www.7zhao.net欢迎您

First, you’ll fine tune some layout parameters from the MessagesLayoutDelegate . Add the following section below the MessagesDisplayDelegate section:

www.7zhao.net

// MARK: - MessagesLayoutDelegate

extension ChatViewController: MessagesLayoutDelegate {

  func avatarSize(for message: MessageType, at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> CGSize {

    // 1
    return .zero
  }

  func footerViewSize(for message: MessageType, at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> CGSize {

    // 2
    return CGSize(width: 0, height: 8)
  }

  func heightForLocation(message: MessageType, at indexPath: IndexPath, 
    with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {

    // 3
    return 0
  }
} 
去找(www.7zhao.net欢迎您

Here’s the break down: 内容来自www.7zhao.net

zero
 

本文来自去找www.7zhao.net

The messages displayed in the collection view are simply images with text overlaid. There are two types of messages: outgoing and incoming . Outgoing messages are displayed to the right and incoming messages on the left. 本文来自去找www.7zhao.net

In ChatViewController , replace the MessagesDisplayDelegate extension with the following: 内容来自www.7zhao.net

extension ChatViewController: MessagesDisplayDelegate {
  
  func backgroundColor(for message: MessageType, at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> UIColor {
    
    // 1
    return isFromCurrentSender(message: message) ? .primary : .incomingMessage
  }

  func shouldDisplayHeader(for message: MessageType, at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> Bool {

    // 2
    return false
  }

  func messageStyle(for message: MessageType, at indexPath: IndexPath, 
    in messagesCollectionView: MessagesCollectionView) -> MessageStyle {

    let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight : .bottomLeft

    // 3
    return .bubbleTail(corner, .curved)
  }
} 
内容来自www.7zhao.net

Taking the above code step-by-step:

copyright www.7zhao.net

false
 本文来自去找www.7zhao.net 

To tie this all together, add the following to the bottom of viewDidLoad() : 本文来自去找www.7zhao.net

messageInputBar.delegate = self
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self 去找(www.7zhao.net欢迎您 

Check that your app builds and you can navigate to one of your channels

内容来自www.7zhao.net

copyright www.7zhao.net

Believe it or not, that’s all it takes to configure a MessagesViewController subclass to display messages! Well, it would be more exciting to see some messages, wouldn’t it? 本文来自去找www.7zhao.net

Time to get this conversation started! 内容来自www.7zhao.net

Creating Messages

Create the following method below viewDidLoad() in ChatViewController :

copyright www.7zhao.net

// MARK: - Helpers

private func insertNewMessage(_ message: Message) {
  guard !messages.contains(message) else {
    return
  }
  
  messages.append(message)
  messages.sort()
  
  let isLatestMessage = messages.index(of: message) == (messages.count - 1)
  let shouldScrollToBottom = messagesCollectionView.isAtBottom && isLatestMessage
  
  messagesCollectionView.reloadData()
  
  if shouldScrollToBottom {
    DispatchQueue.main.async {
      self.messagesCollectionView.scrollToBottom(animated: true)
    }
  }
} 

去找(www.7zhao.net欢迎您

This helper method is similar to the one that’s in ChannelsViewController . It makes sure the messages array doesn’t already contain the message, then adds it to the collection view. Then, if the new message is the latest and the collection view is at the bottom, scroll to reveal the new message.

去找(www.7zhao.net欢迎您

Add a test message by overriding viewDidAppear(_:) : 本文来自去找www.7zhao.net

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  
  let testMessage = Message(user: user, content: "I love pizza, what is your favorite kind?")
  insertNewMessage(testMessage)
} 内容来自www.7zhao.net 

Build and run the app; you’ll see your message appear in the conversation view:

内容来自www.7zhao.net

本文来自去找www.7zhao.net

Boom — that’s one nice looking chat app! Time to make it work (for real) with Firebase. 本文来自去找www.7zhao.net

Sending Messages

First, delete viewDidAppear(_:) to remove the test message in ChatViewController and add the following properties at the top of the file: 去找(www.7zhao.net欢迎您

private let db = Firestore.firestore()
private var reference: CollectionReference? 去找(www.7zhao.net欢迎您 

At the top of viewDidLoad add the following:

欢迎访问www.7zhao.net

guard let id = channel.id else {
  navigationController?.popViewController(animated: true)
  return
}

reference = db.collection(["channels", id, "thread"].joined(separator: "/")) copyright www.7zhao.net 

The reference property is the point in the database where the messages are stored. The id property on the channel is optional because you might not yet have synced the channel. If the channel doesn’t exist in Firestore yet messages cannot be sent, so returning to the channel list makes the most sense. www.7zhao.net

Next add the following method to the top of the Helpers section: 去找(www.7zhao.net欢迎您

private func save(_ message: Message) {
  reference?.addDocument(data: message.representation) { error in
    if let e = error {
      print("Error sending message: \(e.localizedDescription)")
      return
    }
    
    self.messagesCollectionView.scrollToBottom()
  }
} copyright www.7zhao.net 

This method uses the reference that was just setup. The addDocument method on the reference takes a dictionary with the keys and values that represent that data. The message data struct implements DatabaseRepresentation , which defines a dictionary property to fill out. copyright www.7zhao.net

Open Message.swift and examine the implementation of DatabaseRepresentation . As you can see, it maps its properties to readable keys and only sets the content of the message if there is no download URL.

去找(www.7zhao.net欢迎您

Back in ChatViewController.swift , add the following delegate method inside the MessageInputBarDelegate extension:

本文来自去找www.7zhao.net

func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) {

  // 1
  let message = Message(user: user, content: text)

  // 2
  save(message)

  // 3
  inputBar.inputTextView.text = ""
} 

内容来自www.7zhao.net

Here’s what’s going on:

欢迎访问www.7zhao.net

  1. Create a message from the contents of the message bar and the current user.
  2. Save the message to Cloud Firestore using save(_:) .
  3. Clear the message bar’s input field after you send the message.

Build and run; open up your and click on the Database tab. Select a channel, then send a message in the app and you should see the messages appear in the dashboard in real time:

copyright www.7zhao.net

Note : The first time you view the database on the console, it will prompt you to select a database type. For this tutorial, you’re using Cloud Firestore . After clicking the Create Database button, select the test mode option. For a real world setup, you’ll want to configure security rules for Firestore. You can read more about security rules . 欢迎访问www.7zhao.net

www.7zhao.net

High five! You’re saving messages to Cloud Firestore like a pro. The messages don’t appear on the screen, but you’ll take care of that next. 去找(www.7zhao.net欢迎您

Synchronizing the Data Source

Add the following to below insertNewMessage(_:) in ChatViewController : www.7zhao.net

private func handleDocumentChange(_ change: DocumentChange) {
  guard let message = Message(document: change.document) else {
    return
  }

  switch change.type {
  case .added:
    insertNewMessage(message)

  default:
    break
  }
} 
内容来自www.7zhao.net

This is very similar to how ChannelsViewController observes new database changes. For brevity, the only change type you handle in the switch statement is add . 本文来自去找www.7zhao.net

Next, add the following code below the reference initialization in viewDidLoad() :

www.7zhao.net

messageListener = reference?.addSnapshotListener { querySnapshot, error in
  guard let snapshot = querySnapshot else {
    print("Error listening for channel updates: \(error?.localizedDescription ?? "No error")")
    return
  }
  
  snapshot.documentChanges.forEach { change in
    self.handleDocumentChange(change)
  }
} 欢迎访问www.7zhao.net 

Firestore calls this snapshot listener whenever there is a change to the database.

www.7zhao.net

To clean things up add a deinit towards the top of the file:

去找(www.7zhao.net欢迎您

deinit {
  messageListener?.remove()
} 

欢迎访问www.7zhao.net

Build and run your app; you should see any messages sent earlier along with any new ones you enter: copyright www.7zhao.net

内容来自www.7zhao.net

Congrats! You have a real time chat app! Now it’s time to add one final finishing touch.

内容来自www.7zhao.net

Sending Images

To send images, you’re going to follow mostly the same principle as sending text with one key difference. Rather than storing the image data directly with the message, you’ll use Firebase Storage , which is better suited to storing large files like audio, video or images.

copyright www.7zhao.net

To start, you need to add the Photos import to ChatViewController.swift :

本文来自去找www.7zhao.net

import Photos 

内容来自www.7zhao.net

Add the following above the Helpers section:

www.7zhao.net

// MARK: - Actions

@objc private func cameraButtonPressed() {
  let picker = UIImagePickerController()
  picker.delegate = self

  if UIImagePickerController.isSourceTypeAvailable(.camera) {
    picker.sourceType = .camera
  } else {
    picker.sourceType = .photoLibrary
  }

  present(picker, animated: true, completion: nil)
} 

www.7zhao.net

This method will present an image picker controller to allow the user to select an image.

www.7zhao.net

Next, add the following to viewDidLoad() : www.7zhao.net

// 1
let cameraItem = InputBarButtonItem(type: .system)
cameraItem.tintColor = .primary
cameraItem.image = #imageLiteral(resourceName: "camera")

// 2
cameraItem.addTarget(
  self,
  action: #selector(cameraButtonPressed),
  for: .primaryActionTriggered
)
cameraItem.setSize(CGSize(width: 60, height: 30), animated: false)

messageInputBar.leftStackView.alignment = .center
messageInputBar.setLeftStackViewWidthConstant(to: 50, animated: false)

// 3
messageInputBar.setStackViewItems([cameraItem], forStack: .left, animated: false) 欢迎访问www.7zhao.net 

Going through this: www.7zhao.net

InputBarButtonItem
cameraButtonPressed()
 

www.7zhao.net

Sending a photo message is a little different then sending a plain text message. Saving a photo to Firebase Storage returns a URL, but this may take a couple of seconds — perhaps longer, if the network connection is poor. Rather than blocking the user interface during this time, which will make your app feel slow, you’ll start sending the message and disable the camera message bar item. www.7zhao.net

Add the following properties at the top of ChatViewController : 欢迎访问www.7zhao.net

private var isSendingPhoto = false {
  didSet {
    DispatchQueue.main.async {
      self.messageInputBar.leftStackViewItems.forEach { item in
        item.isEnabled = !self.isSendingPhoto
      }
    }
  }
}

private let storage = Storage.storage().reference() 

www.7zhao.net

and add this method to the bottom of the Helpers section: copyright www.7zhao.net

private func uploadImage(_ image: UIImage, to channel: Channel, completion: @escaping (URL?) -> Void) {
  guard let channelID = channel.id else {
    completion(nil)
    return
  }
  
  guard let scaledImage = image.scaledToSafeUploadSize,
    let data = scaledImage.jpegData(compressionQuality: 0.4) else {
    completion(nil)
    return
  }
  
  let metadata = StorageMetadata()
  metadata.contentType = "image/jpeg"
  
  let imageName = [UUID().uuidString, String(Date().timeIntervalSince1970)].joined()
  storage.child(channelID).child(imageName).putData(data, metadata: metadata) { meta, error in
    completion(meta?.downloadURL())
  }
} 内容来自www.7zhao.net 

The isSendingPhoto property takes care of updating the camera item when it changes and the storage property is a reference to the root of Firebase Storage. uploadImage(_:to:completion:) uploads an image to the specified channel in the Firebase Storage .

欢迎访问www.7zhao.net

Below uploadImage(_:to:completion:) , add:

去找(www.7zhao.net欢迎您

private func sendPhoto(_ image: UIImage) {
  isSendingPhoto = true
  
  uploadImage(image, to: channel) { [weak self] url in
    guard let `self` = self else {
      return
    }
    self.isSendingPhoto = false
    
    guard let url = url else {
      return
    }
    
    var message = Message(user: self.user, image: image)
    message.downloadURL = url
    
    self.save(message)
    self.messagesCollectionView.scrollToBottom()
  }
} 欢迎访问www.7zhao.net 

This method takes care of updating the isSendingPhoto property to update the UI. Once the photo upload completes and the URL to that photo is returned, save a new message with that photo URL to the database.

copyright www.7zhao.net

Next, to use sendPhoto(_:) , add the following image picker delegate methods to the UIImagePickerControllerDelegate extension:

本文来自去找www.7zhao.net

func imagePickerController(_ picker: UIImagePickerController, 
                           didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  picker.dismiss(animated: true, completion: nil)
  
  // 1
  if let asset = info[.phAsset] as? PHAsset {
    let size = CGSize(width: 500, height: 500)
    PHImageManager.default().requestImage(
      for: asset,
      targetSize: size,
      contentMode: .aspectFit,
      options: nil) { result, info in
        
      guard let image = result else {
        return
      }
      
      self.sendPhoto(image)
    }

  // 2
  } else if let image = info[.originalImage] as? UIImage {
    sendPhoto(image)
  }
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
  picker.dismiss(animated: true, completion: nil)
} 

www.7zhao.net

These two methods handle the cases when the user either selects an image or cancels the selection process. When selecting an image, the user can either get one from the photo library or take an image directly with the camera. 去找(www.7zhao.net欢迎您

Here’s what this does:

去找(www.7zhao.net欢迎您

  1. If the user selected an asset, the selected image needs to be downloaded from iCloud. Request it at a fixed size. Once it’s successfully retrieved, send it.
  2. If there is an original image in the info dictionary, send that. You don’t need to worry about the original image being too large here because the storage helper handles resizing the image for you. Have a look at UIImage+Additions.swift to see how the resizing is done.

Nearly there! You’ve now set up your app to save the image data to Firebase Storage and save the URL to the message data, but you’ve not yet updated the app to display those photos. Time to fix that. 欢迎访问www.7zhao.net

Get started by adding the following to the bottom of the Helpers section: 去找(www.7zhao.net欢迎您

private func downloadImage(at url: URL, completion: @escaping (UIImage?) -> Void) {
  let ref = Storage.storage().reference(forURL: url.absoluteString)
  let megaByte = Int64(1 * 1024 * 1024)
  
  ref.getData(maxSize: megaByte) { data, error in
    guard let imageData = data else {
      completion(nil)
      return
    }
    
    completion(UIImage(data: imageData))
  }
} copyright www.7zhao.net 

This method asynchronously downloads an image at the specified path from Firebase Storage .

内容来自www.7zhao.net

Next, change the guard statement from a constant to a variable in the handleDocumentChange(_:) method:

www.7zhao.net

guard var message = Message(document: change.document) else {
  return
} 
去找(www.7zhao.net欢迎您

Then, in handleDocumentChange(_:) , replace the content of the .added case with the following:

去找(www.7zhao.net欢迎您

if let url = message.downloadURL {
  downloadImage(at: url) { [weak self] image in
    guard let self = self else {
      return
    }
    guard let image = image else {
      return
    }
    
    message.image = image
    self.insertNewMessage(message)
  }
} else {
  insertNewMessage(message)
} 本文来自去找www.7zhao.net 

Note : You’ll need to open the Firebase Console and enable Storage . To do this, first select storage on the left, click Get Started , then choose default security rules.

内容来自www.7zhao.net

Build and run the app; tap on the little camera icon and send a photo message in your chat. Notice how the camera icon is disabled when your app is saving the photo data to Firebase Storage .

欢迎访问www.7zhao.net

www.7zhao.net

Kaboom! You just made a big, bad, real time, photo and text sending chat app. Go grab yourself your favorite beverage, you earned it!

copyright www.7zhao.net

Where to Go From Here?

Use the Download Materials button at the top or bottom of this tutorial to download the completed project.

www.7zhao.net

You now know the basics of Cloud Firestore and MessageKit , but there’s plenty more you can do, including one-to-one messaging, social authentication, and avatar display. www.7zhao.net

To take this app even further, you could take a look at the . You can also take a look at our 22 part video course onBeginning Firebase!

欢迎访问www.7zhao.net

I hope you’ve enjoyed this Firebase tutorial; if you have any questions feel free to leave them in the non-anonymous yet avatar-enabled discussion below! :] 内容来自www.7zhao.net

copyright www.7zhao.net

本文来自去找www.7zhao.net


本文原文地址:https://www.raywenderlich.com/194091/firebase-tutorial-real-time-chat-3

以上为Firebase Tutorial: Real-time Chat文章的全部内容,若您也有好的文章,欢迎与我们分享! www.7zhao.net

Copyright ©2008-2017去找网版权所有   皖ICP备12002049号-2 皖公网安备 34088102000435号   关于我们|联系我们| 免责声明|友情链接|网站地图|手机版