Firebase Android Codelab - สร้างแชทที่เป็นกันเอง

1. ภาพรวม

ภาพหน้าจอ

รูปภาพ: แอป Friendly Chat ที่ใช้งานได้

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

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

  • วิธีใช้การตรวจสอบสิทธิ์ Firebase เพื่ออนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
  • วิธีซิงค์ข้อมูลโดยใช้ฐานข้อมูลเรียลไทม์ของ Firebase
  • วิธีจัดเก็บไฟล์ไบนารีใน Cloud Storage for Firebase
  • วิธีใช้ Firebase Local Emulator Suite เพื่อพัฒนาแอป Android ด้วย Firebase

สิ่งที่ต้องมี

  • Android Studio เวอร์ชันล่าสุด
  • โปรแกรมจำลอง Android ที่ใช้ Android 5.0 ขึ้นไป
  • Node.js เวอร์ชัน 10 ขึ้นไป (หากต้องการใช้ชุดโปรแกรมจำลอง)
  • Java 8 ขึ้นไป หากต้องการติดตั้ง Java ให้ใช้วิธีการเหล่านี้ หากต้องการตรวจสอบเวอร์ชัน ให้เรียกใช้ java -version
  • มีความคุ้นเคยกับภาษาโปรแกรม Kotlin

2. รับโค้ดตัวอย่าง

โคลนที่เก็บ

โคลนที่เก็บ GitHub จากบรรทัดคำสั่งโดยทำดังนี้

$ git clone https://github.com/firebase/codelab-friendlychat-android

นำเข้าไปยัง Android Studio

ใน Android Studio ให้เลือกไฟล์ > เปิด จากนั้นเลือกไดเรกทอรี build-android-start ( android_studio_folder) จากไดเรกทอรีที่คุณดาวน์โหลดโค้ดตัวอย่าง

ตอนนี้คุณควรมีโปรเจ็กต์ build-android-start เปิดอยู่ใน Android Studio ไม่ต้องกังวลหากเห็นคำเตือนเกี่ยวกับgoogle-services.jsonไฟล์ที่หายไป โดยจะเพิ่มในขั้นตอนถัดไป

ตรวจสอบทรัพยากร Dependency

ใน Codelab นี้ เราได้เพิ่มการขึ้นต่อกันทั้งหมดที่คุณต้องการให้คุณแล้ว แต่คุณควรทำความเข้าใจวิธีเพิ่ม Firebase SDK ลงในแอป

build.gradle.kts

plugins {
    id("com.android.application") version "8.0.0" apply false
    id("com.android.library") version "8.0.0" apply false
    id("org.jetbrains.kotlin.android") version "1.8.20" apply false

    // The google-services plugin is required to parse the google-services.json file
    id("com.google.gms.google-services") version "4.3.15" apply false
}

app/build.gradle.kts

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("com.google.gms.google-services")
}

android {
    // ...
}

dependencies {
    // ...

    // Google Sign In SDK
    implementation("com.google.android.gms:play-services-auth:20.5.0")

    // Firebase SDK
    implementation(platform("com.google.firebase:firebase-bom:32.0.0"))
    implementation("com.google.firebase:firebase-database-ktx")
    implementation("com.google.firebase:firebase-storage-ktx")
    implementation("com.google.firebase:firebase-auth-ktx")

    // Firebase UI Library
    implementation("com.firebaseui:firebase-ui-auth:8.0.2")
    implementation("com.firebaseui:firebase-ui-database:8.0.2")
}

3. ติดตั้ง Firebase CLI

ในโค้ดแล็บนี้ คุณจะได้ใช้ชุดโปรแกรมจำลอง Firebase เพื่อจำลอง Firebase Auth, Realtime Database และ Cloud Storage ในเครื่อง ซึ่งจะช่วยให้คุณมีสภาพแวดล้อมการพัฒนาในเครื่องที่ปลอดภัย รวดเร็ว และไม่มีค่าใช้จ่ายเพื่อสร้างแอป

ติดตั้ง Firebase CLI

ก่อนอื่นคุณจะต้องติดตั้ง Firebase CLI หากใช้ macOS หรือ Linux คุณสามารถเรียกใช้คำสั่ง cURL ต่อไปนี้

curl -sL https://firebase.tools | bash

หากใช้ Windows โปรดอ่านวิธีการติดตั้งเพื่อรับไบนารีแบบสแตนด์อโลนหรือติดตั้งผ่าน npm

เมื่อติดตั้ง CLI แล้ว การเรียกใช้ firebase --version ควรรายงานเวอร์ชันของ 9.0.0 ขึ้นไป

$ firebase --version
9.0.0

เข้าสู่ระบบ

เรียกใช้ firebase login เพื่อเชื่อมต่อ CLI กับบัญชี Google ซึ่งจะเป็นการเปิดหน้าต่างเบราว์เซอร์ใหม่เพื่อทำกระบวนการเข้าสู่ระบบให้เสร็จสมบูรณ์ โปรดเลือกบัญชีเดียวกับที่ใช้เมื่อสร้างโปรเจ็กต์ Firebase ก่อนหน้านี้

4. เชื่อมต่อกับ Firebase Emulator Suite

เริ่มโปรแกรมจำลอง

ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้จากรูทของไดเรกทอรี codelab-friendlychat-android ในเครื่อง

firebase emulators:start --project=demo-friendlychat-android

คุณควรเห็นบันทึกบางอย่างดังนี้ ค่าพอร์ตได้รับการกำหนดไว้ในไฟล์ firebase.json ซึ่งรวมอยู่ในโค้ดตัวอย่างที่โคลน

$ firebase emulators:start --project=demo-friendlychat-android
i  emulators: Starting emulators: auth, database, storage
i  emulators: Detected demo project ID "demo-friendlychat-android", emulated services will use a demo configuration and attempts to access non-emulated services for this project will fail.
i  database: Database Emulator logging to database-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│   All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬────────────────────────────────┐
│ Emulator        Host:Port       View in Emulator UI            │
├────────────────┼────────────────┼────────────────────────────────┤
│ Authentication  localhost:9099  http://localhost:4000/auth     │
├────────────────┼────────────────┼────────────────────────────────┤
│ Database        localhost:9000  http://localhost:4000/database │
├────────────────┼────────────────┼────────────────────────────────┤
│ Storage         localhost:9199  http://localhost:4000/storage  │
└────────────────┴────────────────┴────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

ไปที่ http://localhost:4000 ในเว็บเบราว์เซอร์เพื่อดู UI ของ Firebase Emulator Suite

หน้าแรกของ UI ชุดโปรแกรมจำลอง

ปล่อยให้คำสั่ง emulators:start ทำงานต่อไปสำหรับส่วนที่เหลือของโค้ดแล็บ

เชื่อมต่อแอป

ใน Android Studio ให้เปิด MainActivity.kt จากนั้นเพิ่มโค้ดต่อไปนี้ภายในเมธอด onCreate

// When running in debug mode, connect to the Firebase Emulator Suite.
// "10.0.2.2" is a special IP address which allows the Android Emulator
// to connect to "localhost" on the host computer. The port values (9xxx)
// must match the values defined in the firebase.json file.
if (BuildConfig.DEBUG) {
    Firebase.database.useEmulator("10.0.2.2", 9000)
    Firebase.auth.useEmulator("10.0.2.2", 9099)
    Firebase.storage.useEmulator("10.0.2.2", 9199)
}

5. เรียกใช้แอปเริ่มต้น

เพิ่ม google-services.json

หากต้องการให้แอป Android เชื่อมต่อกับ Firebase ได้ คุณต้องเพิ่มไฟล์ google-services.json ภายในโฟลเดอร์ app ของโปรเจ็กต์ Android เพื่อวัตถุประสงค์ของโค้ดแล็บนี้ เราได้จัดเตรียมไฟล์ JSON จำลองที่จะช่วยให้คุณเชื่อมต่อกับ Firebase Emulator Suite ได้

คัดลอกไฟล์ mock-google-services.json ไปยังโฟลเดอร์ build-android-start/app เป็น google-services.json ดังนี้

cp mock-google-services.json build-android-start/app/google-services.json

ในขั้นตอนสุดท้ายของโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีสร้างโปรเจ็กต์ Firebase และแอป Firebase Android จริง เพื่อให้คุณแทนที่ไฟล์ JSON จำลองนี้ด้วยการกำหนดค่าของคุณเองได้

เรียกใช้แอป

ตอนนี้คุณได้นำเข้าโปรเจ็กต์ไปยัง Android Studio และเพิ่มไฟล์ JSON การกำหนดค่า Firebase แล้ว คุณก็พร้อมที่จะเรียกใช้แอปเป็นครั้งแรก

  1. เริ่มโปรแกรมจำลอง Android
  2. ใน Android Studio ให้คลิกเรียกใช้ ( ดำเนินการ) ในแถบเครื่องมือ

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

6. เปิดใช้การตรวจสอบสิทธิ์

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

เพิ่มฟังก์ชันการลงชื่อเข้าใช้พื้นฐาน

จากนั้นเราจะเพิ่มโค้ดการตรวจสอบสิทธิ์ Firebase ขั้นพื้นฐานบางส่วนลงในแอปเพื่อตรวจหาผู้ใช้และใช้หน้าจอลงชื่อเข้าใช้

ตรวจสอบผู้ใช้ปัจจุบัน

ก่อนอื่นให้เพิ่มตัวแปรอินสแตนซ์ต่อไปนี้ลงในคลาส MainActivity.kt

MainActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

ตอนนี้เรามาแก้ไข MainActivity เพื่อส่งผู้ใช้ไปยังหน้าจอลงชื่อเข้าใช้ทุกครั้งที่ผู้ใช้เปิดแอปและยังไม่ได้ยืนยันตัวตน เพิ่มรายการต่อไปนี้ลงในonCreate()เมธอดหลังจากแนบbindingกับวิวแล้ว

MainActivity.kt

// Initialize Firebase Auth and check if the user is signed in
auth = Firebase.auth
if (auth.currentUser == null) {
    // Not signed in, launch the Sign In activity
    startActivity(Intent(this, SignInActivity::class.java))
    finish()
    return
}

นอกจากนี้ เรายังต้องการตรวจสอบว่าผู้ใช้ลงชื่อเข้าใช้ในระหว่าง onStart() หรือไม่

MainActivity.kt

public override fun onStart() {
    super.onStart()
    // Check if user is signed in.
    if (auth.currentUser == null) {
        // Not signed in, launch the Sign In activity
        startActivity(Intent(this, SignInActivity::class.java))
        finish()
        return
    }
}

จากนั้นใช้เมธอด getUserPhotoUrl() และ getUserName() เพื่อแสดงข้อมูลที่เหมาะสมเกี่ยวกับผู้ใช้ Firebase ที่ได้รับการตรวจสอบสิทธิ์ในปัจจุบัน

MainActivity.kt

private fun getPhotoUrl(): String? {
    val user = auth.currentUser
    return user?.photoUrl?.toString()
}

private fun getUserName(): String? {
    val user = auth.currentUser
    return if (user != null) {
        user.displayName
    } else ANONYMOUS
}

จากนั้นใช้signOut()วิธีจัดการปุ่มออกจากระบบดังนี้

MainActivity.kt

private fun signOut() {
    AuthUI.getInstance().signOut()
    startActivity(Intent(this, SignInActivity::class.java))
    finish()
}

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

ใช้หน้าจอลงชื่อเข้าใช้

เปิดไฟล์ SignInActivity.kt ในที่นี้ เราใช้ปุ่มลงชื่อเข้าใช้แบบง่ายเพื่อเริ่มการตรวจสอบสิทธิ์ ในส่วนนี้ คุณจะใช้ FirebaseUI เพื่อใช้ตรรกะสำหรับการลงชื่อเข้าใช้

เพิ่มตัวแปรอินสแตนซ์ Auth ในSignInActivity คลาสภายใต้ความคิดเห็น // Firebase instance variables

SignInActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

จากนั้นแก้ไขเมธอด onCreate() เพื่อเริ่มต้น Firebase ในลักษณะเดียวกับที่คุณทำใน MainActivity

SignInActivity.kt

// Initialize FirebaseAuth
auth = Firebase.auth

เพิ่มฟิลด์ ActivityResultLauncher ลงใน SignInActivity โดยทำดังนี้

SignInActivity.kt

// ADD THIS
private val signIn: ActivityResultLauncher<Intent> =
        registerForActivityResult(FirebaseAuthUIActivityResultContract(), this::onSignInResult)

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
}

จากนั้นแก้ไขเมธอด onStart() เพื่อเริ่มขั้นตอนการลงชื่อเข้าใช้ FirebaseUI โดยทำดังนี้

SignInActivity.kt

public override fun onStart() {
    super.onStart()

    // If there is no signed in user, launch FirebaseUI
    // Otherwise head to MainActivity
    if (Firebase.auth.currentUser == null) {
        // Sign in with FirebaseUI, see docs for more details:
        // https://firebase.google.com/docs/auth/android/firebaseui
        val signInIntent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setLogo(R.mipmap.ic_launcher)
                .setAvailableProviders(listOf(
                        AuthUI.IdpConfig.EmailBuilder().build(),
                        AuthUI.IdpConfig.GoogleBuilder().build(),
                ))
                .build()

        signIn.launch(signInIntent)
    } else {
        goToMainActivity()
    }
}

จากนั้นใช้เมธอด onSignInResult เพื่อจัดการผลการลงชื่อเข้าใช้ หากลงชื่อเข้าใช้สำเร็จ ให้ไปที่MainActivity

SignInActivity.kt

private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) {
    if (result.resultCode == RESULT_OK) {
        Log.d(TAG, "Sign in successful!")
        goToMainActivity()
    } else {
        Toast.makeText(
                this,
                "There was an error signing in",
                Toast.LENGTH_LONG).show()

        val response = result.idpResponse
        if (response == null) {
            Log.w(TAG, "Sign in canceled")
        } else {
            Log.w(TAG, "Sign in error", response.error)
        }
    }
}

เพียงเท่านี้ก็เสร็จแล้ว! คุณได้ใช้การตรวจสอบสิทธิ์กับ FirebaseUI ด้วยการเรียกใช้เมธอดเพียงไม่กี่ครั้งและไม่ต้องจัดการการกำหนดค่าฝั่งเซิร์ฟเวอร์ใดๆ

ทดสอบงาน

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

หลังจากลงชื่อเข้าใช้แล้ว ให้เปิด UI ของ Firebase Emulator Suite ในเบราว์เซอร์ จากนั้นคลิกแท็บการตรวจสอบสิทธิ์เพื่อดูบัญชีผู้ใช้ที่ลงชื่อเข้าใช้เป็นครั้งแรกนี้

7. อ่านข้อความ

ในขั้นตอนนี้ เราจะเพิ่มฟังก์ชันการทำงานเพื่ออ่านและแสดงข้อความที่จัดเก็บไว้ใน Realtime Database

นำเข้าข้อความตัวอย่าง

  1. ใน UI ของ Firebase Emulator Suite ให้เลือกแท็บฐานข้อมูลเรียลไทม์
  2. ลากและวางไฟล์ initial_messages.json จากสำเนารีโปซิโทรี Codelab ในเครื่องลงในเครื่องมือแสดงข้อมูล

ตอนนี้คุณควรมีข้อความ 2-3 ข้อความภายใต้โหนด messages ของฐานข้อมูล

อ่านข้อมูล

ซิงค์ข้อความ

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

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

MainActivity.kt

// Firebase instance variables
// ...
private lateinit var db: FirebaseDatabase
private lateinit var adapter: FriendlyMessageAdapter

แก้ไขเมธอด onCreate() ของ MainActivity ภายใต้ความคิดเห็น // Initialize Realtime Database and FirebaseRecyclerAdapter ด้วยโค้ดที่กำหนดไว้ด้านล่าง โค้ดนี้จะเพิ่มข้อความที่มีอยู่ทั้งหมดจากฐานข้อมูลเรียลไทม์ จากนั้นจะรอรายการใหม่ที่อยู่ภายใต้เส้นทาง messages ในฐานข้อมูลเรียลไทม์ของ Firebase โดยจะเพิ่มองค์ประกอบใหม่ลงใน UI สำหรับแต่ละข้อความ ดังนี้

MainActivity.kt

// Initialize Realtime Database
db = Firebase.database
val messagesRef = db.reference.child(MESSAGES_CHILD)

// The FirebaseRecyclerAdapter class and options come from the FirebaseUI library
// See: https://github.com/firebase/FirebaseUI-Android
val options = FirebaseRecyclerOptions.Builder<FriendlyMessage>()
    .setQuery(messagesRef, FriendlyMessage::class.java)
    .build()
adapter = FriendlyMessageAdapter(options, getUserName())
binding.progressBar.visibility = ProgressBar.INVISIBLE
manager = LinearLayoutManager(this)
manager.stackFromEnd = true
binding.messageRecyclerView.layoutManager = manager
binding.messageRecyclerView.adapter = adapter

// Scroll down when a new message arrives
// See MyScrollToBottomObserver for details
adapter.registerAdapterDataObserver(
    MyScrollToBottomObserver(binding.messageRecyclerView, adapter, manager)
)

จากนั้นในFriendlyMessageAdapter.ktคลาส ให้ใช้เมธอด bind() ภายในคลาสใน MessageViewHolder() ดังนี้

FriendlyMessageAdapter.kt

inner class MessageViewHolder(private val binding: MessageBinding) : ViewHolder(binding.root) {
    fun bind(item: FriendlyMessage) {
        binding.messageTextView.text = item.text
        setTextColor(item.name, binding.messageTextView)

        binding.messengerTextView.text = if (item.name == null) ANONYMOUS else item.name
        if (item.photoUrl != null) {
            loadImageIntoView(binding.messengerImageView, item.photoUrl!!)
        } else {
            binding.messengerImageView.setImageResource(R.drawable.ic_account_circle_black_36dp)
        }
    }
    ...
}

นอกจากนี้ เรายังต้องแสดงข้อความที่เป็นรูปภาพด้วย ดังนั้นให้ใช้เมธอด bind() ภายในคลาสใน ImageMessageViewHolder() ด้วย

FriendlyMessageAdapter.kt

inner class ImageMessageViewHolder(private val binding: ImageMessageBinding) :
    ViewHolder(binding.root) {
    fun bind(item: FriendlyMessage) {
        loadImageIntoView(binding.messageImageView, item.imageUrl!!)

        binding.messengerTextView.text = if (item.name == null) ANONYMOUS else item.name
        if (item.photoUrl != null) {
            loadImageIntoView(binding.messengerImageView, item.photoUrl!!)
        } else {
            binding.messengerImageView.setImageResource(R.drawable.ic_account_circle_black_36dp)
        }
    }
}

สุดท้ายนี้ กลับไปที่ MainActivity แล้วเริ่มและหยุดฟังการอัปเดตจากฐานข้อมูลเรียลไทม์ของ Firebase อัปเดตเมธอด onPause() และ onResume() ใน MainActivity ดังที่แสดงด้านล่าง

MainActivity.kt

public override fun onPause() {
    adapter.stopListening()
    super.onPause()
}

public override fun onResume() {
    super.onResume()
    adapter.startListening()
}

ทดสอบการซิงค์ข้อความ

  1. คลิกเรียกใช้ ( ดำเนินการ)
  2. ใน UI ของ Emulator Suite ให้กลับไปที่แท็บ Realtime Database แล้วเพิ่มข้อความใหม่ด้วยตนเอง ตรวจสอบว่าข้อความปรากฏในแอป Android โดยทำดังนี้

ขอแสดงความยินดี คุณเพิ่งเพิ่ม Realtime Database ลงในแอป

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

ติดตั้งใช้งานการส่งข้อความ

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

อัปเดตเครื่องมือฟังการคลิกของปุ่มส่งในเมธอด onCreate() ในคลาส MainActivity รหัสนี้อยู่ที่ด้านล่างของเมธอด onCreate() อยู่แล้ว อัปเดตonClick()เนื้อหาให้ตรงกับโค้ดด้านล่าง

MainActivity.kt

// Disable the send button when there's no text in the input field
// See MyButtonObserver for details
binding.messageEditText.addTextChangedListener(MyButtonObserver(binding.sendButton))

// When the send button is clicked, send a text message
binding.sendButton.setOnClickListener {
    val friendlyMessage = FriendlyMessage(
        binding.messageEditText.text.toString(),
        getUserName(),
        getPhotoUrl(),
        null /* no image */
    )
    db.reference.child(MESSAGES_CHILD).push().setValue(friendlyMessage)
    binding.messageEditText.setText("")
}

ใช้การส่งข้อความรูปภาพ

ในส่วนนี้ คุณจะเพิ่มความสามารถให้ผู้ใช้แอปส่งข้อความรูปภาพได้ การสร้างข้อความรูปภาพทำได้โดยทำตามขั้นตอนต่อไปนี้

  • เลือกรูปภาพ
  • จัดการการเลือกรูปภาพ
  • เขียนข้อความรูปภาพชั่วคราวไปยัง Realtime Database
  • เริ่มอัปโหลดรูปภาพที่เลือก
  • อัปเดต URL ของข้อความรูปภาพเป็น URL ของรูปภาพที่อัปโหลดเมื่ออัปโหลดเสร็จสมบูรณ์

เลือกรูปภาพ

หากต้องการเพิ่มรูปภาพ Codelab นี้จะใช้ Cloud Storage for Firebase Cloud Storage เป็นที่เก็บข้อมูลไบนารีของแอปที่เหมาะสม

จัดการการเลือกรูปภาพและเขียนข้อความชั่วคราว

เมื่อผู้ใช้เลือกรูปภาพแล้ว ระบบจะเปิดใช้การเลือกรูปภาพ Intent ซึ่งได้มีการติดตั้งใช้งานในโค้ดที่ส่วนท้ายของเมธอด onCreate() แล้ว เมื่อเสร็จแล้ว ระบบจะเรียกใช้เมธอด MainActivity's onImageSelected() การใช้ข้อมูลโค้ดด้านล่างจะช่วยให้คุณเขียนข้อความที่มี URL ของรูปภาพชั่วคราวลงในฐานข้อมูลเพื่อระบุว่ากำลังอัปโหลดรูปภาพ

MainActivity.kt

private fun onImageSelected(uri: Uri) {
    Log.d(TAG, "Uri: $uri")
    val user = auth.currentUser
    val tempMessage = FriendlyMessage(null, getUserName(), getPhotoUrl(), LOADING_IMAGE_URL)
    db.reference
            .child(MESSAGES_CHILD)
            .push()
            .setValue(
                    tempMessage,
                    DatabaseReference.CompletionListener { databaseError, databaseReference ->
                        if (databaseError != null) {
                            Log.w(
                                    TAG, "Unable to write message to database.",
                                    databaseError.toException()
                            )
                            return@CompletionListener
                        }

                        // Build a StorageReference and then upload the file
                        val key = databaseReference.key
                        val storageReference = Firebase.storage
                                .getReference(user!!.uid)
                                .child(key!!)
                                .child(uri.lastPathSegment!!)
                        putImageInStorage(storageReference, uri, key)
                    })
}

อัปโหลดรูปภาพและอัปเดตข้อความ

เพิ่มวิธีการ putImageInStorage() ถึง MainActivity โดยจะเรียกใช้ฟังก์ชันนี้onImageSelected()เพื่อเริ่มอัปโหลดรูปภาพที่เลือก เมื่ออัปโหลดเสร็จแล้ว คุณจะอัปเดตข้อความให้ใช้รูปภาพที่เหมาะสม

MainActivity.kt

private fun putImageInStorage(storageReference: StorageReference, uri: Uri, key: String?) {
    // First upload the image to Cloud Storage
    storageReference.putFile(uri)
        .addOnSuccessListener(
            this
        ) { taskSnapshot -> // After the image loads, get a public downloadUrl for the image
            // and add it to the message.
            taskSnapshot.metadata!!.reference!!.downloadUrl
                .addOnSuccessListener { uri ->
                    val friendlyMessage =
                        FriendlyMessage(null, getUserName(), getPhotoUrl(), uri.toString())
                    db.reference
                        .child(MESSAGES_CHILD)
                        .child(key!!)
                        .setValue(friendlyMessage)
                }
        }
        .addOnFailureListener(this) { e ->
            Log.w(
                TAG,
                "Image upload task was unsuccessful.",
                e
            )
        }
}

ทดสอบการส่งข้อความ

  1. ใน Android Studio ให้คลิกปุ่มดำเนินการเรียกใช้
  2. ใน Android Emulator ให้ป้อนข้อความ แล้วแตะปุ่มส่ง ข้อความใหม่ควรปรากฏใน UI ของแอปและใน UI ของ Firebase Emulator Suite
  3. ในโปรแกรมจำลอง Android ให้แตะรูปภาพ "+" เพื่อเลือกรูปภาพจากอุปกรณ์ ข้อความใหม่ควรแสดงก่อนพร้อมกับรูปภาพตัวยึดตำแหน่ง จากนั้นจึงแสดงพร้อมกับรูปภาพที่เลือกเมื่ออัปโหลดรูปภาพเสร็จสมบูรณ์ ข้อความใหม่ควรปรากฏใน UI ของ Emulator Suite ด้วย โดยเฉพาะอย่างยิ่งเป็นออบเจ็กต์ในแท็บ Realtime Database และเป็น Blob ในแท็บ Storage

9. ยินดีด้วย

คุณเพิ่งสร้างแอปพลิเคชันแชทเรียลไทม์โดยใช้ Firebase

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

  • การตรวจสอบสิทธิ์ Firebase
  • ฐานข้อมูลเรียลไทม์ของ Firebase
  • Cloud Storage for Firebase

จากนั้นลองใช้สิ่งที่ได้เรียนรู้ใน Codelab นี้เพื่อเพิ่ม Firebase ลงในแอป Android ของคุณเอง ดูข้อมูลเพิ่มเติมเกี่ยวกับ Firebase ได้ที่ firebase.google.com

หากต้องการดูวิธีตั้งค่าโปรเจ็กต์ Firebase จริงและใช้ทรัพยากร Firebase จริง (แทนโปรเจ็กต์สาธิตและทรัพยากรจำลองเท่านั้น) ให้ไปที่ขั้นตอนถัดไป

หมายเหตุ: แม้หลังจากตั้งค่าโปรเจ็กต์ Firebase จริงและโดยเฉพาะเมื่อเริ่มสร้างแอปจริง เราขอแนะนําให้ใช้ Firebase Local Emulator Suite ในการพัฒนาและทดสอบ

10. ไม่บังคับ: สร้างและตั้งค่าโปรเจ็กต์ Firebase

ในขั้นตอนนี้ คุณจะสร้างโปรเจ็กต์ Firebase จริงและแอป Android ของ Firebase เพื่อใช้กับ Codelab นี้ นอกจากนี้ คุณยังจะเพิ่มการกำหนดค่า Firebase เฉพาะแอปไปยังแอปด้วย และสุดท้าย คุณจะตั้งค่าทรัพยากร Firebase จริงเพื่อใช้กับแอป

สร้างโปรเจ็กต์ Firebase

  1. ลงชื่อเข้าใช้คอนโซล Firebase โดยใช้บัญชี Google
  2. คลิกปุ่มเพื่อสร้างโปรเจ็กต์ใหม่ แล้วป้อนชื่อโปรเจ็กต์ (เช่น FriendlyChat)
  3. คลิกต่อไป
  4. หากได้รับแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase แล้วคลิกต่อไป
  5. (ไม่บังคับ) เปิดใช้ความช่วยเหลือจาก AI ในคอนโซล Firebase (เรียกว่า "Gemini ใน Firebase")
  6. สำหรับ Codelab นี้ คุณไม่จำเป็นต้องใช้ Google Analytics ดังนั้นให้ปิดตัวเลือก Google Analytics
  7. คลิกสร้างโปรเจ็กต์ รอให้ระบบจัดสรรโปรเจ็กต์ แล้วคลิกดำเนินการต่อ

อัปเกรดแพ็กเกจราคาของ Firebase

หากต้องการใช้ Cloud Storage สำหรับ Firebase โปรเจ็กต์ Firebase ของคุณต้องอยู่ในแพ็กเกจราคาแบบจ่ายเมื่อใช้ (Blaze) ซึ่งหมายความว่าโปรเจ็กต์ดังกล่าวลิงก์กับบัญชีการเรียกเก็บเงินในระบบคลาวด์

หากต้องการอัปเกรดโปรเจ็กต์เป็นแพ็กเกจ Blaze ให้ทำตามขั้นตอนต่อไปนี้

  1. ในคอนโซล Firebase ให้เลือกอัปเกรดแพ็กเกจ
  2. เลือกแพ็กเกจ Blaze ทำตามวิธีการบนหน้าจอเพื่อลิงก์บัญชีสำหรับการเรียกเก็บเงินใน Cloud กับโปรเจ็กต์
    หากคุณต้องสร้างบัญชีสำหรับการเรียกเก็บเงินใน Cloud เป็นส่วนหนึ่งของการอัปเกรดนี้ คุณอาจต้องกลับไปที่ขั้นตอนการอัปเกรดใน Firebase Console เพื่อทำการอัปเกรดให้เสร็จสมบูรณ์

เพิ่ม Firebase ไปยังโปรเจ็กต์ Android

ก่อนที่จะเริ่มขั้นตอนนี้ ให้รับแฮช SHA1 ของแอป เรียกใช้คำสั่งต่อไปนี้จากไดเรกทอรี build-android-start ในเครื่องเพื่อกำหนด SHA1 ของคีย์การแก้ไขข้อบกพร่อง

./gradlew signingReport

Store: /Users/<username>/.android/debug.keystore
Alias: AndroidDebugKey
MD5: A5:88:41:04:8F:06:59:6A:AE:33:76:87:AA:AD:19:23
SHA1: A7:89:F5:06:A8:07:A1:22:EC:90:6A:A6:EA:C3:D4:8B:3A:30:AB:18
SHA-256: 05:A2:2A:35:EE:F2:51:23:72:4D:72:67:A5:6A:8A:58:22:2C:00:A6:AB:F6:45:D5:A1:82:D8:90:A4:69:C8:FE
Valid until: Wednesday, August 10, 2044

คุณควรเห็นเอาต์พุตบางอย่างเช่นด้านบน บรรทัดที่สำคัญคือSHA1แฮช หากค้นหาแฮช SHA1 ไม่พบ โปรดดูข้อมูลเพิ่มเติมในหน้านี้

กลับไปที่คอนโซล Firebase แล้วทำตามขั้นตอนต่อไปนี้เพื่อลงทะเบียนโปรเจ็กต์ Android กับโปรเจ็กต์ Firebase

  1. จากหน้าจอภาพรวมของโปรเจ็กต์ใหม่ ให้คลิกไอคอน Android เพื่อเปิดเวิร์กโฟลว์การตั้งค่า เพิ่มแอป Android
  2. ในหน้าจอถัดไป ให้ป้อน com.google.firebase.codelab.friendlychat เป็นชื่อแพ็กเกจของแอป
  3. คลิกลงทะเบียนแอป แล้วคลิกดาวน์โหลด google-services.json เพื่อดาวน์โหลดไฟล์การกำหนดค่า Firebase
  4. คัดลอกไฟล์ google-services.json ไปยังไดเรกทอรี app ของโปรเจ็กต์ Android
  5. ข้ามขั้นตอนถัดไปที่แสดงในเวิร์กโฟลว์การตั้งค่าของคอนโซล (ระบบได้ดำเนินการให้คุณแล้วในโปรเจ็กต์ build-android-start)
  6. ตรวจสอบว่าแอปมีทรัพยากร Dependency ทั้งหมดโดยซิงค์โปรเจ็กต์กับไฟล์ Gradle จากแถบเครื่องมือของ Android Studio ให้เลือก File > Sync Project with Gradle Files นอกจากนี้ คุณอาจต้องเรียกใช้สร้าง/ล้างโปรเจ็กต์และสร้าง/สร้างโปรเจ็กต์ใหม่เพื่อให้การเปลี่ยนแปลงการกำหนดค่ามีผล

กำหนดค่าการตรวจสอบสิทธิ์ Firebase

ก่อนที่แอปจะเข้าถึง Firebase Authentication API ในนามของผู้ใช้ได้ คุณต้องเปิดใช้ Firebase Authentication และผู้ให้บริการลงชื่อเข้าใช้ที่ต้องการใช้ในแอป

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

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

ตั้งค่า Realtime Database

แอปในโค้ดแล็บนี้จะจัดเก็บข้อความแชทในฐานข้อมูลเรียลไทม์ของ Firebase ในส่วนนี้ เราจะสร้างฐานข้อมูลและกำหนดค่าความปลอดภัยผ่านภาษาการกำหนดค่า JSON ที่เรียกว่ากฎความปลอดภัยของ Firebase

  1. ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือก Realtime Database
  2. คลิกสร้างฐานข้อมูล
  3. เลือกตำแหน่งสำหรับฐานข้อมูล แล้วคลิกถัดไป
    สำหรับแอปจริง คุณควรเลือกตำแหน่งที่อยู่ใกล้กับผู้ใช้
  4. คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
    ในขั้นตอนถัดไปของ Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล อย่าเผยแพร่หรือเปิดเผยแอปต่อสาธารณะโดยไม่ได้เพิ่มกฎความปลอดภัยสำหรับฐานข้อมูล
  5. คลิกสร้าง
  6. เมื่อสร้างอินสแตนซ์ฐานข้อมูลแล้ว ให้เลือกแท็บกฎ จากนั้นอัปเดตการกำหนดค่ากฎด้วยข้อมูลต่อไปนี้
     {
       "rules": {
         "messages": {
           ".read": "auth.uid != null",
           ".write": "auth.uid != null"
         }
       }
     }
    

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของกฎความปลอดภัย (รวมถึงเอกสารประกอบเกี่ยวกับตัวแปร "auth") ได้ที่เอกสารประกอบด้านความปลอดภัยของ Realtime Database

ตั้งค่า Cloud Storage for Firebase

  1. ในแผงด้านซ้ายของคอนโซล Firebase ให้ขยายสร้าง แล้วเลือก Storage
  2. คลิกเริ่มต้นใช้งาน
  3. เลือกตำแหน่งสำหรับที่เก็บข้อมูลเริ่มต้น
    ที่เก็บข้อมูลใน US-WEST1, US-CENTRAL1 และ US-EAST1 จะใช้ประโยชน์จากระดับ"ใช้งานฟรีเสมอ" สำหรับ Google Cloud Storage ได้ ที่เก็บข้อมูลในตำแหน่งอื่นๆ ทั้งหมดจะเป็นไปตามราคาและการใช้งาน Google Cloud Storage
  4. คลิกเริ่มในโหมดทดสอบ อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัย
    ในภายหลังใน Codelab นี้ คุณจะเพิ่มกฎความปลอดภัยเพื่อรักษาความปลอดภัยของข้อมูล อย่าเผยแพร่หรือแสดงแอปต่อสาธารณะโดยไม่ได้เพิ่มกฎความปลอดภัยสำหรับที่เก็บข้อมูล
  5. คลิกสร้าง

เชื่อมต่อกับทรัพยากร Firebase

ในขั้นตอนก่อนหน้าของโค้ดแล็บนี้ คุณได้เพิ่มรายการต่อไปนี้ลงใน MainActivity.kt บล็อกแบบมีเงื่อนไขนี้เชื่อมต่อโปรเจ็กต์ Android กับ Firebase Emulator Suite

// REMOVE OR DISABLE THIS
if (BuildConfig.DEBUG) {
    Firebase.database.useEmulator("10.0.2.2", 9000)
    Firebase.auth.useEmulator("10.0.2.2", 9099)
    Firebase.storage.useEmulator("10.0.2.2", 9199)
}

หากต้องการเชื่อมต่อแอปกับโปรเจ็กต์ Firebase จริงใหม่และทรัพยากร Firebase จริงของโปรเจ็กต์ คุณสามารถนำบล็อกนี้ออกหรือเรียกใช้แอปในโหมดรีลีสเพื่อให้ BuildConfig.DEBUG เป็น false