Client-Messaging-SDK für IVS Chat: Android-Tutorial Teil 1: Chaträume - Amazon IVS

Client-Messaging-SDK für IVS Chat: Android-Tutorial Teil 1: Chaträume

Hierbei handelt es sich um den ersten Teil eines zweiteiligen Tutorials. Sie werden die Grundlagen der Arbeit mit dem SDK für Amazon IVS Chat Messaging kennenlernen, indem Sie eine voll funktionsfähige Android-Anwendung mithilfe der Kotlin-Programmiersprache entwickeln. Wir nennen die App Chatterbox.

Bevor Sie das Modul starten, nehmen Sie sich ein paar Minuten Zeit, um sich mit den Voraussetzungen, den wichtigsten Konzepten hinter Chat-Token und dem Backend-Server vertraut zu machen, der für die Erstellung von Chaträumen erforderlich ist.

Diese Tutorials sind für erfahrene Android-Entwickler gedacht, die das IVS Chat Messaging SDK noch nicht kennen. Sie müssen mit der Programmiersprache Kotlin und der Erstellung von Benutzeroberflächen auf der Android-Plattform vertraut sein.

Der vorliegende erste Teil des Tutorials ist in mehrere Abschnitte unterteilt:

Umfassende Informationen zum SDK finden Sie im Client-Messaging-SDK für Amazon IVS Chat (im vorliegenden Benutzerhandbuch zu Amazon IVS Chat) und unter Chat Client Messaging: SDK für Android-Referenz auf GitHub.

Voraussetzungen

Einrichten eines lokalen Authentifizierungs-/Autorisierungsservers

Ihr Backend-Server ist sowohl für die Erstellung von Chaträumen als auch für die Generierung der Chat-Token verantwortlich, die das SDK von IVS Chat Android für die Authentifizierung und Autorisierung Ihrer Kunden in Ihren Chaträumen benötigt.

Weitere Informationen finden Sie unter Erstellen eines Chat-Tokens unter Erste Schritte mit Amazon IVS Chat. Wie im dortigen Flussdiagramm gezeigt, erfolgt die Erstellung eines Chat-Tokens in Ihrem serverseitigen Code. Das bedeutet, dass Ihre App eigene Mittel zur Generierung eines Chat-Tokens bereitstellen muss, indem sie ein Token von der serverseitigen Anwendung anfordert.

Mit dem Ktor-Framework erstellen wir einen lokalen Live-Server, der die Erstellung von Chat-Token mithilfe Ihrer lokalen AWS-Umgebung verwaltet.

Zu diesem Zeitpunkt gehen wir davon aus, dass Sie Ihre AWS-Anmeldeinformationen korrekt eingerichtet haben. Schritt-für-Schritt-Informationen dazu finden Sie unter Einrichten der AWS-Anmeldeinformationen und ‑Region für die Entwicklung.

Erstellen Sie ein neues Verzeichnis mit dem Namen chatterbox und darin ein weiteres Verzeichnis mit dem Namen auth-server.

Unser Server-Ordner hat die folgende Struktur:

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

Hinweis: Sie können den Code hier direkt in die referenzierten Dateien kopieren/einfügen.

Als Nächstes fügen wir alle notwendigen Abhängigkeiten und Plugins hinzu, damit unser Authentifizierungsserver funktioniert:

Kotlin-Skript:

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

Jetzt müssen wir die Protokollierungsfunktion für den Authentifizierungsserver einrichten. (Weitere Informationen finden Sie unter Konfigurieren von 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>

Der Ktor-Server benötigt Konfigurationseinstellungen, die er automatisch aus der application.*-Datei im resources-Verzeichnis lädt, also fügen wir diese ebenfalls hinzu. (Weitere Informationen finden Sie unter Konfigurierung in einer Datei.)

HOCON:

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

Lassen Sie uns abschließend unseren Server implementieren:

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

Erstellen eines Chatterbox-Projekts

Um ein Android-Projekt zu erstellen, installieren und öffnen Sie das Android Studio.

Folgen Sie den Schritten, die in der offiziellen Android-Anleitung zum Erstellen eines Projekts aufgeführt sind.

  • Wählen Sie unter Projekttyp wählen die Projektvorlage Aktivität leeren für unsere Chatterbox-App aus.

  • Wählen Sie unter Projekt konfigurieren die folgenden Werte für Konfigurationsfelder aus:

    • Name: My App

    • Paketname: com.chatterbox.myapp

    • Speicherort: Zeigt auf das im vorherigen Schritt erstellte chatterbox-Verzeichnis

    • Sprache: Kotlin

    • API-Mindestlevel: API 21: Android 5.0 (Lollipop)

Nachdem Sie alle Konfigurationsparameter korrekt angegeben haben, sollte unsere Dateistruktur im chatterbox-Ordner wie folgt aussehen:

- 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

Jetzt, da wir ein funktionierendes Android-Projekt haben, können wir com.amazonaws:ivs-chat-messaging zu unseren build.gradle-Abhängigkeiten hinzufügen. (Weitere Informationen zum Gradle-Build-Toolkit finden Sie unter Ihren eigenen Build konfigurieren.)

Hinweis: Am Anfang jedes Codeausschnitts befindet sich ein Pfad zu der Datei, in der Sie Änderungen an Ihrem Projekt vornehmen sollten. Der Pfad ist relativ zur Root des Projekts.

Ersetzen Sie im folgenden Code <version> durch die aktuelle Versionsnummer des Chat Android SDKs (z. B. 1.0.0).

Kotlin:

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

Nachdem die neue Abhängigkeit hinzugefügt wurde, führen Sie Projekt mit Gradle-Dateien synchronisieren in Android Studio aus, um das Projekt mit der neuen Abhängigkeit zu synchronisieren. (Weitere Informationen finden Sie unter Build-Abhängigkeiten hinzufügen.)

Um unseren Authentifizierungsserver (der im vorherigen Abschnitt erstellt wurde) bequem vom Projektstammverzeichnis aus ausführen zu können, fügen wir ihn als neues Modul in settings.gradle hinzu. (Weitere Informationen finden Sie unter Strukturierung und Erstellen einer Softwarekomponente mit Gradle.)

Kotlin-Skript:

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

Von nun an, da auth-server im Android-Projekt enthalten ist, können Sie den Authentifizierungsserver mit dem folgenden Befehl aus dem Stammverzeichnis des Projekts starten:

Shell:

./gradlew :auth-server:run

Mit einem Chatraum verbinden und Verbindungsupdates beobachten

Um eine Chatraum-Verbindung zu öffnen, verwenden wir onCreate() activity lifecycle callback, welcher ausgelöst wird, wenn die Aktivität zum ersten Mal erstellt wird. Für den ChatRoom-Constructor müssen wir region und tokenProvider bereitstellen, um eine Raumverbindung zu instanziieren.

Hinweis: Die fetchChatToken-Funktion im folgenden Ausschnitt wird im nächsten Abschnitt implementiert.

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

Das Anzeigen und Reagieren auf Änderungen in der Verbindung eines Chatraums sind wesentliche Bestandteile einer Chat-App wie chatterbox. Bevor wir anfangen können, mit dem Raum zu interagieren, müssen wir die Verbindungsstatus-Ereignisse des Chat-Raums abonnieren, um Aktualisierungen zu erhalten.

ChatRoom erwartet, dass wir eine ChatRoomListener-Schnittstellenimplementierung zum Auslösen von Lebenszyklusereignissen anhängen. Für den Moment protokollieren Listener-Funktionen nur Bestätigungsnachrichten, wenn diese aufgerufen werden:

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

Nun da wir ChatRoomListener implementiert haben, hängen wir es an unsere Raum-Instance an:

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

Danach müssen wir die Möglichkeit bieten, den Raum-Verbindungsstatus zu lesen. Wir behalten sie in der Eigenschaft bei MainActivity.kt und initialisieren sie auf den Standardzustand DISCONNECTED für Räume (siehe ChatRoom state in der Referenz zu IVS Chat Android SDK). Um den lokalen Status auf dem neuesten Stand zu halten, müssen wir eine Statusaktualisierungsfunktion implementieren; nennen wir sie 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") } } } }

Als Nächstes integrieren wir unsere Statusaktualisierungsfunktion in die Eigenschaft 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) } } } }

Da wir nun die Möglichkeit haben, den ChatRoom-Status zu speichern, abzuhören und auf Aktualisierungen zu reagieren, ist es an der Zeit, eine Verbindung zu initialisieren:

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

Erstellen eines Token-Anbieters

Es ist an der Zeit, eine Funktion zu erstellen, die für die Erstellung und Verwaltung von Chat-Token in unserer Anwendung verantwortlich ist. In diesem Beispiel verwenden wir Retrofit-HTTP-Client für Android.

Bevor wir Netzwerkverkehr senden können, müssen wir eine Netzwerksicherheitskonfiguration für Android einrichten. (Weitere Informationen finden Sie unter Konfiguration der Netzwerksicherheit.) Wir beginnen mit dem Hinzufügen von Netzwerkberechtigungen zur App-Manifest-Datei. Beachten Sie das hinzugefügte Tag user-permission und das hinzugefügte Attribut networkSecurityConfig, die auf unsere neue Netzwerksicherheitskonfiguration verweisen. Ersetzen Sie im folgenden Code <version> durch die aktuelle Versionsnummer des Chat Android SDKs (z. B. 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") }

Deklarieren Sie die Domains 10.0.2.2 und localhost als vertrauenswürdig, um mit dem Nachrichtenaustausch mit unserem Backend zu beginnen:

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>

Als Nächstes müssen wir eine neue Abhängigkeit sowie Gson converter addition für die Analyse von HTTP-Antworten hinzufügen. Ersetzen Sie im folgenden Code <version> durch die aktuelle Versionsnummer des Chat Android SDKs (z. B. 1.0.0).

Kotlin-Skript:

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

Um ein Chat-Token abzurufen, müssen wir eine POST-HTTP-Anfrage von unserer chatterbox-App aus stellen. Wir definieren die Anfrage in einer Schnittstelle, die Retrofit implementieren soll. (Siehe Retrofit-Dokumentation. Machen Sie sich mit der CreateChatToken-Endpunktspezifikation vertraut.)

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

Jetzt, da das Netzwerk eingerichtet ist, ist es an der Zeit, eine Funktion hinzuzufügen, die für die Erstellung und Verwaltung unseres Chat-Tokens verantwortlich ist. Wir fügen sie zu MainActivity.kt hinzu, das bei der Generierung des Projekts automatisch erstellt wurde:

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

Nächste Schritte

Nachdem Sie nun eine Chatraum-Verbindung hergestellt haben, fahren Sie mit Teil 2 dieses Android-Tutorials fort: Nachrichten und Ereignisse.