Lớp học lập trình Android Firebase – Xây dựng Chat thân thiện

1. Tổng quan

ảnh chụp màn hình

Hình ảnh: Ứng dụng Chat thân thiện với hoạt động.

Chào mừng bạn đến với lớp học lập trình thân thiện về Chat. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng nền tảng Firebase để tạo một ứng dụng trò chuyện trên Android.

Kiến thức bạn sẽ học được

  • Cách sử dụng tính năng Xác thực Firebase để cho phép người dùng đăng nhập.
  • Cách đồng bộ hoá dữ liệu bằng Cơ sở dữ liệu theo thời gian thực của Firebase.
  • Cách lưu trữ tệp nhị phân trong Cloud Storage cho Firebase.
  • Cách sử dụng Bộ công cụ mô phỏng cục bộ của Firebase để phát triển ứng dụng Android bằng Firebase.

Bạn cần có

  • Phiên bản Android Studio mới nhất.
  • Trình mô phỏng Android với Android 5.0 trở lên.
  • Node.js phiên bản 10 trở lên (để sử dụng Bộ mô phỏng).
  • Java 8 trở lên. Để cài đặt Java, hãy sử dụng các hướng dẫn sau; để kiểm tra phiên bản của bạn, hãy chạy java -version.
  • Làm quen với ngôn ngữ lập trình Kotlin.

2. Nhận mã mẫu

Sao chép kho lưu trữ

Sao chép kho lưu trữ GitHub từ dòng lệnh:

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

Nhập vào Android Studio

Trong Android Studio, chọn File (Tệp) > Mở, sau đó chọn thư mục build-android-start ( thư mục_android_studio) trong thư mục bạn đã tải mã mẫu xuống.

Bây giờ, bạn sẽ mở dự án build-android-start trong Android Studio. Đừng lo nếu bạn thấy cảnh báo về việc thiếu tệp google-services.json. Mã này sẽ được bổ sung ở bước sau.

Kiểm tra phần phụ thuộc

Trong lớp học lập trình này, tất cả phần phụ thuộc cần thiết đã được thêm vào cho bạn, nhưng điều quan trọng là bạn phải hiểu cách thêm Firebase SDK vào ứng dụng của mình:

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. Cài đặt Firebase CLI

Trong lớp học lập trình này, bạn sẽ sử dụng Bộ mô phỏng Firebase để mô phỏng cục bộ tính năng Xác thực Firebase, Cơ sở dữ liệu theo thời gian thực và Cloud Storage. Việc này mang đến một môi trường phát triển tại địa phương an toàn, nhanh chóng và miễn phí để tạo ứng dụng.

Cài đặt Firebase CLI

Trước tiên, bạn sẽ cần cài đặt Firebase CLI. Nếu đang sử dụng macOS hoặc Linux, bạn có thể chạy lệnh cURL sau:

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

Nếu bạn đang sử dụng Windows, hãy đọc hướng dẫn cài đặt để tải tệp nhị phân độc lập hoặc cài đặt qua npm.

Sau khi bạn cài đặt CLI, việc chạy firebase --version sẽ báo cáo phiên bản 9.0.0 trở lên:

$ firebase --version
9.0.0

Đăng nhập

Chạy firebase login để kết nối giao diện dòng lệnh (CLI) với Tài khoản Google của bạn. Một cửa sổ trình duyệt mới sẽ mở ra để hoàn tất quá trình đăng nhập. Hãy nhớ chọn chính tài khoản mà bạn đã dùng khi tạo dự án Firebase trước đó.

4. Kết nối với Bộ mô phỏng Firebase

Khởi động trình mô phỏng

Trong dòng lệnh, hãy chạy lệnh sau từ gốc của thư mục codelab-friendlychat-android cục bộ:

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

Bạn sẽ thấy một số nhật ký như thế này. Các giá trị cổng được xác định trong tệp firebase.json, có trong mã mẫu đã sao chép.

$ 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.

Chuyển đến http://localhost:4000 trong trình duyệt web của bạn để xem giao diện người dùng của Bộ mô phỏng Firebase:

Trang chủ giao diện người dùng của Bộ công cụ mô phỏng

Tiếp tục chạy lệnh emulators:start trong phần còn lại của lớp học lập trình.

Kết nối ứng dụng

Trong Android Studio, hãy mở MainActivity.kt, sau đó thêm mã sau vào phương thức 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. Chạy ứng dụng khởi đầu

Thêm tệp google-services.json

Để ứng dụng Android của bạn kết nối được với Firebase, bạn phải thêm tệp google-services.json vào thư mục app của dự án Android. Nhằm phục vụ mục đích của lớp học lập trình này, chúng tôi đã cung cấp một tệp JSON mô phỏng cho phép bạn kết nối với Bộ công cụ mô phỏng Firebase.

Sao chép tệp mock-google-services.json vào thư mục build-android-start/app dưới dạng google-services.json:

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

Trong bước cuối cùng của lớp học lập trình này, bạn sẽ tìm hiểu cách tạo một dự án Firebase thực tế và Ứng dụng Android Firebase để có thể thay thế tệp JSON mô phỏng này bằng cấu hình của riêng bạn.

Chạy ứng dụng

Sau khi nhập dự án vào Android Studio và thêm tệp JSON cấu hình Firebase, bạn có thể chạy ứng dụng này lần đầu tiên.

  1. Khởi động Trình mô phỏng Android.
  2. Trong Android Studio, hãy nhấp vào biểu tượng Chạy ( thực hiện) trên thanh công cụ.

Ứng dụng phải chạy trên Trình mô phỏng Android. Lúc này, bạn sẽ thấy một danh sách thư trống. Đồng thời, tính năng gửi và nhận tin nhắn sẽ không hoạt động. Trong bước tiếp theo của lớp học lập trình này, bạn sẽ xác thực người dùng để họ có thể sử dụng tính năng Trò chuyện thân thiện.

6. Bật tính năng xác thực

Ứng dụng này sẽ sử dụng Cơ sở dữ liệu theo thời gian thực của Firebase để lưu trữ tất cả tin nhắn trò chuyện. Tuy nhiên, trước khi thêm dữ liệu, chúng ta phải đảm bảo rằng ứng dụng được bảo mật và chỉ người dùng đã xác thực mới có thể đăng thông báo. Trong bước này, chúng ta sẽ bật tính năng Xác thực Firebase và định cấu hình các Quy tắc bảo mật cơ sở dữ liệu theo thời gian thực.

Thêm chức năng đăng nhập cơ bản

Tiếp theo, chúng ta sẽ thêm một số mã Xác thực Firebase cơ bản vào ứng dụng để phát hiện người dùng và triển khai màn hình đăng nhập.

Kiểm tra người dùng hiện tại

Trước tiên, hãy thêm biến thực thể sau vào lớp MainActivity.kt:

MainActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

Bây giờ, hãy sửa đổi MainActivity để đưa người dùng đến màn hình đăng nhập mỗi khi họ mở ứng dụng và chưa được xác thực. Thêm đoạn mã sau vào phương thức onCreate() sau khi binding được đính kèm vào thành phần hiển thị:

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
}

Chúng ta cũng muốn kiểm tra xem người dùng có đăng nhập trong onStart() không:

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
    }
}

Sau đó, hãy triển khai các phương thức getUserPhotoUrl()getUserName() để trả về thông tin thích hợp về người dùng Firebase hiện đã được xác thực:

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
}

Sau đó, hãy triển khai phương thức signOut() để xử lý nút đăng xuất:

MainActivity.kt

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

Bây giờ, chúng ta đã có sẵn tất cả logic để đưa người dùng đến màn hình đăng nhập khi cần. Tiếp theo, chúng ta cần triển khai màn hình đăng nhập để xác thực người dùng đúng cách.

Triển khai màn hình Đăng nhập

Mở tệp SignInActivity.kt. Ở đây, một nút Đăng nhập đơn giản được sử dụng để bắt đầu xác thực. Trong phần này, bạn sẽ sử dụng FirebaseUI để triển khai logic đăng nhập.

Thêm một biến thực thể Xác thực trong lớp SignInActivity trong nhận xét // Firebase instance variables:

SignInActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

Sau đó, hãy chỉnh sửa phương thức onCreate() để khởi chạy Firebase theo cách tương tự như bạn đã làm trong MainActivity:

SignInActivity.kt

// Initialize FirebaseAuth
auth = Firebase.auth

Thêm trường ActivityResultLauncher vào SignInActivity:

SignInActivity.kt

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

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

Tiếp theo, hãy chỉnh sửa phương thức onStart() để bắt đầu quy trình đăng nhập vào 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()
    }
}

Tiếp theo, hãy triển khai phương thức onSignInResult để xử lý kết quả đăng nhập. Nếu kết quả đăng nhập thành công, hãy tiếp tục truy cập 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)
        }
    }
}

Tất cả chỉ có thế! Bạn đã triển khai tính năng xác thực bằng FirebaseUI chỉ trong một vài lệnh gọi phương thức và không cần quản lý cấu hình phía máy chủ nào.

Kiểm thử thành phẩm

Chạy ứng dụng trên Trình mô phỏng Android. Bạn sẽ được chuyển ngay đến màn hình đăng nhập. Nhấn vào nút Đăng nhập bằng email, sau đó tạo tài khoản. Nếu mọi thứ được triển khai chính xác, bạn sẽ được chuyển đến màn hình thông báo.

Sau khi đăng nhập, hãy mở giao diện người dùng Bộ mô phỏng Firebase trong trình duyệt, sau đó nhấp vào thẻ Xác thực để xem tài khoản người dùng đăng nhập đầu tiên này.

7. Đọc tin nhắn

Ở bước này, chúng ta sẽ thêm chức năng đọc và hiển thị thông báo được lưu trữ trong Cơ sở dữ liệu theo thời gian thực.

Nhập thông báo mẫu

  1. Trong giao diện người dùng Bộ mô phỏng Firebase, hãy chọn thẻ Cơ sở dữ liệu theo thời gian thực.
  2. Kéo và thả tệp initial_messages.json từ bản sao cục bộ của kho lưu trữ của lớp học lập trình vào trình xem dữ liệu.

Bây giờ, bạn sẽ có một số thông báo trong nút messages của cơ sở dữ liệu.

Đọc dữ liệu

Đồng bộ hoá thư

Trong phần này, chúng ta thêm mã để đồng bộ hoá các thông báo mới được thêm vào giao diện người dùng của ứng dụng bằng cách:

  • Khởi chạy Cơ sở dữ liệu theo thời gian thực của Firebase và thêm trình nghe để xử lý các thay đổi đối với dữ liệu.
  • Cập nhật bộ chuyển đổi RecyclerView để hiển thị các thông báo mới.
  • Thêm các biến thực thể Database với các biến thực thể Firebase khác của bạn trong lớp MainActivity:

MainActivity.kt

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

Sửa đổi phương thức onCreate() của MainActivity trong nhận xét // Initialize Realtime Database and FirebaseRecyclerAdapter bằng đoạn mã được xác định bên dưới. Mã này sẽ thêm tất cả thông báo hiện có từ Cơ sở dữ liệu theo thời gian thực, sau đó theo dõi các mục nhập con mới theo đường dẫn messages trong Cơ sở dữ liệu theo thời gian thực của Firebase. Thêm thành phần mới vào giao diện người dùng cho mỗi thông báo:

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)
)

Tiếp theo, trong lớp FriendlyMessageAdapter.kt, hãy triển khai phương thức bind() bên trong lớp MessageViewHolder() bên trong:

BodyMessageAdapter.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)
        }
    }
    ...
}

Chúng ta cũng cần hiển thị các thông báo là hình ảnh, vì vậy, bạn cũng cần triển khai phương thức bind() bên trong lớp ImageMessageViewHolder() bên trong:

BodyMessageAdapter.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)
        }
    }
}

Cuối cùng, hãy quay lại MainActivity, hãy bắt đầu và dừng theo dõi thông tin cập nhật từ Cơ sở dữ liệu theo thời gian thực của Firebase. Cập nhật các phương thức onPause()onResume() trong MainActivity như minh hoạ dưới đây:

MainActivity.kt

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

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

Kiểm thử quá trình đồng bộ hoá thông báo

  1. Nhấp vào biểu tượng Chạy ( thực hiện).
  2. Trong giao diện người dùng của Trình mô phỏng, hãy quay lại thẻ Cơ sở dữ liệu theo thời gian thực, sau đó thêm một thông báo mới theo cách thủ công. Kiểm tra để đảm bảo thông báo xuất hiện trong ứng dụng Android của bạn:

Xin chúc mừng! Bạn vừa thêm một cơ sở dữ liệu theo thời gian thực vào ứng dụng của mình!

8. Gửi tin nhắn

Triển khai tính năng gửi tin nhắn văn bản

Trong phần này, bạn sẽ thêm tính năng cho phép người dùng ứng dụng gửi tin nhắn văn bản. Đoạn mã dưới đây theo dõi các sự kiện nhấp chuột trên nút gửi, tạo một đối tượng FriendlyMessage mới có nội dung của trường tin nhắn và đẩy thông báo đó đến cơ sở dữ liệu. Phương thức push() sẽ thêm một mã nhận dạng được tạo tự động vào đường dẫn của đối tượng được đẩy. Các mã này có tính tuần tự để đảm bảo rằng các thư mới sẽ được thêm vào cuối danh sách.

Cập nhật trình nghe lượt nhấp của nút gửi trong phương thức onCreate() trong lớp MainActivity. Mã này đã nằm ở cuối phương thức onCreate(). Cập nhật nội dung onClick() để khớp với mã dưới đây:

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("")
}

Triển khai tính năng gửi tin nhắn hình ảnh

Trong phần này, bạn sẽ thêm khả năng cho phép người dùng ứng dụng gửi tin nhắn hình ảnh. Bạn có thể tạo thông báo bằng hình ảnh qua các bước sau:

  • Chọn hình ảnh
  • Xử lý lựa chọn hình ảnh
  • Ghi thông báo hình ảnh tạm thời vào Cơ sở dữ liệu theo thời gian thực
  • Bắt đầu tải hình ảnh đã chọn lên
  • Cập nhật URL của tin nhắn hình ảnh thành URL của hình ảnh đã tải lên, sau khi quá trình tải lên hoàn tất

Chọn hình ảnh

Để thêm hình ảnh, lớp học lập trình này sẽ sử dụng Cloud Storage cho Firebase. Cloud Storage là nơi phù hợp để lưu trữ dữ liệu nhị phân của ứng dụng.

Xử lý lựa chọn hình ảnh và viết thông báo tạm thời

Sau khi người dùng chọn một hình ảnh, lựa chọn hình ảnh Intent sẽ được bắt đầu. Việc này đã được triển khai trong mã ở cuối phương thức onCreate(). Khi hoàn tất, phương thức này sẽ gọi phương thức onImageSelected() của MainActivity. Bằng cách sử dụng đoạn mã dưới đây, bạn sẽ viết một thông báo kèm theo URL hình ảnh tạm thời tới cơ sở dữ liệu cho biết hình ảnh đang được tải lên.

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)
                    })
}

Tải hình ảnh lên và thông báo cập nhật

Thêm phương thức putImageInStorage() vào MainActivity. Lệnh này được gọi trong onImageSelected() để bắt đầu quá trình tải hình ảnh đã chọn lên. Sau khi quá trình tải lên hoàn tất, bạn sẽ cập nhật thông báo để sử dụng hình ảnh thích hợp.

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
            )
        }
}

Thử gửi tin nhắn

  1. Trong Android Studio, nhấp vào nút thực hiệnRun (Chạy).
  2. Trong Trình mô phỏng Android, hãy nhập tin nhắn rồi nhấn vào nút gửi. Thông báo mới sẽ xuất hiện trong giao diện người dùng ứng dụng và trong giao diện người dùng Bộ mô phỏng Firebase.
  3. Trong Trình mô phỏng Android, hãy nhấn vào dấu "+" để chọn một bức ảnh từ thiết bị của bạn. Trước tiên, thông báo mới sẽ hiển thị cùng với một hình ảnh giữ chỗ, sau đó hiển thị với hình ảnh được chọn sau khi quá trình tải hình ảnh lên hoàn tất. Thông báo mới cũng phải xuất hiện trong giao diện người dùng của Bộ công cụ mô phỏng, cụ thể là dưới dạng một đối tượng trong thẻ Cơ sở dữ liệu theo thời gian thực và dưới dạng một blob trong thẻ Bộ nhớ.

9. Xin chúc mừng!

Bạn vừa tạo một ứng dụng trò chuyện theo thời gian thực bằng Firebase!

Kiến thức bạn học được

  • Xác thực Firebase
  • Cơ sở dữ liệu theo thời gian thực của Firebase
  • Cloud Storage cho Firebase

Tiếp theo, hãy thử áp dụng những gì bạn đã tìm hiểu được trong lớp học lập trình này để thêm Firebase vào ứng dụng Android của riêng bạn! Để tìm hiểu thêm về Firebase, hãy truy cập vào firebase.google.com.

Nếu bạn muốn tìm hiểu cách thiết lập một dự án Firebase thực và sử dụng các tài nguyên Firebase thực (thay vì dự án minh hoạ và chỉ các tài nguyên được mô phỏng), hãy tiếp tục chuyển sang bước tiếp theo.

Lưu ý: Ngay cả sau khi thiết lập một dự án Firebase thực tế và đặc biệt khi bắt đầu xây dựng một ứng dụng thực tế, bạn nên sử dụng Bộ công cụ mô phỏng cục bộ Firebase để phát triển và kiểm thử.

10. Không bắt buộc: Tạo và thiết lập dự án Firebase

Ở bước này, bạn sẽ tạo một dự án Firebase thực tế và một Ứng dụng Android trên Firebase để sử dụng trong lớp học lập trình này. Bạn cũng sẽ thêm cấu hình Firebase dành riêng cho ứng dụng vào ứng dụng của mình. Cuối cùng, bạn cần thiết lập các tài nguyên Firebase thực để sử dụng với ứng dụng của mình.

Tạo một dự án Firebase

  1. Trong trình duyệt, hãy truy cập vào bảng điều khiển của Firebase.
  2. Chọn Thêm dự án.
  3. Chọn hoặc nhập tên dự án. Bạn có thể sử dụng bất kỳ tên nào bạn muốn.
  4. Bạn không cần sử dụng Google Analytics cho lớp học lập trình này nên có thể bỏ qua bước bật tính năng này cho dự án của mình.
  5. Nhấp vào Create Project (Tạo dự án). Khi dự án của bạn đã sẵn sàng, hãy nhấp vào Tiếp tục.

Thêm Firebase vào dự án Android

Trước khi bắt đầu bước này, hãy lấy hàm băm SHA1 của ứng dụng. Chạy lệnh sau từ thư mục build-android-start cục bộ để xác định SHA1 của khoá gỡ lỗi:

./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

Bạn sẽ thấy một số kết quả như trên. Dòng quan trọng là hàm băm SHA1. Nếu bạn không tìm thấy hàm băm SHA1 của mình, hãy xem trang này để biết thêm thông tin.

Quay lại bảng điều khiển của Firebase và làm theo các bước sau để đăng ký dự án Android với dự án Firebase của bạn:

  1. Trên màn hình tổng quan của dự án mới, hãy nhấp vào biểu tượng Android để bắt đầu quy trình thiết lập: thêm ứng dụng android
  2. Trên màn hình tiếp theo, hãy nhập com.google.firebase.codelab.friendlychat làm tên gói cho ứng dụng.
  3. Nhấp vào Đăng ký ứng dụng, sau đó nhấp vào Tải google-services.json xuống để tải tệp cấu hình Firebase của bạn xuống.
  4. Sao chép tệp google-services.json vào thư mục app của dự án Android.
  5. Bỏ qua các bước tiếp theo hiển thị trong quy trình thiết lập của bảng điều khiển (các bước này đã được thực hiện cho bạn trong dự án build-android-start).
  6. Hãy đảm bảo rằng tất cả các phần phụ thuộc đều có sẵn cho ứng dụng của bạn bằng cách đồng bộ hoá dự án với các tệp Gradle. Trên thanh công cụ Android Studio, chọn File (Tệp) > Đồng bộ hoá dự án với tệp Gradle. Bạn cũng có thể cần chạy Xây dựng/Dọn sạch dự ánTạo/Tạo lại dự án để các thay đổi về cấu hình diễn ra.

Định cấu hình tính năng xác thực Firebase

Trước khi ứng dụng của bạn có thể thay mặt người dùng truy cập vào API xác thực Firebase, bạn cần bật tính năng Xác thực Firebase và nhà cung cấp dịch vụ đăng nhập mà bạn muốn sử dụng trong ứng dụng của mình.

  1. Trong bảng điều khiển của Firebase, hãy chọn mục Xác thực trong bảng điều hướng bên trái.
  2. Chọn thẻ Phương thức đăng nhập.
  3. Nhấp vào Email/Mật khẩu, sau đó gạt nút chuyển sang trạng thái bật (màu xanh dương).
  4. Nhấp vào Google, sau đó gạt nút chuyển sang bật (màu xanh dương) và đặt email hỗ trợ dự án.

Nếu sau này bạn gặp lỗi trong lớp học lập trình này khi thông báo "CONFIGURATION_NOT_FOUND", hãy quay lại bước này và kiểm tra kỹ bài tập của bạn.

Định cấu hình cơ sở dữ liệu theo thời gian thực

Ứng dụng trong lớp học lập trình này lưu trữ tin nhắn trò chuyện trong Cơ sở dữ liệu theo thời gian thực của Firebase. Trong phần này, chúng ta sẽ tạo một cơ sở dữ liệu và định cấu hình tính bảo mật của cơ sở dữ liệu đó thông qua ngôn ngữ cấu hình JSON có tên là Quy tắc bảo mật của Firebase.

  1. Trong bảng điều khiển của Firebase, hãy chọn Cơ sở dữ liệu theo thời gian thực trên bảng điều hướng bên trái.
  2. Nhấp vào Tạo cơ sở dữ liệu để tạo một phiên bản Cơ sở dữ liệu theo thời gian thực mới. Khi được nhắc, hãy chọn khu vực us-central1, sau đó nhấp vào Tiếp theo.
  3. Khi được nhắc về quy tắc bảo mật, hãy chọn chế độ khoá, sau đó nhấp vào Bật.
  4. Sau khi tạo phiên bản thể hiện cơ sở dữ liệu, hãy chọn thẻ Rules (Quy tắc), rồi cập nhật cấu hình quy tắc như sau:
     {
       "rules": {
         "messages": {
           ".read": "auth.uid != null",
           ".write": "auth.uid != null"
         }
       }
     }
    

Để biết thêm thông tin về cách hoạt động của Quy tắc bảo mật (bao gồm cả tài liệu về biến "auth"), hãy xem tài liệu về bảo mật của Cơ sở dữ liệu theo thời gian thực.

Định cấu hình Cloud Storage cho Firebase

  1. Trong bảng điều khiển của Firebase, hãy chọn mục Bộ nhớ trên bảng điều hướng bên trái.
  2. Nhấp vào Bắt đầu để bật Cloud Storage cho dự án của bạn.
  3. Làm theo các bước trong hộp thoại để thiết lập bộ chứa của bạn bằng cách sử dụng các giá trị mặc định được đề xuất.

Kết nối với các tài nguyên của Firebase

Trong một bước trước của lớp học lập trình này, bạn đã thêm nội dung sau đây vào MainActivity.kt. Khối có điều kiện này đã kết nối dự án Android của bạn với Bộ mô phỏng 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)
}

Nếu muốn kết nối ứng dụng của mình với dự án Firebase thực mới và các tài nguyên Firebase thực của dự án đó, bạn có thể xoá khối này hoặc chạy ứng dụng ở chế độ phát hành để BuildConfig.DEBUGfalse.