Firebase iOS Codelab สวิฟท์

1. ภาพรวม

2efe6805ef369641.png

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

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

  • อนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
  • ซิงค์ข้อมูลโดยใช้ฐานข้อมูล Firebase Realtime
  • จัดเก็บไฟล์ไบนารี่ใน 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 ปุ่ม เรียกใช้

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

4. สร้างโครงการคอนโซล Firebase

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

จาก คอนโซล Firebase เลือก เพิ่มโครงการ

เรียกโปรเจ็กต์ FriendlyChat จากนั้นคลิกที่ Create Project

ภาพหน้าจอจาก 06-11-2015 14:13:39.png

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

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

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

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

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

19d59efb213ddbdc.png

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

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

AppDelegate.swift , FCViewController.swift

import Firebase

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

ใช้เมธอด "configure" ใน 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

พอดไฟล์

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

หลังจากกำหนดค่า 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 แล้ว

พอดไฟล์

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. ยืนยันว่าปรากฏใน Friendly-Chat UI

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

ดำเนินการส่งข้อความ

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

แก้ไขเมธอด "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. ส่งข้อความรูปภาพ

ใช้จัดเก็บและส่งรูปภาพ

อัปโหลดรูปภาพจากผู้ใช้ จากนั้นซิงค์ 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 เพื่อสร้างแอปพลิเคชันแชทแบบเรียลไทม์ได้อย่างง่ายดาย

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

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

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