SDK de Mensagens para Clientes do Chat do IVS: Tutorial para Android, parte 1: salas de chat - Amazon IVS

SDK de Mensagens para Clientes do Chat do IVS: Tutorial para Android, parte 1: salas de chat

Esta é a primeira de um tutorial de duas partes. Você aprenderá os fundamentos do trabalho com o SDK de Mensagens do Chat do Amazon IVS ao desenvolver uma aplicação Android totalmente funcional usando a linguagem de programação Kotlin. Chamamos a aplicação de Chatterbox.

Antes de iniciar o módulo, dedique alguns minutos para se familiarizar com os pré-requisitos, os principais conceitos por trás dos tokens de chat e o servidor de back-end necessários para criar salas de chat.

Esses tutoriais são criados para desenvolvedores de Android experientes que são iniciantes no SDK de Mensagens para Clientes do Chat do IVS. Você precisará estar familiarizado com a linguagem de programação Kotlin e com a criação de interfaces de usuário na plataforma Android.

Esta primeira parte do tutorial está dividida em várias seções:

Para obter a documentação completa do SDK, comece com o SDK de Mensagens para Clientes do Chat do Amazon IVS (aqui no Guia de usuário do Chat do Amazon IVS) e a Referência de Mensagens para Clientes do Chat: SDK para Android (no Github).

Pré-requisitos

Configure um servidor local de autenticação/autorização

Seu servidor de back-end será responsável por criar salas de chat e gerar os tokens de chat necessários para que o SDK do Chat do IVS para Android autentique e autorize seus clientes nas salas de chat.

Consulte Criar um token de chat em Introdução ao Amazon IVS Chat. Conforme mostrado no fluxograma, o código do lado do servidor é responsável por criar um token de chat. Isso significa que sua aplicação deve fornecer seu próprio meio de gerar um token de chat solicitando-o da sua aplicação a partir do lado do servidor.

Usamos a estrutura Ktor para criar um servidor local ativo que gerencia a criação de tokens de chat usando seu ambiente local da AWS.

Neste momento, esperamos que você tenha as credenciais da AWS configuradas corretamente. Para obter instruções detalhadas, consulte Configurar as credenciais e a região da AWS para o desenvolvimento.

Crie um novo diretório e chame-o de chatterbox. Nele, crie outro, chamado auth-server.

A pasta do nosso servidor terá a seguinte estrutura:

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

Observação: é possível copiar e colar este código diretamente nos arquivos referenciados.

Em seguida, adicionaremos todas as dependências e plug-ins necessários para que o servidor de autenticação funcione:

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

Agora, é necessário configurar a funcionalidade de registro em log para o servidor de autenticação. (Para obter mais informações, consulte Configurar 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>

O servidor Ktor requer definições de configuração, que são carregadas automaticamente do arquivo application.* no diretório resources, então adicionaremos isso também. (Para obter mais informações, consulte Configuração em um arquivo.)

HOCON:

// ./auth-server/src/main/resources/application.conf ktor { deployment { port = 3000 } application { modules = [ com.chatterbox.authserver.ApplicationKt.main ] } }

Por fim, vamos implementar o servidor:

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

Crie um projeto de Chatterbox

Para criar um projeto Android, instale e abra o Android Studio.

Siga as etapas listadas no guia oficial Criar um projeto do Android.

  • Em Escolher o tipo de projeto, selecione o modelo de projeto Atividade em branco para a aplicação Chatterbox.

  • Em Configurar o projeto, escolha os valores a seguir para os campos de configuração:

    • Nome: My App

    • Nome do pacote: com.chatterbox.myapp

    • Salvar localização: direcione para o diretório chatterbox criado na etapa anterior

    • Linguagem: Kotlin

    • Nível mínimo de API: API 21: Android 5.0 (Lollipop)

Após especificar todos os parâmetros de configuração corretamente, a estrutura de arquivos na pasta chatterbox deve se assemelhar a:

- 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

Agora que temos um projeto Android em funcionamento, é possível adicionar com.amazonaws:ivs-chat-messaging às dependências build.gradle. (Para obter mais informações sobre o kit de ferramentas de compilação Gradle, consulte Configurar sua compilação.)

Observação: na parte superior de cada trecho de código, há um caminho para o arquivo em que você deve fazer alterações em seu projeto. O caminho é relativo à raiz do projeto.

No código abaixo, substitua <version> pelo número da versão atual do SDK do Chat para Android (por exemplo, 1.0.0).

Kotlin:

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

Após a nova dependência ser adicionada, execute Sincronizar projeto com arquivos do Gradle no Android Studio para sincronizar o projeto com a nova dependência. (Para obter mais informações, consulte Adicionar dependências de compilação.)

Para executar o servidor de autenticação (criado na seção anterior) de forma conveniente a partir da raiz do projeto, nós o incluímos como um novo módulo em settings.gradle. (Para obter mais informações, consulte Como estruturar e criar um componente de software com o Gradle.)

Script de Kotlin:

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

A partir de agora, como auth-server está incluso no projeto Android, é possível executar o servidor de autenticação com o seguinte comando da raiz do projeto:

Shell:

./gradlew :auth-server:run

Conecte-se a uma sala de chat e observe as atualizações de conexão

Para abrir uma conexão de sala de chat, usamos o retorno de chamada do ciclo de vida da atividade onCreate(), que é acionado quando a atividade é criada pela primeira vez. O construtor do ChatRoom exige que forneçamos region e tokenProvider para instanciar uma conexão de sala.

Observação: a função fetchChatToken apresentada no trecho abaixo será implementada na próxima seção.

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

Exibir e reagir a mudanças na conexão de uma sala de chat são partes essenciais da criação de uma aplicação de chat como o chatterbox. Antes de começar a interagir com a sala, é necessário se inscrever em eventos de estado de conexão da sala de chat para obter atualizações.

O ChatRoom espera que vinculemos uma implementação da interface ChatRoomListener para a geração de eventos de ciclo de vida. Por enquanto, as funções do receptor registrarão em log somente mensagens de confirmação, quando invocadas:

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

Agora que implementamos o ChatRoomListener, vamos vinculá-lo à instância da sala:

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

Depois disso, é necessário fornecer a capacidade de ler o estado de conexão da sala. Vamos mantê-lo na propriedade MainActivity.kt e inicializá-lo com o estado padrão DISCONNECTED para salas (consulte ChatRoom state na Referência do SDK do Chat do IVS para Android). Para ser possível manter o estado local atualizado, é necessário implementar uma função de atualização de estado. Vamos chamá-la de 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") } } } }

Em seguida, integraremos a função de atualização de estado com a propriedade 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) } } } }

Agora que temos a capacidade de salvar, ouvir e reagir às atualizações de estado do ChatRoom, é o momento de inicializar uma conexão:

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

Crie um provedor de tokens

É hora de criar uma função responsável pela criação e pelo gerenciamento de tokens de chat na aplicação. Neste exemplo, usamos o cliente HTTP Retrofit para Android.

Antes de ser possível enviar qualquer tráfego de rede, é necessário definir uma configuração de segurança de rede para o Android. (Para obter mais informações, consulte Configuração de segurança de rede.) Começamos adicionando permissões de rede ao arquivo Manifesto da aplicação. Observe a etiqueta user-permission e o atributo networkSecurityConfig adicionados, que direcionarão para a nova configuração de segurança de rede. No código abaixo, substitua <version> pelo número da versão atual do SDK do Chat para Android (por exemplo, 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") }

Declare os domínios 10.0.2.2 e localhost como confiáveis para começar a trocar mensagens com o back-end:

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>

Em seguida, é necessário adicionar uma nova dependência, em conjunto com a adição do conversor Gson para analisar as respostas HTTP. No código abaixo, substitua <version> pelo número da versão atual do SDK do Chat para Android (por exemplo, 1.0.0).

Script de Kotlin:

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

Para recuperar um token de chat, precisamos realizar uma solicitação POST HTTP da aplicação chatterbox. Definimos a solicitação em uma interface para implementação do Retrofit. (Consulte a documentação do Retrofit. Familiarize-se também com a especificação do endpoint 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> }

Agora, com a rede configurada, é o momento de adicionar uma função responsável pela criação e pelo gerenciamento do token de chat. Nós o adicionamos ao MainActivity.kt, que foi criado automaticamente quando o projeto foi gerado:

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

Próximos Passos

Agora que você estabeleceu uma conexão com a sala de chat, prossiga para a parte 2 deste tutorial para Android: mensagens e eventos.