

# IVS Chat Client Messaging SDK: Android のチュートリアルパート 1: チャットルーム
<a name="chat-sdk-android-tutorial-chat-rooms"></a>

これは 2 部構成のチュートリアルの第 1 部です。[Kotlin](https://kotlinlang.org/) プログラミング言語を使用して完全に機能する Android アプリを構築することにより、Amazon IVS Chat Messaging SDK の操作の要点を学びます。このアプリケーションは、Chatterbox と呼ばれます。

モジュールを開始する前に、数分の時間を割いて、前提条件、チャットトークンの主な概念、チャットルームの作成に必要なバックエンドサーバーについて理解しておいてください。

これらのチュートリアルは、IVS Chat Messaging SDK を初めて利用する、経験豊富な Android デベロッパー向けに作成されています。Kotlin プログラミング言語と Android プラットフォームでの UI の作成に慣れている必要があります。

このチュートリアルの最初の部分は、いくつかのセクションに分かれています。

1. [ローカル認証サーバーおよび認可サーバーのセットアップ](#chat-android-rooms-auth-server)

1. [Chatterbox プロジェクトの作成](#chat-android-rooms-chatterbox)

1. [チャットルームに接続し、接続の更新を確認する](#chat-android-rooms-connect-state)

1. [トークンプロバイダーの作成](#chat-android-rooms-token-provider)

1. [次のステップ](#chat-android-rooms-next-steps)

すべての SDK ドキュメントについては、まずこの「Amazon IVS Chat ユーザーガイド」の「[Amazon IVS Chat Client Messaging SDK](chat-sdk.md)」および GitHub の「[Chat Client Messaging: SDK for Android リファレンス](https://aws.github.io/amazon-ivs-chat-messaging-sdk-android/1.0.0/)」を参照してください。

## 前提条件
<a name="chat-android-rooms-prerequisites"></a>
+ Kotlin と Android プラットフォームでのアプリケーションの作成に慣れておいてください。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-android-rooms-auth-server"></a>

バックエンドサーバーは、チャットルームの作成と、IVS Chat Android SDK がチャットルーム用のクライアントを認証および認可するために必要なチャットトークンの生成の両方を行います。

「*Amazon IVS Chat の開始方法*」の「[チャットトークンを作成する](getting-started-chat-auth.md)」を参照してください。フローチャートで示されているように、チャットトークンの作成はサーバー側のコードで行われます。つまり、サーバー側のアプリケーションからリクエストし、独自の方法でチャットトークンを生成する必要があります。

[Ktor](https://ktor.io/) フレームワークを使用して、ローカルの AWS 環境でチャットトークンの作成を管理するライブローカルサーバーを作成します。

この時点で、AWS 認証情報が正しく設定されている必要があります。詳しい手順については、「[開発用に一時的な AWS 認証情報とリージョンを設定する](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")
}
```

ここで、認証サーバー用にログ記録機能を設定する必要があります。(詳細については、「[Configure logger](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-android-rooms-chatterbox"></a>

Android プロジェクトを作成するには、[Android Studio](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)」で、設定フィールドに次の値を選択します。
  + **[Name]**: My App
  + **[Package name]**: com.chatterbox.myapp
  + **[Save location]**: 前の手順で作成した `chatterbox` ディレクトリを指します
  + **[Language]**: Kotlin
  + **[Minimum API level]**: 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](https://mvnrepository.com/artifact/com.amazonaws/ivs-chat-messaging) を追加できます。([Gradle](https://gradle.org/) ビルドツールキットの詳細については、「[Configure your build](https://developer.android.com/build)」を参照してください)。

**注:** すべてのコードスニペットの先頭には、プロジェクトで変更を加える必要があるファイルへのパスがあります。パスは、プロジェクトのルートに対する相対パスです。

以下のコードでは、`<version>` を、Chat Android SDK の現在のバージョン番号 (1.0.0 など) に置き換えてください。

**Kotlin**:

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

plugins {
// ...
}

android {
// ...
}

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

新しい依存関係を追加したら、Android Studio で **[Sync Project with Gradle Files]** を実行して、プロジェクトを新しい依存関係と同期させます。(詳細については、「[ビルド依存関係を追加する](https://developer.android.com/build/dependencies)」を参照してください。)

(前のセクションで作成した) 認証サーバーをプロジェクトルートから便利に実行するために、`settings.gradle` で新しいモジュールとして組み込みます。(詳細については、「[Structuring and Building a Software Component with Gradle](https://docs.gradle.org/current/userguide/multi_project_builds.html)」を参照してください。)

**Kotlin スクリプト:**

```
// ./settings.gradle

// ...

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

これで、`auth-server` が Android プロジェクトに含まれたため、そのプロジェクトのルートから次のコマンドを実行して認証サーバーを実行できます。

**シェル:**

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

## チャットルームに接続し、接続の更新を確認する
<a name="chat-android-rooms-connect-state"></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-android-rooms-token-provider)で実装されます。

**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](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) では、ライフサイクルイベントを発生させるための [ChatRoomListener インターフェイス](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
// ...
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` [プロパティ](https://kotlinlang.org/docs/properties.html)に保持し、ルームのデフォルトの [DISCONNECTED] 状態に初期化します (「[IVS Chat 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
// ...

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](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() {
// ...

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

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

## トークンプロバイダーの作成
<a name="chat-android-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>` を Chat 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.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>` を Chat 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 のドキュメント](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 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>
}
```

ネットワークが設定されたので、チャットトークンの作成と管理を行う関数を追加します。プロジェクトが[生成](#chat-android-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 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)
         }
      })
   }
}
```

## 次のステップ
<a name="chat-android-rooms-next-steps"></a>

これで、チャットルーム接続を確立できました。次に、この Android のチュートリアルのパート 2「[メッセージとイベント](chat-sdk-android-tutorial-messages-events.md)」に進んでください。