

# IVS 챗 클라이언트 메시징 SDK: Kotlin 코루틴 자습서 1부: 채팅룸
<a name="chat-sdk-kotlin-tutorial-chat-rooms"></a>

본 문서는 두 파트로 구성된 자습서 중 첫 번째 파트에 해당하는 자습서입니다. [Kotlin](https://kotlinlang.org/) 프로그래밍 언어 및 [코루틴](https://kotlinlang.org/docs/coroutines-overview.html)을 사용하여 완전한 기능을 갖춘 Android 앱을 구축하여 Amazon IVS Chat 메시징 SDK로 작업하기 위한 필수 사항을 알아봅니다. 여기에서 지칭하는 앱은 *Chatterbox*라고 합니다.

모듈을 시작하기 전에 몇 분 정도 시간을 내어 사전 조건, 채팅 토큰의 주요 개념, 채팅룸 생성에 필요한 백엔드 서버를 숙지해 두세요.

이 자습서는 IVS 챗 메시징 SDK를 처음 사용하는 숙련된 Android 개발자를 위해 만들어졌습니다. Kotlin 프로그래밍 언어와 Android 플랫폼에서 UI를 만드는 데 익숙해야 합니다.

이 자습서의 첫 번째 부분은 여러 섹션으로 나뉩니다.

1. [로컬 인증/권한 부여 서버 설정](#chat-kotlin-rooms-auth-server)

1. [Chatterbox 프로젝트 생성](#chat-kotlin-rooms-chatterbox)

1. [채팅룸에 연결 및 연결 업데이트 관찰](#chat-kotlin-rooms-connect)

1. [토큰 공급자 구축](#chat-kotlin-rooms-token-provider)

1. [다음 단계](#chat-kotlin-rooms-next-steps)

전체 SDK 설명서를 보려면 우선 [Amazon IVS Chat Client Messaging SDK](chat-sdk.md)(Amazon IVS Chat 사용 설명서**에서 참조) 및 [Chat Client Messaging: SDK for Android Reference](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/latest/)(GitHub)를 참조하세요.

## 사전 조건
<a name="chat-kotlin-rooms-prerequisites"></a>
+ Kotlin과 Android 플랫폼에서 애플리케이션을 만드는 데 익숙해야 합니다. Android용 애플리케이션을 만드는 데 익숙하지 않은 경우 Android 개발자를 위한 [첫 앱 빌드](https://developer.android.com/codelabs/basic-android-kotlin-compose-first-app#0) 가이드에서 기본 사항을 배워 보세요.
+ [Amazon IVS Chat 시작하기](getting-started-chat.md)를 읽고 이해합니다.
+ 기존 IAM 정책에 정의된 `CreateChatToken` 및 `CreateRoom` 기능을 사용하여 AWS IAM 사용자를 생성합니다. ([Amazon IVS Chat 시작하기](getting-started-chat.md)를 참조하세요.)
+ 이 사용자의 비밀/액세스 키가 AWS 보안 인증 파일에 저장되어 있는지 확인합니다. 지침은 [AWS CLI 사용 설명서](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)(특히 [구성 및 보안 인증 파일 설정](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html))를 참조합니다.
+ 채팅룸을 생성하고 ARN을 저장합니다. [Amazon IVS Chat 시작하기](getting-started-chat.md)을(를) 참조하세요. (ARN을 저장하지 않은 경우 나중에 콘솔이나 Chat API를 사용하여 조회할 수 있습니다.)

## 로컬 인증/권한 부여 서버 설정
<a name="chat-kotlin-rooms-auth-server"></a>

백엔드 서버는 채팅룸을 생성하고 IVS 챗 Android SDK가 채팅룸의 클라이언트를 인증하고 권한을 부여하는 데 필요한 채팅 토큰을 생성하는 일을 맡습니다.

Amazon IVS 채팅 시작하기에서 [채팅 토큰 생성](getting-started-chat-auth.md)을 참조하세요.** 플로우차트에서 볼 수 있듯이 서버 측 코드는 채팅 토큰 생성을 담당합니다 즉, 앱은 서버 측 애플리케이션에서 채팅 토큰을 요청하여 채팅 토큰을 생성하는 자체 수단을 제공해야 합니다.

저희는 [Ktor](https://ktor.io/) 프레임워크를 사용하여 로컬 AWS 환경을 통해 채팅 토큰 생성을 관리하는 라이브 로컬 서버를 생성합니다.

이제 AWS 보안 인증 정보가 올바르게 설정되었을 것입니다. 단계별 지침은 [Set up AWS temporary credentials and AWS Region for development](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html)를 참조하세요.

`chatterbox`라는 새 디렉터리를 생성하고 그 안에서 또 다른 디렉토리 `auth-server`를 생성합니다.**

서버 폴더는 다음과 같은 구조를 갖습니다.

```
- auth-server
  - src
    - main
      - kotlin
        - com
          - chatterbox
            - authserver
              - Application.kt
       - resources
         - application.conf
         - logback.xml
   - build.gradle.kts
```

*참고: 여기에서 코드를 참조된 파일에 직접 복사하거나 붙여넣을 수 있습니다.*

다음으로 인증 서버가 작동하는 데 필요한 모든 종속 항목과 플러그인을 추가합니다.

**Kotlin 스크립트:**

```
// ./auth-server/build.gradle.kts

plugins {
   application
   kotlin("jvm")
   kotlin("plugin.serialization").version("1.7.10")
}

application {   
   mainClass.set("io.ktor.server.netty.EngineMain")
}

dependencies {
   implementation("software.amazon.awssdk:ivschat:2.18.1")
   implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20")

   implementation("io.ktor:ktor-server-core:2.1.3")
   implementation("io.ktor:ktor-server-netty:2.1.3")
   implementation("io.ktor:ktor-server-content-negotiation:2.1.3")
   implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.3")

   implementation("ch.qos.logback:logback-classic:1.4.4")
}
```

이제 인증 서버의 로깅 기능을 설정해야 합니다. (자세한 정보는 [로거 구성](https://ktor.io/docs/logging.html#configure-logger)을 참조하세요.)

**XML:**

```
// ./auth-server/src/main/resources/logback.xml

<configuration>
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
   </appender>
   <root level="trace">
      <appender-ref ref="STDOUT"/>
   </root>
   <logger name="org.eclipse.jetty" level="INFO"/>
   <logger name="io.netty" level="INFO"/>
</configuration>
```

[Ktor](https://ktor.io/docs/welcome.html) 서버에는 `resources` 디렉터리의 `application.*` 파일에서 자동으로 로드되는 구성 설정이 필요하므로 구성 설정도 추가합니다. (자세한 정보는 [파일으로 구성](https://ktor.io/docs/configurations.html#configuration-file)을 참조하세요.)

**HOCON**:

```
// ./auth-server/src/main/resources/application.conf

ktor {
   deployment {
      port = 3000
   }
   application {
      modules = [ com.chatterbox.authserver.ApplicationKt.main ]
   }
}
```

마지막으로 서버를 구현해 보겠습니다.

**Kotlin:**

```
// ./auth-server/src/main/kotlin/com/chatterbox/authserver/Application.kt

package com.chatterbox.authserver

import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import software.amazon.awssdk.services.ivschat.IvschatClient
import software.amazon.awssdk.services.ivschat.model.CreateChatTokenRequest

@Serializable
data class ChatTokenParams(var userId: String, var roomIdentifier: String)

@Serializable
data class ChatToken(
   val token: String,
   val sessionExpirationTime: String,
   val tokenExpirationTime: String,
)

fun Application.main() {
   install(ContentNegotiation) {
      json(Json)
   }

   routing {
      post("/create_chat_token") {
         val callParameters = call.receive<ChatTokenParams>()
         val request = CreateChatTokenRequest.builder().roomIdentifier(callParameters.roomIdentifier)
            .userId(callParameters.userId).build()
         val token = IvschatClient.create()
            .createChatToken(request)

         call.respond(
            ChatToken(
                token.token(),
                token.sessionExpirationTime().toString(),
                token.tokenExpirationTime().toString()
            )
         )
      }
   }
}
```

## Chatterbox 프로젝트 생성
<a name="chat-kotlin-rooms-chatterbox"></a>

Android 프로젝트를 생성하려면 [Android 스튜디오](https://developer.android.com/studio)를 설치하고 엽니다.

공식 Android [프로젝트 생성 가이드](https://developer.android.com/studio/projects/create-project)에 나와 있는 단계를 따릅니다.
+ [프로젝트 선택](https://developer.android.com/studio/projects/create-project)에서 Chatterbox 앱을 위한 **빈 활동** 프로젝트 템플릿을 선택합니다.
+ [프로젝트 구성](https://developer.android.com/studio/projects/create-project#configure)에서 다음 구성 필드 값을 선택합니다.
  + **이름**: My App
  + **패키지 이름**: com.chatterbox.myapp
  + **저장 위치**: 이전 단계에서 만든`chatterbox` 디렉터리를 지정합니다.
  + **언어**: Kotlin
  + **최소 API 레벨**: API 21: Android 5.0(Lollipop)

모든 구성 매개 변수를 올바르게 지정한 후 `chatterbox` 폴더 내의 파일 구조는 다음과 같아야 합니다.

```
- app
  - build.gradle
  ...
- gradle
- .gitignore
- build.gradle
- gradle.properties
- gradlew
- gradlew.bat
- local.properties
- settings.gradle
- auth-server
  - src
    - main
      - kotlin
        - com
          - chatterbox
            - authserver
              - Application.kt
       - resources
         - application.conf
         - logback.xml
   - build.gradle.kts
```

이제 작동하는 안드로이드 프로젝트가 있으므로 `build.gradle` 종속 항목에 [com.amazonaws:ivs-chat-messaging](https://mvnrepository.com/artifact/com.amazonaws/ivs-chat-messaging) 및 [org.jetbrains.kotlinx:kotlinx-coroutines-core](https://github.com/Kotlin/kotlinx.coroutines)를 추가할 수 있습니다. ([Gradle](https://gradle.org/) 빌드 툴킷에 대한 자세한 정보는 [빌드 구성](https://developer.android.com/build)을 참조하세요.) 

**참고:** 모든 코드 조각의 맨 위에는 프로젝트에서 변경해야 하는 파일의 경로가 있습니다. 경로는 프로젝트 루트의 상대 경로입니다.

**Kotlin:**

```
// ./app/build.gradle

plugins {
// ...
}

android {
// ...
}

dependencies {
    implementation 'com.amazonaws:ivs-chat-messaging:1.1.0'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'

// ...
}
```

새 종속 항목이 추가된 후 Android 스튜디오에서 **Gradle 파일과 프로젝트 동기화**를 실행하여 프로젝트를 새 종속 항목과 동기화합니다. (자세한 정보는 [빌드 종속 항목 추가](https://developer.android.com/build/dependencies)를 참조하세요.)

이전 섹션에서 생성한 인증 서버를 프로젝트 루트에서 편리하게 실행하기 위해 이 서버를 `settings.gradle`에 새 모듈로 포함시킵니다. (자세한 정보는 [Gradle을 사용하여 소프트웨어 구성 요소 구조화 및 빌드](https://docs.gradle.org/current/userguide/multi_project_builds.html)를 참조하세요.)

**Kotlin 스크립트:**

```
// ./settings.gradle

// ...

rootProject.name = "My App"
include ':app'
include ':auth-server'
```

이제부터 `auth-server`가 Android 프로젝트에 포함되므로 프로젝트 루트에서 다음 명령으로 인증 서버를 실행할 수 있습니다.

**쉘:**

```
./gradlew :auth-server:run         
```

## 채팅룸에 연결 및 연결 업데이트 관찰
<a name="chat-kotlin-rooms-connect"></a>

채팅룸 연결을 열기 위해 활동이 처음 생성될 때 실행되는 [onCreate() 활동 수명 주기 콜백](https://developer.android.com/guide/components/activities/activity-lifecycle)을 사용합니다. [ChatRoom 생성자](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/-amazon%20-i-v-s%20-chat%20-messaging%20-s-d-k%20for%20-android/com.amazonaws.ivs.chat.messaging/-chat-room/index.html)를 사용하려면 룸 연결을 인스턴스화하기 위해 `region` 및 `tokenProvider`를 제공해야 합니다.

**참고:** 아래 조각의 `fetchChatToken` 함수는 [다음 섹션](#chat-kotlin-rooms-token-provider)에서 구현됩니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp
// ...

// AWS region of the room that was created in Getting Started with Amazon IVS Chat
const val REGION = "us-west-2"

class MainActivity : AppCompatActivity() {
    private var room: ChatRoom? = null
    // ...

   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

      // Create room instance
      room = ChatRoom(REGION, ::fetchChatToken)
   }

// ...
}
```

채팅룸 연결의 변화를 표시하고 대응하는 것은 `chatterbox`와 같은 채팅 앱을 만드는 데 필수적인 부분입니다. 룸과 상호작용을 시작하기 전에 채팅룸 연결 상태 이벤트를 구독하여 업데이트를 받아야 합니다.

코루틴용 챗 SDK에서 [https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/-amazon%20-i-v-s%20-chat%20-messaging%20-s-d-k%20for%20-android/com.amazonaws.ivs.chat.messaging/-chat-room/index.html](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/-amazon%20-i-v-s%20-chat%20-messaging%20-s-d-k%20for%20-android/com.amazonaws.ivs.chat.messaging/-chat-room/index.html)은 [Flow](https://kotlinlang.org/docs/flow.html)에서 룸 수명 주기 이벤트를 처리할 것으로 예상합니다. 현재 함수는 호출 시 확인 메시지만 로그합니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp
// ...

const val TAG = "Chatterbox-MyApp"

class MainActivity : AppCompatActivity() {
// ...

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

        // Create room instance
        room = ChatRoom(REGION, ::fetchChatToken).apply {
            lifecycleScope.launch {
                stateChanges().collect { state ->
                    Log.d(TAG, "state change to $state")
                }
            }

            lifecycleScope.launch {
                receivedMessages().collect { message ->
                    Log.d(TAG, "messageReceived $message")
                }
            }

            lifecycleScope.launch {
                receivedEvents().collect { event ->
                    Log.d(TAG, "eventReceived $event")
                }
            }

            lifecycleScope.launch {
                deletedMessages().collect { event ->
                    Log.d(TAG, "messageDeleted $event")
                }
            }

            lifecycleScope.launch {
                disconnectedUsers().collect { event ->
                    Log.d(TAG, "userDisconnected $event")
                }
            }
        }
    }
}
```

이 다음으로 룸 연결 상태를 읽을 수 있는 기능을 제공해야 합니다. `MainActivity.kt` [속성](https://kotlinlang.org/docs/properties.html)에 이를 보관하고 룸의 기본 DISCONNECTED 상태로 초기화합니다([IVS 챗 Android SDK 참조](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/latest/)의 `ChatRoom` `state` 참조). 로컬 상태를 최신 상태로 유지하려면 state-updater 함수를 구현해야 합니다. 이 함수를 `updateConnectionState`라고 해 보겠습니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp
// ...

class MainActivity : AppCompatActivity() {
   private var connectionState = ChatRoom.State.DISCONNECTED

// ...

   private fun updateConnectionState(state: ChatRoom.State) {
      connectionState = state

     when (state) {
          ChatRoom.State.CONNECTED -> {
              Log.d(TAG, "room connected")
          }
          ChatRoom.State.DISCONNECTED -> {
              Log.d(TAG, "room disconnected")
          }
          ChatRoom.State.CONNECTING -> {
              Log.d(TAG, "room connecting")
          }
      }
}
```

다음으로 state-updater 함수를 [ChatRoom.Listener](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/-amazon%20-i-v-s%20-chat%20-messaging%20-s-d-k%20for%20-android/com.amazonaws.ivs.chat.messaging/-chat-room/listener.html) 속성과 통합합니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp
// ...

class MainActivity : AppCompatActivity() {
// ...

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

        // Create room instance
        room = ChatRoom(REGION, ::fetchChatToken).apply {
            lifecycleScope.launch {
                stateChanges().collect { state ->
                    Log.d(TAG, "state change to $state")
                    updateConnectionState(state)

                }
            }

      // ...

      }
   }
}
```

이제 [ChatRoom](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/-amazon%20-i-v-s%20-chat%20-messaging%20-s-d-k%20for%20-android/com.amazonaws.ivs.chat.messaging/-chat-room/index.html) 상태 업데이트를 저장하고, 듣고, 반응할 수 있게 되었으므로 연결을 초기화할 차례입니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp
// ...

class MainActivity : AppCompatActivity() {
// ...

   private fun connect() {
      try {
         room?.connect()
      } catch (ex: Exception) {
         Log.e(TAG, "Error while calling connect()", ex)
      }
   }

   // ...
}
```

## 토큰 공급자 구축
<a name="chat-kotlin-rooms-token-provider"></a>

이제 애플리케이션에서 채팅 토큰을 생성하고 관리하는 함수를 만들 차례입니다. 이 예에서는 [Android용 Retrofit HTTP 클라이언트](https://square.github.io/retrofit/)를 사용합니다.

네트워크 트래픽을 보내려면 먼저 Android용 네트워크 보안 구성을 설정해야 합니다. (자세한 정보는 [네트워크 보안 구성](https://developer.android.com/privacy-and-security/security-config)을 참조하세요.) [앱 매니페스트](https://developer.android.com/guide/topics/manifest/manifest-intro) 파일에 네트워크 권한을 추가하는 것부터 시작합니다. 새로운 네트워크 보안 구성을 가리키는 추가된 `user-permission` 태그와 `networkSecurityConfig` 속성에 유의하세요. 아래 코드에서 `<version>`을 챗 Android SDK의 현재 버전 번호(예: 1.1.0)로 대체하세요.****

**XML:**

```
// ./app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.chatterbox.myapp">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:fullBackupContent="@xml/backup_rules"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
// ...

// ./app/build.gradle


dependencies {
   implementation("com.amazonaws:ivs-chat-messaging:<version>")
// ...

   implementation("com.squareup.retrofit2:retrofit:2.9.0")
   implementation("com.squareup.retrofit2:converter-gson:2.9.0")
}
```

로컬 IP 주소(예:`10.0.2.2` 및 `localhost` 도메인)를 신뢰할 수 있는 것으로 선언하여 백엔드와 메시지 교환을 시작합니다.

**XML:**

```
// ./app/src/main/res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2</domain>
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>
```

다음으로 HTTP 응답 구문 분석을 위한 [Gson 변환기 추가](https://github.com/square/retrofit/tree/trunk/retrofit-converters/gson)와 함께 새로운 종속 항목을 추가해야 합니다. 아래 코드에서 `<version>`을 챗 Android SDK의 현재 버전 번호(예: 1.1.0)로 대체하세요.****

**Kotlin 스크립트:**

```
// ./app/build.gradle

dependencies {
   implementation("com.amazonaws:ivs-chat-messaging:<version>")
// ...

   implementation("com.squareup.retrofit2:retrofit:2.9.0")
   implementation("com.squareup.retrofit2:converter-gson:2.9.0")
}
```

채팅 토큰을 검색하려면 `chatterbox` 앱에서 POST HTTP 요청을 해야 합니다. Retrofit이 구현할 수 있도록 요청을 인터페이스로 정의합니다. ([Retrofit 설명서](https://square.github.io/retrofit/)를 참조하세요. 또한 [CreateChatToken](https://docs.aws.amazon.com/ivs/latest/ChatAPIReference/API_CreateChatToken.html#API_CreateChatToken_RequestBody) 작업 사양도 숙지하세요.)

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/network/ApiService.kt

package com.chatterbox.myapp.network

import com.amazonaws.ivs.chat.messaging.ChatToken
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

data class CreateTokenParams(var userId: String, var roomIdentifier: String)

interface ApiService {
   @POST("create_chat_token")
   fun createChatToken(@Body params: CreateTokenParams): Call<ChatToken>
}


// ./app/src/main/java/com/chatterbox/myapp/network/RetrofitFactory.kt

package com.chatterbox.myapp.network

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitFactory {
   private const val BASE_URL = "http://10.0.2.2:3000"

   fun makeRetrofitService(): ApiService {
       return Retrofit.Builder()
           .baseUrl(BASE_URL)
           .addConverterFactory(GsonConverterFactory.create())
           .build().create(ApiService::class.java)
   }
}
```

이제 네트워킹을 설정했으므로 채팅 토큰을 생성하고 관리하는 함수를 추가할 차례입니다. 프로젝트가 [생성](#chat-kotlin-rooms-chatterbox)되었을 때 자동으로 생성된 `MainActivity.kt`에 함수를 추가합니다.

**Kotlin:**

```
// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt

package com.chatterbox.myapp

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import com.amazonaws.ivs.chat.messaging.*
import com.amazonaws.ivs.chat.messaging.coroutines.*
import com.chatterbox.myapp.network.CreateTokenParams
import com.chatterbox.myapp.network.RetrofitFactory
import retrofit2.Call
import java.io.IOException
import retrofit2.Callback
import retrofit2.Response

// custom tag for logging purposes
const val TAG = "Chatterbox-MyApp"

// any ID to be associated with auth token
const val USER_ID = "test user id"
// ID of the room the app wants to access. Must be an ARN. See Amazon Resource Names(ARNs)
const val ROOM_ID = "arn:aws:..."
// AWS region of the room that was created in Getting Started with Amazon IVS Chat
const val REGION = "us-west-2"

class MainActivity : AppCompatActivity() {

   private val service = RetrofitFactory.makeRetrofitService()
   private var userId: String = USER_ID

// ...

   private fun fetchChatToken(callback: ChatTokenCallback) {
      val params = CreateTokenParams(userId, ROOM_ID)
      service.createChatToken(params).enqueue(object : Callback<ChatToken> {
         override fun onResponse(call: Call<ChatToken>, response: Response<ChatToken>) {
            val token = response.body()
            if (token == null) {
               Log.e(TAG, "Received empty token response")
               callback.onFailure(IOException("Empty token response"))
               return
            }

            Log.d(TAG, "Received token response $token")
            callback.onSuccess(token)
         }

         override fun onFailure(call: Call<ChatToken>, throwable: Throwable) {
            Log.e(TAG, "Failed to fetch token", throwable)
            callback.onFailure(throwable)
         }
      })
   }
}
```

## 다음 단계
<a name="chat-kotlin-rooms-next-steps"></a>

이제 채팅룸 연결을 설정했으므로 이 Kotlin 코루틴 자습서의 2부인 [메시지 및 이벤트](chat-sdk-kotlin-tutorial-messages-events.md)로 이동하세요.