Firebase Android Codelab - 친근한 채팅 빌드

1. 개요

스크린샷

이미지: 작동 중인 Friendly Chat 앱

Friendly Chat Codelab에 오신 것을 환영합니다. 이 Codelab에서는 Firebase 플랫폼을 사용하여 Android에서 채팅 앱을 만드는 방법을 알아봅니다.

학습할 내용

  • Firebase 인증을 사용하여 사용자가 로그인할 수 있도록 허용하는 방법
  • Firebase 실시간 데이터베이스를 사용하여 데이터를 동기화하는 방법
  • Firebase용 Cloud Storage에 바이너리 파일을 저장하는 방법
  • Firebase 로컬 에뮬레이터 도구 모음을 사용하여 Firebase로 Android 앱을 개발하는 방법

필요한 사항

  • 최신 Android 스튜디오 버전
  • Android 5.0 이상을 실행하는 Android Emulator
  • Node.js 버전 10 이상 (에뮬레이터 모음 사용)
  • Java 8 이상 Java를 설치하려면 이 안내를 따르세요. 버전을 확인하려면 java -version를 실행하세요.
  • Kotlin 프로그래밍 언어에 관한 지식

2. 샘플 코드 가져오기

저장소 복제

명령줄에서 GitHub 저장소를 클론합니다.

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

Android 스튜디오로 가져오기

Android 스튜디오에서 File > Open을 선택한 다음 샘플 코드를 다운로드한 디렉터리에서 build-android-start 디렉터리 ( android_studio_folder)를 선택합니다.

이제 Android 스튜디오에서 build-android-start 프로젝트가 열려 있어야 합니다. google-services.json 파일이 누락되었다는 경고가 표시되더라도 걱정하지 마세요. 이 값은 이후 단계에서 추가됩니다.

종속 항목 확인

이 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 설치

이 Codelab에서는 Firebase 에뮬레이터 모음을 사용하여 Firebase 인증, 실시간 데이터베이스, 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 에뮬레이터 모음에 연결

에뮬레이터 시작

터미널에서 로컬 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으로 이동하여 Firebase 에뮬레이터 모음 UI를 봅니다.

에뮬레이터 도구 모음 UI 홈

나머지 Codelab에서는 emulators:start 명령어를 실행 상태로 둡니다.

앱 연결

Android 스튜디오에서 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에 연결하려면 Android 프로젝트의 app 폴더 내에 google-services.json 파일을 추가해야 합니다. 이 Codelab에서는 Firebase 에뮬레이터 모음에 연결할 수 있는 모의 JSON 파일을 제공합니다.

mock-google-services.json 파일을 build-android-start/app 폴더에 google-services.json로 복사합니다.

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

이 Codelab의 마지막 단계에서는 이 모의 JSON 파일을 자체 구성으로 대체할 수 있도록 실제 Firebase 프로젝트와 Firebase Android 앱을 만드는 방법을 알아봅니다.

앱 실행

이제 프로젝트를 Android 스튜디오로 가져오고 Firebase 구성 JSON 파일을 추가했으므로 앱을 처음으로 실행할 수 있습니다.

  1. Android Emulator를 시작합니다.
  2. Android 스튜디오에서 툴바의 Run ( execute)을 클릭합니다.

Android Emulator에서 앱이 실행됩니다. 이때 메시지 목록이 비어 있고 메시지를 보내거나 받을 수 없습니다. 이 Codelab의 다음 단계에서는 사용자가 프렌디 채팅을 사용할 수 있도록 사용자를 인증합니다.

6. 인증 사용 설정

이 앱은 Firebase 실시간 데이터베이스를 사용하여 모든 채팅 메시지를 저장합니다. 하지만 데이터를 추가하기 전에 앱이 안전하고 인증된 사용자만 메시지를 게시할 수 있는지 확인해야 합니다. 이 단계에서는 Firebase 인증을 사용 설정하고 실시간 데이터베이스 보안 규칙을 구성합니다.

기본 로그인 기능 추가

다음으로 사용자를 감지하고 로그인 화면을 구현하기 위해 앱에 몇 가지 기본 Firebase 인증 코드를 추가합니다.

현재 사용자 확인

먼저 MainActivity.kt 클래스에 다음 인스턴스 변수를 추가합니다.

MainActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

이제 사용자가 앱을 열고 인증되지 않은 경우 로그인 화면으로 보내도록 MainActivity를 수정해 보겠습니다. binding가 뷰에 연결된 onCreate() 메서드에 다음을 추가합니다.

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를 사용하여 로그인 로직을 구현합니다.

SignInActivity 클래스의 // Firebase instance variables 주석 아래에 Auth 인스턴스 변수를 추가합니다.

SignInActivity.kt

// Firebase instance variables
private lateinit var auth: FirebaseAuth

그런 다음 onCreate() 메서드를 수정하여 MainActivity에서와 동일한 방식으로 Firebase를 초기화합니다.

SignInActivity.kt

// Initialize FirebaseAuth
auth = Firebase.auth

SignInActivityActivityResultLauncher 필드를 추가합니다.

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에서 앱을 실행합니다. 로그인 화면으로 즉시 이동합니다. 이메일로 로그인 버튼을 탭한 다음 계정을 만듭니다. 모든 것이 올바르게 구현되면 메시지 화면으로 이동합니다.

로그인한 후 브라우저에서 Firebase 에뮬레이터 모음 UI를 연 다음 인증 탭을 클릭하여 처음 로그인한 사용자 계정을 확인합니다.

7. 메시지 읽기

이 단계에서는 실시간 데이터베이스에 저장된 메시지를 읽고 표시하는 기능을 추가합니다.

샘플 메시지 가져오기

  1. Firebase 에뮬레이터 도구 모음 UI에서 실시간 데이터베이스 탭을 선택합니다.
  2. codelab 저장소의 로컬 사본에서 initial_messages.json 파일을 데이터 뷰어로 드래그 앤 드롭합니다.

이제 데이터베이스의 messages 노드 아래에 몇 개의 메시지가 표시됩니다.

데이터 읽기

메시지 동기화

이 섹션에서는 다음과 같이 새로 추가된 메시지를 앱 UI에 동기화하는 코드를 추가합니다.

  • Firebase 실시간 데이터베이스를 초기화하고 데이터 변경사항을 처리하는 리스너를 추가합니다.
  • 새 메시지가 표시되도록 RecyclerView 어댑터를 업데이트합니다.
  • MainActivity 클래스에서 다른 Firebase 인스턴스 변수와 함께 Database 인스턴스 변수를 추가합니다.

MainActivity.kt

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

// Initialize Realtime Database and FirebaseRecyclerAdapter 주석 아래에 있는 MainActivity의 onCreate() 메서드를 아래에 정의된 코드로 수정합니다. 이 코드는 실시간 데이터베이스의 기존 메시지를 모두 추가한 다음 Firebase 실시간 데이터베이스의 messages 경로 아래에 있는 새 하위 항목을 리슨합니다. 각 메일의 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 클래스의 내부 클래스 MessageViewHolder() 내에서 bind() 메서드를 구현합니다.

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

이미지인 메시지도 표시해야 하므로 내부 클래스 ImageMessageViewHolder() 내에 bind() 메서드도 구현합니다.

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 실시간 데이터베이스의 업데이트 수신 대기를 시작 및 중지합니다. 아래와 같이 MainActivityonPause()onResume() 메서드를 업데이트합니다.

MainActivity.kt

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

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

메시지 동기화 테스트

  1. Run ( execute)을 클릭합니다.
  2. 에뮬레이터 도구 모음 UI에서 실시간 데이터베이스 탭으로 돌아간 다음 새 메시지를 수동으로 추가합니다. Android 앱에 메시지가 표시되는지 확인합니다.

축하합니다. 앱에 실시간 데이터베이스를 추가했습니다.

8. 메시지 전송

문자 메시지 전송 구현

이 섹션에서는 앱 사용자가 문자 메시지를 보낼 수 있는 기능을 추가합니다. 아래 코드 스니펫은 전송 버튼의 클릭 이벤트를 수신 대기하고 메시지 필드의 콘텐츠로 새 FriendlyMessage 객체를 만든 다음 메시지를 데이터베이스에 푸시합니다. push() 메서드는 푸시된 객체의 경로에 자동으로 생성된 ID를 추가합니다. 이러한 ID는 순차적이므로 새 메시지가 목록 끝에 추가됩니다.

MainActivity 클래스의 onCreate() 메서드에서 전송 버튼의 클릭 리스너를 업데이트합니다. 이 코드는 이미 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("")
}

이미지 메시지 전송 구현

이 섹션에서는 앱 사용자가 이미지 메시지를 보낼 수 있는 기능을 추가합니다. 이미지 메시지를 만들려면 다음 단계를 따르세요.

  • 이미지 선택:
  • 이미지 선택 처리
  • 실시간 데이터베이스에 임시 이미지 메시지 쓰기
  • 선택한 이미지 업로드 시작
  • 업로드가 완료되면 이미지 메시지 URL을 업로드된 이미지의 URL로 업데이트합니다.

이미지 선택

이 Codelab에서는 이미지를 추가하기 위해 Firebase용 Cloud Storage를 사용합니다. Cloud Storage는 앱의 바이너리 데이터를 저장하기에 적합합니다.

이미지 선택을 처리하고 임시 메시지 작성

사용자가 이미지를 선택하면 이미지 선택 Intent이 실행됩니다. 이는 이미 onCreate() 메서드 끝에 있는 코드에 구현되어 있습니다. 완료되면 MainActivityonImageSelected() 메서드를 호출합니다. 아래의 코드 스니펫을 사용하여 이미지가 업로드되고 있음을 나타내는 임시 이미지 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)
                    })
}

이미지 업로드 및 메시지 업데이트

MainActivityputImageInStorage() 메서드를 추가합니다. 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 스튜디오에서 executeRun 버튼을 클릭합니다.
  2. Android Emulator에서 메시지를 입력한 다음 보내기 버튼을 탭합니다. 새 메시지가 앱 UI와 Firebase 에뮬레이터 모음 UI에 표시됩니다.
  3. Android Emulator에서 '+' 이미지를 탭하여 기기에서 이미지를 선택합니다. 새 메시지는 먼저 자리표시자 이미지로 표시되고 이미지 업로드가 완료되면 선택한 이미지로 표시됩니다. 새 메시지는 에뮬레이터 모음 UI에도 표시되어야 합니다. 특히 실시간 데이터베이스 탭의 객체로, 저장소 탭의 블로프로 표시되어야 합니다.

9. 수고하셨습니다.

Firebase를 사용하여 실시간 채팅 애플리케이션을 빌드했습니다.

학습한 내용

  • Firebase 인증
  • Firebase 실시간 데이터베이스
  • Firebase용 Cloud Storage

이제 이 Codelab에서 배운 내용을 사용하여 Firebase를 Android 앱에 추가해 보세요. Firebase에 대해 자세히 알아보려면 firebase.google.com을 참고하세요.

데모 프로젝트 및 에뮬레이션된 리소스 사용하는 대신 실제 Firebase 프로젝트를 설정하고 실제 Firebase 리소스를 사용하는 방법을 알아보려면 다음 단계를 진행하세요.

참고: 실제 Firebase 프로젝트를 설정하고 나서도, 특히 실제 앱 빌드를 시작할 때는 개발 및 테스트에 Firebase 로컬 에뮬레이터 도구 모음을 사용하는 것이 좋습니다.

10. 선택사항: Firebase 프로젝트 만들기 및 설정

이 단계에서는 이 Codelab에서 사용할 실제 Firebase 프로젝트와 Firebase Android 앱을 만듭니다. 또한 앱별 Firebase 구성을 앱에 추가합니다. 마지막으로 앱과 함께 사용할 실제 Firebase 리소스를 설정합니다.

Firebase 프로젝트 만들기

  1. 브라우저에서 Firebase Console로 이동합니다.
  2. 프로젝트 추가를 선택합니다.
  3. 프로젝트 이름을 선택하거나 입력합니다. 원하는 이름을 사용할 수 있습니다.
  4. 이 Codelab에는 Google 애널리틱스가 필요하지 않으므로 프로젝트에 Google 애널리틱스를 사용 설정하지 않아도 됩니다.
  5. 프로젝트 만들기를 클릭합니다. 프로젝트가 준비되면 계속을 클릭합니다.

Firebase 요금제 업그레이드

Firebase용 Cloud Storage를 사용하려면 Firebase 프로젝트가 사용한 만큼만 지불 (Blaze) 요금제를 사용해야 합니다. 즉, Cloud Billing 계정에 연결되어 있어야 합니다.

  • Cloud Billing 계정에는 신용카드와 같은 결제 수단이 필요합니다.
  • Firebase와 Google Cloud를 처음 사용하는 경우 $300 크레딧과 무료 체험판 Cloud Billing 계정을 받을 자격이 되는지 확인하세요.
  • 이벤트의 일환으로 이 Codelab을 진행하는 경우 주최자에게 사용 가능한 Cloud 크레딧이 있는지 문의하세요.

프로젝트를 Blaze 요금제로 업그레이드하려면 다음 단계를 따르세요.

  1. Firebase Console에서 요금제를 업그레이드하도록 선택합니다.
  2. Blaze 요금제를 선택합니다. 화면에 표시된 안내에 따라 Cloud Billing 계정을 프로젝트에 연결합니다.
    이 업그레이드의 일환으로 Cloud Billing 계정을 만들어야 하는 경우 업그레이드를 완료하기 위해 Firebase Console의 업그레이드 흐름으로 돌아가야 할 수 있습니다.

Android 프로젝트에 Firebase 추가

이 단계를 시작하기 전에 앱의 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 Console로 돌아가 다음 단계에 따라 Android 프로젝트를 Firebase 프로젝트에 등록합니다.

  1. 새 프로젝트의 개요 화면에서 Android 아이콘을 클릭하여 설정 워크플로를 시작합니다. Android 앱 추가
  2. 다음 화면에서 앱의 패키지 이름으로 com.google.firebase.codelab.friendlychat를 입력합니다.
  3. 앱 등록을 클릭한 다음 google-services.json 다운로드를 클릭하여 Firebase 구성 파일을 다운로드합니다.
  4. google-services.json 파일을 Android 프로젝트의 app 디렉터리에 복사합니다.
  5. 콘솔의 설정 워크플로에 표시된 다음 단계를 건너뜁니다. build-android-start 프로젝트에서 이미 완료되었습니다.
  6. 프로젝트를 Gradle 파일과 동기화하여 앱에서 모든 종속 항목을 사용할 수 있는지 확인합니다. Android 스튜디오 툴바에서 File > Sync Project with Gradle Files를 선택합니다. 구성 변경사항이 적용되도록 Build/Clean ProjectBuild/Rebuild Project를 실행해야 할 수도 있습니다.

Firebase 인증 구성

앱이 사용자를 대신하여 Firebase 인증 API에 액세스하려면 먼저 Firebase 인증과 앱에서 사용할 로그인 제공업체를 사용 설정해야 합니다.

  1. Firebase Console의 왼쪽 탐색 패널에서 인증을 선택합니다.
  2. 로그인 방법 탭을 선택합니다.
  3. 이메일/비밀번호를 클릭한 다음 스위치를 사용 설정 (파란색)으로 전환합니다.
  4. Google을 클릭한 다음 스위치를 사용 (파란색)으로 전환하고 프로젝트 지원 이메일을 설정합니다.

이 Codelab의 뒷부분에서 'CONFIGURATION_NOT_FOUND' 메시지와 함께 오류가 발생하면 이 단계로 돌아가서 작업을 다시 확인하세요.

실시간 데이터베이스 설정

이 Codelab의 앱은 Firebase 실시간 데이터베이스에 채팅 메시지를 저장합니다. 이 섹션에서는 Firebase 보안 규칙이라는 JSON 구성 언어를 통해 데이터베이스를 만들고 보안을 구성합니다.

  1. Firebase Console의 왼쪽 패널에서 빌드를 펼친 다음 실시간 데이터베이스를 선택합니다.
  2. 데이터베이스 만들기를 클릭합니다.
  3. 데이터베이스의 위치를 선택한 다음 다음을 클릭합니다.
    실제 앱의 경우 사용자와 가까운 위치를 선택해야 합니다.
  4. 테스트 모드로 시작을 클릭합니다. 보안 규칙에 관한 면책 조항을 읽습니다.
    이 Codelab의 다음 단계에서는 데이터를 보호하기 위해 보안 규칙을 추가합니다. 데이터베이스에 대한 보안 규칙을 추가하지 않은 채 앱을 공개적으로 배포하거나 노출하지 마세요.
  5. 만들기를 클릭합니다.
  6. 데이터베이스 인스턴스가 생성되면 규칙 탭을 선택한 다음 다음과 같이 규칙 구성을 업데이트합니다.
     {
       "rules": {
         "messages": {
           ".read": "auth.uid != null",
           ".write": "auth.uid != null"
         }
       }
     }
    

보안 규칙의 작동 방식에 관한 자세한 내용('auth' 변수에 관한 문서 포함)은 실시간 데이터베이스 보안 문서를 참고하세요.

Firebase용 Cloud Storage 설정

  1. Firebase Console의 왼쪽 패널에서 빌드를 펼친 다음 스토리지를 선택합니다.
  2. 시작하기를 클릭합니다.
  3. 기본 Storage 버킷의 위치를 선택합니다.
    US-WEST1, US-CENTRAL1, US-EAST1의 버킷은 Google Cloud Storage의 '항상 무료' 등급을 활용할 수 있습니다. 다른 모든 위치의 버킷은 Google Cloud Storage 가격 책정 및 사용량을 따릅니다.
  4. 테스트 모드로 시작을 클릭합니다. 보안 규칙에 관한 면책 조항을 읽습니다.
    이 Codelab의 후반부에서 데이터를 보호하는 보안 규칙을 추가합니다. 스토리지 버킷에 대한 보안 규칙을 추가하지 않은 채 앱을 공개적으로 배포하거나 노출하지 마세요.
  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.DEBUGfalse가 되도록 출시 모드에서 앱을 실행하면 됩니다.