Amazon IVS 챗 클라이언트 메시징 SDK: Android 자습서 1부: 채팅룸 - Amazon IVS

Amazon IVS 챗 클라이언트 메시징 SDK: Android 자습서 1부: 채팅룸

본 문서는 두 파트로 구성된 자습서 중 첫 번째 파트에 해당하는 자습서입니다. Kotlin 프로그래밍 언어를 사용하여 완전한 기능을 갖춘 Android 앱을 구축하여 Amazon IVS 챗 메시징 SDK로 작업하기 위한 필수 사항을 알아봅니다. 여기에서 지칭하는 앱은 Chatterbox라고 합니다.

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

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

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

전체 SDK 설명서를 보려면 우선 Amazon IVS 챗 클라이언트 메시징 SDK(Amazon IVS 챗 사용 설명서에서 참조) 및 Chat Client Messaging: SDK for Android Reference(GitHub)를 참조하세요.

사전 조건 

  • Kotlin과 Android 플랫폼에서 애플리케이션을 만드는 데 익숙해야 합니다. Android용 애플리케이션을 만드는 데 익숙하지 않은 경우 Android 개발자를 위한 첫 앱 빌드 가이드에서 기본 사항을 배워 보세요.

  • Amazon IVS 챗 시작하기를 철저하게 읽고 이해합니다.

  • 기존 IAM 정책에 정의된 CreateChatTokenCreateRoom 기능을 사용하여 AWS IAM 사용자를 생성합니다. (Amazon IVS 챗 시작하기를 참조하세요.)

  • 이 사용자의 비밀/액세스 키가 AWS 보안 인증 파일에 저장되어 있는지 확인합니다. 지침은 AWS CLI 사용 설명서(특히 구성 및 보안 인증 파일 설정)를 참조합니다.

  • 채팅룸을 생성하고 ARN을 저장합니다. Amazon IVS 챗 시작하기를 참조하세요. (ARN을 저장하지 않은 경우 나중에 콘솔이나 Chat API를 사용하여 조회할 수 있습니다.)

로컬 인증/권한 부여 서버 설정

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

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

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

이제 AWS 보안 인증 정보가 올바르게 설정되었을 것입니다. 단계별 지침은 개발을 위한 AWS 자격 증명 및 리전 설정을 참조하세요.

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

이제 인증 서버의 로깅 기능을 설정해야 합니다. (자세한 정보는 로거 구성을 참조하세요.)

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 서버에는 resources 디렉터리의 application.* 파일에서 자동으로 로드되는 구성 설정이 필요하므로 구성 설정도 추가합니다. (자세한 정보는 파일으로 구성을 참조하세요.)

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 프로젝트 생성

Android 프로젝트를 생성하려면 Android 스튜디오를 설치하고 엽니다.

공식 Android 프로젝트 생성 가이드에 나와 있는 단계를 따릅니다.

  • 프로젝트 유형 선택에서 Chatterbox 앱을 위한 빈 활동 프로젝트 템플릿을 선택합니다.

  • 프로젝트 구성에서 다음 구성 필드 값을 선택합니다.

    • 이름: 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

이제 작동하는 Android 프로젝트가 있으므로 build.gradle 종속 항목에 com.amazonaws:ivs-chat-messaging을 추가할 수 있습니다. (Gradle 빌드 툴킷에 대한 자세한 정보는 빌드 구성을 참조하세요.)

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

아래 코드에서 <version>을 챗 Android SDK의 현재 버전 번호(예: 1.0.0)로 대체하세요.

Kotlin:

// ./app/build.gradle plugins { // ... } android { // ... } dependencies { implementation("com.amazonaws:ivs-chat-messaging:<version>") // ... }

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

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

Kotlin 스크립트:

// ./settings.gradle // ... rootProject.name = "Chatterbox" include ':app' include ':auth-server'

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

쉘:

./gradlew :auth-server:run

채팅룸에 연결 및 연결 업데이트 관찰

채팅룸 연결을 열기 위해 활동이 처음 생성될 때 실행되는 onCreate() 활동 수명 주기 콜백을 사용합니다. ChatRoom 생성자를 사용하려면 룸 연결을 인스턴스화하기 위해 regiontokenProvider를 제공해야 합니다.

참고: 아래 조각의 fetchChatToken 함수는 다음 섹션에서 구현됩니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt package com.chatterbox.myapp // ... import androidx.appcompat.app.AppCompatActivity // ... // 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와 같은 채팅 앱을 만드는 데 필수적인 부분입니다. 룸과 상호작용을 시작하기 전에 채팅룸 연결 상태 이벤트를 구독하여 업데이트를 받아야 합니다.

ChatRoom은 수명 주기 이벤트를 발생시키기 위해 ChatRoomListener 인터페이스 구현을 연결할 것으로 예상합니다. 현재 리스너 함수는 호출 시 확인 메시지만 로그합니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt // ... package com.chatterbox.myapp // ... const val TAG = "IVSChat-App" class MainActivity : AppCompatActivity() { // ... private val roomListener = object : ChatRoomListener { override fun onConnecting(room: ChatRoom) { Log.d(TAG, "onConnecting") } override fun onConnected(room: ChatRoom) { Log.d(TAG, "onConnected") } override fun onDisconnected(room: ChatRoom, reason: DisconnectReason) { Log.d(TAG, "onDisconnected $reason") } override fun onMessageReceived(room: ChatRoom, message: ChatMessage) { Log.d(TAG, "onMessageReceived $message") } override fun onMessageDeleted(room: ChatRoom, event: DeleteMessageEvent) { Log.d(TAG, "onMessageDeleted $event") } override fun onEventReceived(room: ChatRoom, event: ChatEvent) { Log.d(TAG, "onEventReceived $event") } override fun onUserDisconnected(room: ChatRoom, event: DisconnectUserEvent) { Log.d(TAG, "onUserDisconnected $event") } } }

이제 ChatRoomListener를 구현했으므로 룸 인스턴스에 연결해 보겠습니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt package com.chatterbox.myapp // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // Create room instance room = ChatRoom(REGION, ::fetchChatToken).apply { listener = roomListener } } private val roomListener = object : ChatRoomListener { // ... }

이 다음으로 룸 연결 상태를 읽을 수 있는 기능을 제공해야 합니다. MainActivity.kt 속성에 이를 보관하고 룸의 기본 DISCONNECTED 상태로 초기화합니다(IVS 챗 Android SDK 참조ChatRoom state 참조). 로컬 상태를 최신 상태로 유지하려면 state-updater 함수를 구현해야 합니다. 이 함수를 updateConnectionState라고 해 보겠습니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt package com.chatterbox.myapp // ... enum class ConnectionState { CONNECTED, DISCONNECTED, LOADING } class MainActivity : AppCompatActivity() { private var connectionState = ConnectionState.DISCONNECTED // ... private fun updateConnectionState(state: ConnectionState) { connectionState = state when (state) { ConnectionState.CONNECTED -> { Log.d(TAG, "room connected") } ConnectionState.DISCONNECTED -> { Log.d(TAG, "room disconnected") } ConnectionState.LOADING -> { Log.d(TAG, "room loading") } } } }

다음으로 state-updater 함수를 ChatRoom.Listener 속성과 통합합니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt package com.chatterbox.myapp // ... class MainActivity : AppCompatActivity() { // ... private val roomListener = object : ChatRoomListener { override fun onConnecting(room: ChatRoom) { Log.d(TAG, "onConnecting") runOnUiThread { updateConnectionState(ConnectionState.LOADING) } } override fun onConnected(room: ChatRoom) { Log.d(TAG, "onConnected") runOnUiThread { updateConnectionState(ConnectionState.CONNECTED) } } override fun onDisconnected(room: ChatRoom, reason: DisconnectReason) { Log.d(TAG, "[${Thread.currentThread().name}] onDisconnected") runOnUiThread { updateConnectionState(ConnectionState.DISCONNECTED) } } } }

이제 ChatRoom 상태 업데이트를 저장하고, 듣고, 반응할 수 있게 되었으므로 연결을 초기화할 차례입니다.

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/MainActivity.kt package com.chatterbox.myapp // ... enum class ConnectionState { CONNECTED, DISCONNECTED, LOADING } class MainActivity : AppCompatActivity() { private var connectionState = ConnectionState.DISCONNECTED // ... private fun connect() { try { room?.connect() } catch (ex: Exception) { Log.e(TAG, "Error while calling connect()", ex) } } private val roomListener = object : ChatRoomListener { // ... override fun onConnecting(room: ChatRoom) { Log.d(TAG, "onConnecting") runOnUiThread { updateConnectionState(ConnectionState.LOADING) } } override fun onConnected(room: ChatRoom) { Log.d(TAG, "onConnected") runOnUiThread { updateConnectionState(ConnectionState.CONNECTED) } } // ... } }

토큰 공급자 구축

이제 애플리케이션에서 채팅 토큰을 생성하고 관리하는 함수를 만들 차례입니다. 이 예에서는 Android용 Retrofit HTTP 클라이언트를 사용합니다.

네트워크 트래픽을 보내려면 먼저 Android용 네트워크 보안 구성을 설정해야 합니다. (자세한 정보는 네트워크 보안 구성을 참조하세요.) 앱 매니페스트 파일에 네트워크 권한을 추가하는 것부터 시작합니다. 새로운 네트워크 보안 구성을 가리키는 추가된 user-permission 태그와 networkSecurityConfig 속성에 유의하세요. 아래 코드에서 <version>을 챗 Android SDK의 현재 버전 번호(예: 1.0.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") }

10.0.2.2localhost 도메인을 신뢰할 수 있는 것으로 선언하여 백엔드와 메시지 교환을 시작합니다.

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 변환기 추가와 함께 새로운 종속 항목을 추가해야 합니다. 아래 코드에서 <version>을 챗 Android SDK의 현재 버전 번호(예: 1.0.0)로 대체하세요.

Kotlin 스크립트:

// ./app/build.gradle dependencies { implementation("com.amazonaws:ivs-chat-messaging:<version>") // ... implementation("com.squareup.retrofit2:retrofit:2.9.0") }

채팅 토큰을 검색하려면 chatterbox 앱에서 POST HTTP 요청을 해야 합니다. Retrofit이 구현할 수 있도록 요청을 인터페이스로 정의합니다. (Retrofit 설명서를 참조하세요. 또한 CreateChatToken 엔드포인트 사양도 숙지하세요.)

Kotlin:

// ./app/src/main/java/com/chatterbox/myapp/network/ApiService.kt package com.chatterbox.myapp.network // ... import androidx.annotation.Keep 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> }

이제 네트워킹을 설정했으므로 채팅 토큰을 생성하고 관리하는 함수를 추가할 차례입니다. 프로젝트가 생성되었을 때 자동으로 생성된 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 com.amazonaws.ivs.chat.messaging.* 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 = "IVSChat-App" // 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 lateinit var userId: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } 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) } }) } }

다음 단계

이제 채팅룸 연결을 설정했으므로 이 Android 자습서의 2부인 메시지 및 이벤트로 이동하세요.