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

1. ภาพรวม

ภาพหน้าจอ

รูปภาพ: แอป Chat ที่เหมาะสำหรับการทำงาน

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

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

  • วิธีใช้การตรวจสอบสิทธิ์ Firebase เพื่ออนุญาตให้ผู้ใช้ลงชื่อเข้าใช้
  • วิธีซิงค์ข้อมูลโดยใช้ฐานข้อมูลเรียลไทม์ของ Firebase
  • วิธีจัดเก็บไฟล์ไบนารีใน Cloud Storage for Firebase
  • วิธีใช้ชุดโปรแกรมจำลองภายในของ Firebase เพื่อพัฒนาแอป 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

ในโค้ดแล็บนี้ เราได้เพิ่มการพึ่งพาทั้งหมดที่จําเป็นไว้ให้คุณแล้ว แต่คุณก็ควรทําความเข้าใจวิธีเพิ่ม 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 ทำงานต่อไปสำหรับ Codelab ที่เหลือ

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

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

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

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

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

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

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

ตอนนี้คุณควรมีข้อความ 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 ด้วยโค้ดที่กำหนดไว้ด้านล่าง โค้ดนี้จะเพิ่มข้อความที่มีอยู่ทั้งหมดจาก Realtime Database จากนั้นจะรอรายการย่อยใหม่ในเส้นทาง messages ใน Firebase Realtime Database ซึ่งจะเพิ่มองค์ประกอบใหม่ลงใน 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 ของชุดโปรแกรมจำลอง ให้กลับไปที่แท็บ Realtime Database แล้วเพิ่มข้อความใหม่ด้วยตนเอง ตรวจสอบว่าข้อความปรากฏในแอป Android ดังนี้

ยินดีด้วย คุณเพิ่งเพิ่มฐานข้อมูลแบบเรียลไทม์ลงในแอป

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

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

ในส่วนนี้ คุณจะเพิ่มความสามารถสำหรับผู้ใช้แอปที่จะส่งข้อความได้ ข้อมูลโค้ดด้านล่างจะรอรับเหตุการณ์คลิกบนปุ่ม "ส่ง" สร้างออบเจ็กต์ 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 สำหรับ Firebase เพื่อเพิ่มรูปภาพ Cloud Storage เป็นที่ที่ดีในการจัดเก็บข้อมูลไบนารีของแอป

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

เมื่อผู้ใช้เลือกรูปภาพแล้ว ระบบจะเปิดการเลือกรูปภาพ Intent วิธีนี้มีการติดตั้งใช้งานในโค้ดที่ส่วนท้ายของเมธอด onCreate() แล้ว เมื่อเสร็จแล้ว ระบบจะเรียกใช้เมธอด onImageSelected() ของ MainActivity เมื่อใช้ข้อมูลโค้ดด้านล่าง คุณจะเขียนข้อความที่มี 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 ให้คลิกปุ่ม ดำเนินการRun
  2. ใน Android Emulator ให้ป้อนข้อความ แล้วแตะปุ่มส่ง ข้อความใหม่ควรแสดงใน UI ของแอปและใน UI ของ Firebase Emulator Suite
  3. ในโปรแกรมจำลอง Android ให้แตะรูปภาพ "+" เพื่อเลือกรูปภาพจากอุปกรณ์ของคุณ ข้อความใหม่ควรแสดงพร้อมรูปภาพตัวยึดตำแหน่งก่อน ตามด้วยรูปภาพที่เลือกเมื่ออัปโหลดรูปภาพเสร็จสมบูรณ์แล้ว ข้อความใหม่ควรปรากฏใน UI ของชุดโปรแกรมจำลองด้วย โดยเฉพาะอย่างยิ่งในฐานะออบเจ็กต์ในแท็บฐานข้อมูลเรียลไทม์ และในฐานะ Blob ในแท็บพื้นที่เก็บข้อมูล

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 จริงและแอป Firebase บน Android เพื่อใช้กับ Codelab นี้ นอกจากนี้ คุณยังเพิ่มการกําหนดค่า Firebase สําหรับแอปโดยเฉพาะลงในแอปด้วย และสุดท้าย คุณจะต้องตั้งค่าทรัพยากร Firebase จริงเพื่อใช้กับแอป

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

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

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

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

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

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

เพิ่ม 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 ให้เลือกไฟล์ > ซิงค์โปรเจ็กต์กับไฟล์ Gradle นอกจากนี้ คุณอาจต้องเรียกใช้สร้าง/ล้างโปรเจ็กต์และสร้าง/สร้างโครงการใหม่เพื่อให้การเปลี่ยนแปลงการกำหนดค่าเกิดขึ้น

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

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

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

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

ตั้งค่า Realtime Database

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

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

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

ตั้งค่า Cloud Storage for Firebase

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

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

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

// 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 ก็ได้