Firebase iOS Codelab Swift

1. ภาพรวม

2efe6805ef369641.png

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

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

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

  • อนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
  • ซิงค์ข้อมูลโดยใช้ Firebase Realtime Database
  • จัดเก็บไฟล์ไบนารีใน Firebase Storage

สิ่งที่คุณต้องการ

  • เอ็กซ์โค้ด
  • ฝักโกโก้
  • อุปกรณ์ทดสอบที่ใช้ 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 เลือก เพิ่มโครงการ

โทรหาโปรเจ็กต์ 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 APIs ในนามของผู้ใช้ได้ คุณจะต้องเปิดใช้งานก่อน

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

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

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

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

พ็อดไฟล์

pod 'Firebase/Auth'

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

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

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

1b54d5bd2f4f1448.png

กำหนดรหัสลูกค้าสำหรับการลงชื่อเข้าใช้ Google

หลังจากกำหนดค่า Firebase แล้ว เราสามารถใช้รหัสลูกค้าเพื่อตั้งค่าการลงชื่อเข้าใช้ Google ภายในเมธอด "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
      }
    }
  }

ลงชื่อเข้าใช้ผู้ใช้โดยอัตโนมัติ จากนั้นเพิ่มผู้ฟังใน Firebase Auth เพื่อให้ผู้ใช้เข้าสู่แอปได้หลังจากลงชื่อเข้าใช้สำเร็จ และนำผู้ฟังออกทันที

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 เลือกไฟล์จากนั้นคลิกปุ่ม นำเข้า สิ่งนี้จะแทนที่ข้อมูลใด ๆ ที่อยู่ในฐานข้อมูลของคุณในปัจจุบัน คุณยังสามารถแก้ไขฐานข้อมูลได้โดยตรง โดยใช้เครื่องหมาย + สีเขียวและสีแดงเพื่อเพิ่มและลบรายการ

20ccf4856b715b4c.png

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

f3e0367f1c9cd187.png

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

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

พ็อดไฟล์

pod 'Firebase/Database'

ซิงโครไนซ์ข้อความที่มีอยู่

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

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

  • เริ่มต้นฐานข้อมูล Firebase และเพิ่มผู้ฟังเพื่อจัดการกับการเปลี่ยนแปลงที่เกิดขึ้นกับฐานข้อมูล
  • อัปเดต 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 Realtime Database ระบบจะเพิ่ม ID อัตโนมัติ 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 รวมอยู่ด้วย

พ็อดไฟล์

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

สิ่งที่เราได้ครอบคลุม

  • ฐานข้อมูลเรียลไทม์
  • ลงชื่อเข้าใช้แบบรวมศูนย์
  • พื้นที่จัดเก็บ

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