Firebase iOS Codelab Swift

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

1. ภาพรวม

2efe6805ef369641.png

ยินดีต้อนรับสู่ Codelab แชทที่เป็นมิตร ใน Codelab นี้ คุณจะได้เรียนรู้วิธีใช้แพลตฟอร์ม Firebase เพื่อสร้างแอปพลิเคชัน iOS คุณจะใช้ไคลเอ็นต์แชทและตรวจสอบประสิทธิภาพโดยใช้ Firebase

Codelab นี้มีอยู่ใน Objective-C ด้วย

สิ่งที่คุณจะได้เรียนรู้

  • อนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
  • ซิงค์ข้อมูลโดยใช้ฐานข้อมูลเรียลไทม์ของ 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.png ไดเร็กทอรี ios-starter/swift-starter จากการดาวน์โหลดโค้ดตัวอย่างของคุณ
  2. เรียกใช้ pod install --repo-update
  3. เปิดไฟล์ FriendlyChatSwift.xcworkspace เพื่อเปิดโครงการใน Xcode
  4. คลิก 98205811bbed9d74.png ปุ่ม เรียกใช้

คุณควรเห็นหน้าจอหลักของแชทที่เป็นมิตรปรากฏขึ้นหลังจากผ่านไปสองสามวินาที UI ควรปรากฏขึ้น อย่างไรก็ตาม ณ จุดนี้ คุณไม่สามารถลงชื่อเข้าใช้ ส่ง หรือรับข้อความได้ แอปจะยกเลิกโดยมีข้อยกเว้นจนกว่าคุณจะทำขั้นตอนถัดไปให้เสร็จสิ้น

4. สร้างโปรเจ็กต์คอนโซล Firebase

สร้างโครงการ

จาก คอนโซล Firebase ให้เลือก Add Project

เรียกโครงการ FriendlyChat จากนั้นคลิกที่ Create Project

สกรีนช็อตจาก 2015-11-06 14:13:39.png

เชื่อมต่อแอพ iOS ของคุณ

  1. จากหน้าจอภาพรวมโปรเจ็กต์ของโปรเจ็กต์ใหม่ ให้คลิก เพิ่ม Firebase ในแอป iOS
  2. ป้อน ID ชุดเป็น " com.google.firebase.codelab.FriendlyChatSwift "
  3. ป้อนรหัส App Store เป็น " 123456 "
  4. คลิก ลงทะเบียนแอป

เพิ่มไฟล์ GoogleService-Info.plist ในแอปของคุณ

ในหน้าจอที่สอง ให้คลิก ดาวน์โหลด GoogleService-Info.plist เพื่อดาวน์โหลดไฟล์การกำหนดค่าที่มีข้อมูลเมตา Firebase ที่จำเป็นทั้งหมดสำหรับแอปของคุณ คัดลอกไฟล์นั้นไปยังแอปพลิเคชันของคุณและเพิ่มไปยังเป้าหมาย FriendlyChatSwift

ขณะนี้ คุณสามารถคลิก "x" ที่มุมขวาบนของป๊อปอัปเพื่อปิดได้ โดยข้ามขั้นตอนที่ 3 และ 4 ไป เนื่องจากคุณจะทำตามขั้นตอนเหล่านี้ที่นี่

19d59efb213ddbdc.png

นำเข้าโมดูล Firebase

เริ่มต้นด้วยการตรวจสอบให้แน่ใจว่านำเข้าโมดูล Firebase แล้ว

AppDelegate.swift , FCViewController.swift

import Firebase

กำหนดค่า Firebase ใน AppDelegate

ใช้เมธอด "กำหนดค่า" ใน FirebaseApp ภายในฟังก์ชัน application:didFinishLaunchingWithOptions เพื่อกำหนดค่าบริการ Firebase พื้นฐานจากไฟล์ .plist ของคุณ

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 Authentication API ในนามของผู้ใช้ คุณจะต้องเปิดใช้งานก่อน

  1. ไปที่ คอนโซล Firebase แล้วเลือกโปรเจ็กต์ของคุณ
  2. เลือก การตรวจสอบสิทธิ์
  3. เลือกแท็บ วิธีการลงชื่อเข้า ใช้
  4. สลับสวิตช์ Google เป็นเปิดใช้งาน (สีน้ำเงิน)
  5. กด บันทึก ในกล่องโต้ตอบผลลัพธ์

หากคุณได้รับข้อผิดพลาดในภายหลังใน Codelab นี้พร้อมด้วยข้อความ "CONFIGURATION_NOT_FOUND" ให้กลับมาที่ขั้นตอนนี้และตรวจสอบงานของคุณอีกครั้ง

ยืนยันการพึ่งพา Firebase Auth

ยืนยันว่ามีการพึ่งพา Firebase Auth ในไฟล์ Podfile

Podfile

pod 'Firebase/Auth'

ตั้งค่า Info.plist ของคุณสำหรับการลงชื่อเข้าใช้ Google

คุณจะต้องเพิ่มรูปแบบ URL ที่กำหนดเองให้กับโปรเจ็กต์ XCode ของคุณ

  1. เปิดการกำหนดค่าโครงการของคุณ: ดับเบิลคลิกที่ชื่อโครงการในมุมมองต้นไม้ด้านซ้าย เลือกแอปของคุณจากส่วนเป้าหมาย จากนั้นเลือกแท็บข้อมูล แล้วขยายส่วนประเภท URL
  2. คลิกปุ่ม + และเพิ่มรูปแบบ URL สำหรับรหัสไคลเอ็นต์ที่ย้อนกลับของคุณ หากต้องการค้นหาค่านี้ ให้เปิดไฟล์การกำหนดค่า GoogleService-Info.plist และมองหาคีย์ REVERSED_CLIENT_ID คัดลอกค่าของคีย์นั้น และวางลงในกล่อง URL Schemes บนหน้าการกำหนดค่า เว้นช่องอื่นๆ ให้ว่างไว้
  3. เมื่อเสร็จสิ้น การกำหนดค่าของคุณควรมีลักษณะคล้ายกับต่อไปนี้ (แต่ด้วยค่าเฉพาะแอปพลิเคชันของคุณ):

1b54d5bd2f4f1448.png

ตั้งค่า clientID สำหรับ Google Sign In

หลังจากกำหนดค่า Firebase เราสามารถใช้ clientID เพื่อตั้งค่า Google Sign In ภายในเมธอด "didFinishLaunchingWithOptions:"

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
      }
    }
  }

ลงชื่อเข้าใช้ผู้ใช้โดยอัตโนมัติ จากนั้นเพิ่ม Listener ไปยัง Firebase Auth เพื่อให้ผู้ใช้เข้าสู่แอปได้หลังจากลงชื่อเข้าใช้สำเร็จ และลบ Listener บน 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 เลือกรายการ ฐานข้อมูล บนแถบนำทางด้านซ้าย ในเมนูรายการเพิ่มเติมของฐานข้อมูล ให้เลือก นำเข้า JSON เรียกดูไฟล์ initial_messages.json ในไดเร็กทอรี friendlychat เลือกไฟล์ จากนั้นคลิกปุ่ม นำเข้า การดำเนินการนี้จะแทนที่ข้อมูลใดๆ ที่อยู่ในฐานข้อมูลของคุณในปัจจุบัน คุณยังสามารถแก้ไขฐานข้อมูลได้โดยตรง โดยใช้เครื่องหมาย + และ x สีแดงเพื่อเพิ่มและลบรายการ

20ccf4856b715b4c.png

หลังจากนำเข้าฐานข้อมูลของคุณควรมีลักษณะดังนี้:

f3e0367f1c9cd187.png

ยืนยันการพึ่งพาฐานข้อมูล Firebase

ในบล็อกการพึ่งพาของไฟล์ Podfile ให้ยืนยันว่ารวม Firebase/Database แล้ว

Podfile

pod 'Firebase/Database'

ประสานข้อความที่มีอยู่

เพิ่มรหัสที่ซิงโครไนซ์ข้อความที่เพิ่มใหม่ไปยัง UI ของแอป

รหัสที่คุณเพิ่มในส่วนนี้จะ:

  • เริ่มต้นฐานข้อมูล Firebase และเพิ่ม Listener เพื่อจัดการการเปลี่ยนแปลงที่เกิดขึ้นกับฐานข้อมูล
  • อัปเดต DataSnapshot เพื่อให้แสดงข้อความใหม่

แก้ไขเมธอด "deinit", "configureDatabase" และ "tableView:cellForRow indexPath:" ของ FCViewController แทนที่ด้วยรหัสที่กำหนดไว้ด้านล่าง:

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. ยืนยันว่าปรากฏใน UI แชทที่เป็นมิตร

7. ส่งข้อความ

ใช้งาน ส่งข้อความ

ผลักค่าไปยังฐานข้อมูล เมื่อคุณใช้วิธีพุชเพื่อเพิ่มข้อมูลไปยังฐานข้อมูลเรียลไทม์ของ Firebase ระบบจะเพิ่ม ID อัตโนมัติ รหัสที่สร้างขึ้นโดยอัตโนมัติเหล่านี้เป็นแบบเรียงตามลำดับ ซึ่งทำให้แน่ใจได้ว่าข้อความใหม่จะถูกเพิ่มในลำดับที่ถูกต้อง

แก้ไขเมธอด "sendMessage:" ของ FCViewController แทนที่ด้วยรหัสที่กำหนดไว้ด้านล่าง:

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 Storage ในแดชบอร์ด

ไปที่คอนโซล Firebase และยืนยันว่าเปิดใช้งานพื้นที่เก็บข้อมูลด้วยโดเมน "gs://PROJECTID.appspot.com"

b0438b37a588bcee.png

หากคุณเห็นหน้าต่างการเปิดใช้งานแทน ให้คลิก "เริ่มต้น" เพื่อเปิดใช้งานด้วยกฎเริ่มต้น

c290bbebff2cafa7.png

กำหนดค่า FirebaseStorage

FCViewController.swift

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

รับภาพในข้อความที่มีอยู่

เพิ่มโค้ดที่ดาวน์โหลดรูปภาพจาก Firebase Storage

แก้ไขเมธอด "tableView: cellForRowAt indexPath:" ของ FCViewController แทนที่ด้วยรหัสที่กำหนดไว้ด้านล่าง:

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. ส่งข้อความรูปภาพ

ใช้งาน Store และส่งรูปภาพ

อัปโหลดรูปภาพจากผู้ใช้ จากนั้นซิงค์ URL ที่เก็บข้อมูลของรูปภาพนี้กับฐานข้อมูล เพื่อให้รูปภาพนี้ถูกส่งไปภายในข้อความ

แก้ไขเมธอด "imagePickerController: didFinishPickingMediaWithInfo:" ของ FCViewController แทนที่ด้วยรหัสที่กำหนดไว้ด้านล่าง:

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 เพื่อสร้างแอปพลิเคชันแชทแบบเรียลไทม์ได้อย่างง่ายดาย

สิ่งที่เราได้กล่าวถึง

  • ฐานข้อมูลเรียลไทม์
  • เข้าสู่ระบบสหพันธรัฐ
  • พื้นที่จัดเก็บ

เรียนรู้เพิ่มเติม