1. ภาพรวม
ยินดีต้อนรับสู่ Friendly Chat Codelab ใน Codelab นี้ คุณจะได้เรียนรู้วิธีใช้แพลตฟอร์ม Firebase เพื่อสร้างแอปพลิเคชัน iOS คุณจะใช้ไคลเอ็นต์แชทและตรวจสอบประสิทธิภาพโดยใช้ Firebase
สิ่งที่คุณจะได้เรียนรู้
- อนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
- ซิงค์ข้อมูลโดยใช้ฐานข้อมูลเรียลไทม์ของ Firebase
- จัดเก็บไฟล์ไบนารีใน Firebase Storage
สิ่งที่คุณต้องมี
- Xcode
- CocoaPods
- อุปกรณ์ทดสอบที่ใช้ iOS 8.0 ขึ้นไปหรือเครื่องจำลอง
คุณจะใช้บทแนะนำนี้อย่างไร
คุณจะให้คะแนนประสบการณ์ในการสร้างแอป iOS อย่างไร
2. รับโค้ดตัวอย่าง
โคลนที่เก็บ GitHub จากบรรทัดคำสั่ง
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. สร้างแอปเริ่มต้น
วิธีสร้างแอปเริ่มต้น
- ในหน้าต่างเทอร์มินัล ให้ไปที่ไดเรกทอรี
ios-starter/swift-starter
จากการดาวน์โหลดโค้ดตัวอย่าง - การเรียกใช้ครั้งที่
pod install --repo-update
- เปิดไฟล์ EasyChatSwift.xcworkspace เพื่อเปิดโปรเจ็กต์ใน Xcode
- คลิกปุ่ม เรียกใช้
คุณควรเห็นหน้าจอหลักของ friendly Chat ปรากฏขึ้นหลังจากผ่านไป 2-3 วินาที UI ควรจะปรากฏขึ้น อย่างไรก็ตาม ณ จุดนี้คุณจะไม่สามารถลงชื่อเข้าใช้ ส่ง หรือรับข้อความได้ แอปจะล้มเลิกโดยมีข้อยกเว้นจนกว่าคุณจะดำเนินการขั้นตอนถัดไปให้เสร็จสมบูรณ์
4. สร้างโปรเจ็กต์คอนโซล Firebase
สร้างโปรเจ็กต์
จากคอนโซล Firebase ให้เลือกเพิ่มโปรเจ็กต์
เรียกใช้โปรเจ็กต์ FriendlyChat
แล้วคลิกสร้างโปรเจ็กต์
อัปเกรดแพ็กเกจราคา Firebase
หากต้องการใช้ Cloud Storage สำหรับ Firebase โปรเจ็กต์ Firebase ของคุณต้องใช้แพ็กเกจราคาแบบจ่ายเมื่อใช้ (Blaze) ซึ่งหมายความว่าโปรเจ็กต์จะลิงก์กับบัญชีสำหรับการเรียกเก็บเงินใน Cloud
- บัญชีสำหรับการเรียกเก็บเงินใน Cloud ต้องมีวิธีการชำระเงิน เช่น บัตรเครดิต
- หากคุณเพิ่งเริ่มใช้ Firebase และ Google Cloud ให้ตรวจสอบว่าคุณมีสิทธิ์รับเครดิตมูลค่า $300 และบัญชีการเรียกเก็บเงินระบบคลาวด์แบบทดลองใช้ฟรีหรือไม่
- หากคุณทำ Codelab นี้เป็นส่วนหนึ่งของกิจกรรม โปรดสอบถามผู้จัดว่ามีเครดิต Cloud เหลืออยู่ไหม
หากต้องการอัปเกรดโปรเจ็กต์เป็นแพ็กเกจ Blaze ให้ทำตามขั้นตอนต่อไปนี้
- ในคอนโซล Firebase ให้เลือกอัปเกรดแพ็กเกจของคุณ
- เลือกแพ็กเกจ Blaze ทำตามวิธีการบนหน้าจอเพื่อลิงก์บัญชีสำหรับการเรียกเก็บเงินใน Cloud กับโปรเจ็กต์
หากต้องการสร้างบัญชีสำหรับการเรียกเก็บเงินใน Cloud ในการอัปเกรดนี้ คุณอาจต้องกลับไปที่ขั้นตอนการอัปเกรดในคอนโซล Firebase เพื่อทำการอัปเกรดให้เสร็จสมบูรณ์
เชื่อมต่อแอป iOS
- จากหน้าจอภาพรวมโปรเจ็กต์ของโปรเจ็กต์ใหม่ ให้คลิกเพิ่ม Firebase ไปยังแอป iOS
- ป้อนรหัสแพ็กเกจเป็น "
com.google.firebase.codelab.FriendlyChatSwift
" - ป้อนรหัส App Store เป็น "
123456
" - คลิกลงทะเบียนแอป
เพิ่มไฟล์ GoogleService-Info.plist ลงในแอป
ในหน้าจอที่ 2 ให้คลิกดาวน์โหลด GoogleService-Info.plist เพื่อดาวน์โหลดไฟล์การกําหนดค่าที่มีข้อมูลเมตา Firebase ที่จําเป็นสําหรับแอปของคุณทั้งหมด คัดลอกไฟล์นั้นไปยังแอปพลิเคชันและเพิ่มลงในเป้าหมาย FriendlyChatSwift
ตอนนี้คุณสามารถคลิก "x" ที่มุมขวาบนของป๊อปอัปเพื่อปิดป๊อปอัปได้ โดยข้ามขั้นตอนที่ 3 และ 4 เนื่องจากคุณจะทำขั้นตอนเหล่านั้นที่นี่
นําเข้าข้อบังคับของ 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
กําหนดค่า Authentication API
ก่อนที่แอปพลิเคชันของคุณจะสามารถเข้าถึง API การตรวจสอบสิทธิ์ Firebase ในนามของผู้ใช้ คุณจะต้องเปิดใช้ API ดังกล่าว
- ไปที่คอนโซล Firebase แล้วเลือกโปรเจ็กต์
- เลือกการตรวจสอบสิทธิ์
- เลือกแท็บวิธีการลงชื่อเข้าใช้
- สลับสวิตช์ Google เป็นเปิดใช้ (สีน้ำเงิน)
- กดบันทึกในกล่องโต้ตอบที่ปรากฏขึ้น
หากคุณได้รับข้อผิดพลาดในภายหลังใน Codelab นี้พร้อมข้อความ "CONFIGURATION_NOT_FOUND" ให้กลับมาที่ขั้นตอนนี้แล้วตรวจสอบงานอีกครั้ง
ยืนยันการพึ่งพา Firebase Auth
ยืนยันว่ามีทรัพยากร Dependency ของการตรวจสอบสิทธิ์ Firebase ในไฟล์ Podfile
Podfile
pod 'Firebase/Auth'
ตั้งค่า Info.plist สำหรับ Google Sign-In
คุณจะต้องเพิ่มรูปแบบ URL ที่กําหนดเองลงในโปรเจ็กต์ XCode
- เปิดการกําหนดค่าโปรเจ็กต์: ดับเบิลคลิกชื่อโปรเจ็กต์ในมุมมองแบบต้นไม้ทางด้านซ้าย เลือกแอปจากส่วน "เป้าหมาย" จากนั้นเลือกแท็บ "ข้อมูล" แล้วขยายส่วน "ประเภท URL"
- คลิกปุ่ม + แล้วเพิ่มรูปแบบ URL สําหรับรหัสไคลเอ็นต์ที่กลับด้าน หากต้องการค้นหาค่านี้ ให้เปิดไฟล์การกําหนดค่า GoogleService-Info.plist แล้วมองหาคีย์ REVERSED_CLIENT_ID คัดลอกค่าของคีย์นั้น แล้ววางลงในช่องรูปแบบ URL ในหน้าการกําหนดค่า เว้นฟิลด์อื่นๆ ว่างไว้
- เมื่อดำเนินการเสร็จแล้ว การกำหนดค่าควรมีลักษณะคล้ายกับข้อความต่อไปนี้ (แต่มีค่าเฉพาะแอปพลิเคชัน)
ตั้งค่า 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 ออกให้ฟังนะ
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)")
}
}
ทดสอบข้อความอ่านในฐานะผู้ใช้ที่ลงชื่อเข้าใช้
- คลิกปุ่ม เรียกใช้
- ระบบควรนําคุณไปยังหน้าจอลงชื่อเข้าใช้ทันที แตะปุ่ม Google Sign-In
- จากนั้นระบบจะนำคุณไปยังหน้าจอการรับส่งข้อความหากทุกอย่างเป็นไปอย่างถูกต้อง
6. เปิดใช้งาน Realtime Database
นำเข้าข้อความ
ในโปรเจ็กต์ของคุณในคอนโซล Firebase ให้เลือกรายการฐานข้อมูลที่แถบนำทางด้านซ้าย ในเมนูรายการเพิ่มเติมของฐานข้อมูล ให้เลือกนําเข้า JSON เรียกดูไฟล์ initial_messages.json
ในไดเรกทอรี friendlychat แล้วเลือกไฟล์นั้น จากนั้นคลิกปุ่มนำเข้า การดำเนินการนี้จะแทนที่ข้อมูลที่อยู่ในฐานข้อมูลของคุณ นอกจากนี้ คุณยังแก้ไขฐานข้อมูลได้โดยตรงโดยใช้เครื่องหมาย + สีเขียวและเครื่องหมาย x สีแดงเพื่อเพิ่มและนำรายการออก
หลังจากนําเข้าแล้ว ฐานข้อมูลควรมีลักษณะดังนี้
ยืนยันทรัพยากร Dependency ของฐานข้อมูล Firebase
ในบล็อก Dependencies ของไฟล์ Podfile
ให้ตรวจสอบว่ามี Firebase/Database
รวมอยู่ด้วย
Podfile
pod 'Firebase/Database'
ซิงค์ข้อความที่มีอยู่
เพิ่มโค้ดที่ซิงค์ข้อความที่เพิ่มใหม่กับ UI ของแอป
โค้ดที่คุณเพิ่มในส่วนนี้จะทําสิ่งต่อไปนี้
- เริ่มต้นฐานข้อมูล Firebase และเพิ่ม Listener เพื่อจัดการการเปลี่ยนแปลงในฐานข้อมูล
- อัปเดต
DataSnapshot
เพื่อแสดงข้อความใหม่
แก้ไขเมธอด "deinit", "configureDatabase" และ "tableView:cellForRow URLPath:" ของ 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
}
ทดสอบการซิงค์ข้อความ
- คลิกปุ่ม เรียกใช้
- คลิกปุ่มลงชื่อเข้าใช้เพื่อเริ่มต้นใช้งานเพื่อไปที่หน้าต่างข้อความ
- เพิ่มข้อความใหม่โดยตรงในคอนโซล Firebase โดยคลิกเครื่องหมาย + สีเขียวข้างรายการ "ข้อความ" แล้วเพิ่มออบเจ็กต์ดังตัวอย่างต่อไปนี้
- ตรวจสอบว่าข้อความปรากฏใน UI ของ Friendly-Chat
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)
}
ทดสอบการส่งข้อความ
- คลิกปุ่ม เรียกใช้
- คลิกลงชื่อเข้าใช้เพื่อไปที่หน้าต่างข้อความ
- พิมพ์ข้อความแล้วกดส่ง ข้อความใหม่ควรแสดงใน UI ของแอปและในคอนโซล Firebase
8. จัดเก็บและรับรูปภาพ
ยืนยันการพึ่งพาพื้นที่เก็บข้อมูลของ Firebase
ในบล็อกทรัพยากร Dependency ของ Podfile
ให้ยืนยันว่ามี Firebase/Storage
รวมอยู่ด้วย
Podfile
pod 'Firebase/Storage'
ตั้งค่า Cloud Storage สำหรับ Firebase
วิธีตั้งค่า Cloud Storage สำหรับ Firebase ในโปรเจ็กต์ Firebase มีดังนี้
- ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายบิลด์ แล้วเลือกพื้นที่เก็บข้อมูล
- คลิกเริ่มต้นใช้งาน
- เลือกตำแหน่งสำหรับที่เก็บข้อมูลเริ่มต้น
ที่เก็บข้อมูลในUS-WEST1
,US-CENTRAL1
และUS-EAST1
สามารถใช้แพ็กเกจ "ฟรีตลอด" สำหรับ Google Cloud Storage ที่เก็บข้อมูลในตำแหน่งอื่นๆ ทั้งหมดจะเป็นไปตามราคาและการใช้งาน Google Cloud Storage - คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎการรักษาความปลอดภัย
ในภายหลังในโค้ดแล็บนี้ คุณจะต้องเพิ่มกฎการรักษาความปลอดภัยเพื่อรักษาความปลอดภัยให้ข้อมูล อย่าเผยแพร่หรือเปิดเผยแอปต่อสาธารณะโดยไม่เพิ่มกฎความปลอดภัยสำหรับที่เก็บข้อมูล Storage - คลิกสร้าง
กําหนดค่า FirebaseStorage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
รับรูปภาพในข้อความที่มีอยู่
เพิ่มโค้ดที่ดาวน์โหลดรูปภาพจากพื้นที่เก็บข้อมูลของ Firebase
แก้ไขเมธอด "tableView: cellForRowAtindexPath:" ของ 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 and Send Images
อัปโหลดรูปภาพจากผู้ใช้ แล้วซิงค์ 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])
}
}
}
ทดสอบการส่งและการรับข้อความรูปภาพ
- คลิกปุ่ม เรียกใช้
- คลิกลงชื่อเข้าใช้เพื่อไปที่หน้าต่างข้อความ
- คลิกไอคอน "เพิ่มรูปภาพ" เพื่อเลือกรูปภาพ ข้อความใหม่พร้อมรูปภาพควรปรากฏใน UI ของแอปและในคอนโซล Firebase
10. ยินดีด้วย
คุณใช้ Firebase เพื่อสร้างแอปพลิเคชันแชทแบบเรียลไทม์ได้อย่างง่ายดาย
สิ่งที่เราได้พูดถึง
- Realtime Database
- การลงชื่อเข้าใช้แบบรวมศูนย์
- พื้นที่เก็บข้อมูล