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

1. ภาพรวม

ภาพหน้าจอ

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

ยินดีต้อนรับสู่ Friendly Chat Codelab ใน 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

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

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

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

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

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. ส่งข้อความ

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

ในส่วนนี้ คุณจะเพิ่มความสามารถในการส่ง 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 ของรูปภาพที่อัปโหลดเมื่ออัปโหลดเสร็จแล้ว

เลือกรูปภาพ

โค้ดแล็บนี้ใช้ Cloud Storage for 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
  3. ในโปรแกรมจำลอง Android ให้แตะรูปภาพ "+" เพื่อเลือกรูปภาพจากอุปกรณ์ ข้อความใหม่ควรปรากฏขึ้นพร้อมกับรูปภาพตัวยึดตําแหน่งก่อน จากนั้นจะแสดงรูปภาพที่เลือกเมื่ออัปโหลดรูปภาพเสร็จสมบูรณ์ ข้อความใหม่ควรปรากฏใน UI ของชุดโปรแกรมจำลองด้วย โดยเฉพาะอย่างยิ่งในฐานะออบเจ็กต์ในแท็บฐานข้อมูลเรียลไทม์และเป็น Blob ในแท็บพื้นที่เก็บข้อมูล

9. ยินดีด้วย

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

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

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

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

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

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

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

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

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

  1. ไปที่คอนโซล Firebase ในเบราว์เซอร์
  2. เลือกเพิ่มโปรเจ็กต์
  3. เลือกหรือป้อนชื่อโปรเจ็กต์ คุณใช้ชื่อใดก็ได้
  4. คุณไม่จำเป็นต้องใช้ 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 จากนั้นสลับสวิตช์เป็นเปิดใช้ (สีน้ำเงิน) และตั้งค่าอีเมลการสนับสนุนโปรเจ็กต์

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

ตั้งค่า Realtime Database

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

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

ในขั้นตอนก่อนหน้าของโค้ดแล็บนี้ คุณได้เพิ่มข้อมูลต่อไปนี้ลงใน 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