In diesem Dokument erfahren Sie, wie Sie das Headless Mobile SDK in Ihre Android-App einbinden und anpassen. Darin werden unter anderem die Themen Lokalisierung und Flows nach der Sitzung behandelt.
Abläufe nach der Sitzung (virtueller Assistent nach der Sitzung, Umfragen und Kundenzufriedenheit)
Wenn ein Live-Chat oder ein Sprachanruf beendet wird, möchten Contact Center häufig Feedback einholen oder automatisierte Follow-ups anbieten. CCAI Platform unterstützt drei Arten von Post-Session-Erlebnissen:
Virtueller Kundenservicemitarbeiter nach der Sitzung: Ein automatisierter Chatbot, der die Unterhaltung fortsetzt, nachdem der Kundenservicemitarbeiter die Verbindung getrennt hat.
Umfragen: Ein Formular mit mehreren Fragen, das auf die jeweilige Warteschlange zugeschnitten ist.
KZUF (Kundenzufriedenheit): Eine Bewertung (z. B. 1–5 Sterne) und optionales Textfeedback.
Hierarchie durchsetzen
Es ist üblich, dass Administratoren sich überschneidende Regeln im Portal konfigurieren, z. B. indem sie CSAT global aktivieren, aber auch einen VA nach der Sitzung für die Abrechnungswarteschlange aktivieren.
Das bietet das SDK: Eine strikte Engine zur Konfliktlösung. Das SDK wertet die Portalregeln aus und sorgt dafür, dass pro Sitzung nur ein Post-Session-Ablauf ausgelöst wird. Dabei wird die folgende Hierarchie strikt eingehalten:
Priorität nach der Sitzung: VA nach der Sitzung > Umfragen > CSAT
- Beispiel: Wenn sowohl die Kundenzufriedenheit als auch die VA nach der Sitzung für eine Warteschlange aktiviert sind, sieht der Nutzer NUR die VA nach der Sitzung.
Was Sie erstellen: Ein Listener, der darauf wartet, dass die Sitzung beendet wird, das SDK fragt, welcher Ablauf die Hierarchieauswertung gewonnen hat, und den entsprechenden Bildschirm zeichnet. Sie müssen keine komplexe If-Else-Logik schreiben, um herauszufinden, welche Variante die beste ist. Das SDK erledigt das für Sie.
Implementierungsbeispiel
In diesem Snippet wird gezeigt, wie Ihre App auf das Ende einer Sitzung reagieren und das SDK fragen sollte, was als Nächstes zu tun ist.
// Called when the active chat or call ends
fun handleSessionEnded(postSessionFlow: PostSessionFlow?) {
// 1. Check if there is a required post-session flow.
// The SDK has already calculated the hierarchy (VA > Survey > CSAT).
val flow = postSessionFlow
if (flow == null) {
// No feedback required. Safely close the support UI.
closeSupportExperience()
return
}
// 2. Route to the winning flow returned by the SDK.
when (flow.type) {
PostSessionType.VIRTUAL_AGENT -> transitionToPostSessionVA()
PostSessionType.SURVEY -> showSurveyScreen(flow)
PostSessionType.CSAT -> showCSATScreen(flow)
}
}
Übergang in die Phase nach der Sitzung
Unabhängig davon, welcher Ablauf in der Hierarchie gewinnt, müssen Sie zwei gemeinsame Lebenszyklusmethoden für chatService aufrufen, um der CCAI Platform zu signalisieren, dass die Phase nach der Sitzung begonnen hat.
Funktionen des SDK: Lebenszyklusmethoden für den Übergang der Sitzung in die und durch die Nachsitzungsphase (startPostSession, readyPostSession).
Was Sie entwickeln: Die Orchestrierungslogik, mit der diese Methoden an den richtigen Stellen in Ihrem UI-Ablauf nach der Sitzung aufgerufen werden.
Implementierungsbeispiel
Mit diesem Code wird die Sitzung durch die beiden Lebenszyklusphasen nach der Sitzung geführt.
lifecycleScope.launch {
// Step 1: Start the post-session process (updates status to "in_progress")
try {
val postSessionResponse = CCAI.chatService?.startPostSession()
if (postSessionResponse != null) {
Log.d("CCAI", "Post-session started successfully: ${postSessionResponse.id}")
}
} catch (e: Exception) {
Log.e("CCAI", "Failed to start post-session: ${e.message}")
}
// Step 2: Signal that post-session is ready (updates status to "ready")
try {
val readyResponse = CCAI.chatService?.readyPostSession()
if (readyResponse != null) {
Log.d("CCAI", "Post-session ready: ${readyResponse.id}")
}
} catch (e: Exception) {
Log.e("CCAI", "Failed to prepare post-session: ${e.message}")
}
}
Nachdem die Plattform die Umstellung bestätigt hat, fahren Sie mit diesem speziellen Ablauf fort.
Felder für den Status nach der Sitzung auf ChatResponse
Zwei Orchestrierungsfelder nach der Sitzung auf ChatResponse steuern die Übergangslogik:
postSessionTransferStatus: String?: Der aktuelle Status der Übertragung nach der Sitzung (z. B."in_progress","ready","completed"). Die Plattform verwendet dieses Feld als Schlüssel für den Orchestrierungsstatusautomaten:startPostSession()verschiebt ihn zu"in_progress",readyPostSession()verschiebt ihn zu"ready". Sie sehen diesen Wert bei nachfolgendenChatResponse-Ausgaben (aus dem Chatflow des Chatdienstes), um den Übergang auf der Plattformseite zu bestätigen.postSessionOptInRequired: Boolean?: Gibt an, ob der Nutzer den Post-Session-Ablauf explizit aktivieren muss, bevor er ausgeführt wird. Wenntrue, blenden Sie in Ihrer Benutzeroberfläche eine Aufforderung zur Einwilligung ein und rufen SiestartPostSession()erst auf, wenn der Nutzer seine Einwilligung erteilt hat. Beifalseodernullist die Opt-in-Prüfung nicht erforderlich und Sie können direkt zum Ablauf nach der Sitzung übergehen.
suspend fun orchestratePostSession(chat: ChatResponse) {
// 1. Honor opt-in gating if required
if (chat.postSessionOptInRequired == true) {
val consented = presentPostSessionOptIn()
if (!consented) {
closeSupportExperience()
return
}
}
// 2. Drive the state machine
CCAI.chatService?.startPostSession() // → "in_progress"
CCAI.chatService?.readyPostSession() // → "ready"
// 3. Observe postSessionTransferStatus on subsequent chat updates
// to confirm the transfer completed before rendering the winning flow.
}
postSessionRequiredgibt an, ob für die Sitzung ein beliebiger Post-Session-Ablauf konfiguriert ist.postSessionOptInRequiredgibt an, ob vor dem Ausführen eine ausdrückliche Nutzereinwilligung erforderlich ist.postSessionTransferStatusgibt an, in welcher Phase des Übergangs sich die Plattform befindet.
Alle drei sind unabhängig voneinander. Prüfen Sie daher immer alle drei.
Virtueller Kundenservicemitarbeiter nach der Sitzung (höchste Priorität)
Was das SDK bietet: Der Übergangszustand, um die Sitzung von einem Kundenservicemitarbeiter zurück zu einem automatisierten Bot zu verlagern, und das Routing der Nachrichten des Bots.
Was Sie erstellen: Nichts völlig Neues. Da der virtuelle Assistent nach der Sitzung als Chat fungiert, lassen Sie die vorhandene benutzerdefinierte Chat-Benutzeroberfläche geöffnet und lassen Sie sie die eingehenden automatisierten Nachrichten genauso verarbeiten wie die Nachrichten des menschlichen Kundenservicemitarbeiters.
Implementierungsbeispiel
Wenn das SDK einen Übergang zu einer virtuellen Assistentin nach der Sitzung signalisiert, aktualisieren Sie die Chat-Benutzeroberfläche entsprechend.
fun transitionToPostSessionVA() {
// Keep your chat UI open, but update the visual context
myChatAdapter.addSystemMessage(
"You are now speaking with our Virtual Assistant"
)
agentNameTextView.text = "Virtual Assistant"
agentAvatarImageView.setImageResource(R.drawable.ic_bot_avatar)
// The SDK will automatically start piping the VA's messages into
// your standard chat message observer (messagesReceived).
}
Umfragen (mittlere Priorität)
Funktionen des SDK: Das rateService stellt Methoden zum Abrufen von Umfragefragen und zum Einreichen von Antworten für eine Kommunikationssitzung bereit. Umfragefragen werden vom Administrator für jede Warteschlange konfiguriert und können mehrere Fragetypen umfassen (Kundenzufriedenheit, Sternebewertung, Freitext, Aufzählung, numerische Skala).
Was Sie erstellen: Ein dynamisches Formular, das die Umfrage abruft, die Fragen durchläuft, die entsprechende Benutzeroberfläche (z. B. Optionsfelder, Sternebewertungen oder Textfelder) für jede Frage rendert, prüft, ob Pflichtfelder ausgefüllt sind, und die Antworten für den Rückversand verpackt.
Schlüsseltypen
// Survey response from getSurvey()
data class Survey(
val id: Int?,
val lang: String?,
val questions: List<SurveyQuestion>?,
val signOffText: String? // "Thank you" message to show after submission
)
// Request payload for sendSurvey()
data class SurveyRequest(
val answers: Map<Int, String> // Maps question IDs to answer values
)
Implementierungsbeispiel
Mit diesem Code werden Umfragefragen aus rateService abgerufen, in einem benutzerdefinierten Fragment gerendert und die Antworten werden gesendet.
fun showSurveyScreen(communicationId: Long) {
val rateService = CCAI.rateService ?: return
lifecycleScope.launch {
try {
// 1. Fetch the survey questions for this session
val survey = rateService.getSurvey(
communicationId = communicationId,
communicationType = "chats"
).getOrThrow()
// 2. Present your custom survey UI
val surveyFragment = MyCustomSurveyFragment.newInstance(
survey.questions.orEmpty()
)
surveyFragment.onSubmit = { answersMap ->
lifecycleScope.launch {
try {
// 3. Submit the answers
val request = SurveyRequest(answers = answersMap)
rateService.sendSurvey(
communicationId = communicationId,
communicationType = "chats",
answers = request
).getOrThrow()
rateService.clear()
closeSupportExperience()
} catch (e: Exception) {
Log.e("CCAI", "Failed to submit survey: ${e.message}")
}
}
}
supportFragmentManager.beginTransaction()
.replace(R.id.container, surveyFragment)
.addToBackStack(null)
.commit()
} catch (e: Exception) {
Log.e("CCAI", "Failed to load survey: ${e.message}")
closeSupportExperience()
}
}
}
CSAT – Kundenzufriedenheit (niedrigste Priorität)
Funktionsweise des SDK: Das rateService stellt eine rate()-Methode zum Senden einer CSAT-Punktzahl und optionalem Feedback für eine Kommunikationssitzung bereit. Die Bewertung ist in der Regel eine Ganzzahl zwischen 1 und 5.
Was Sie entwickeln: Den visuellen Bewertungsbildschirm (z. B. eine Reihe von Sternen zum Antippen oder eine Skala von 1 bis 5), ein Textfeld, wenn Feedback zulässig ist, und eine Schaltfläche Senden.
Schlüsseltypen
// Request payload for rate()
data class RatingRequest(
val rating: Int? = null, // Typically 1-5
val feedback: String? = null // Optional qualitative feedback
)
Implementierungsbeispiel
Nachdem der Nutzer auf eine Sternebewertung getippt und sein Feedback eingegeben hat, übergeben Sie diese Werte an rateService.
fun submitCSATFeedback(communicationId: Long, rating: Int, comment: String?) {
val rateService = CCAI.rateService ?: return
submitButton.isEnabled = false
progressBar.isVisible = true
lifecycleScope.launch {
try {
val request = RatingRequest(
rating = rating,
feedback = comment?.trim()?.takeIf { it.isNotEmpty() }
)
rateService.rate(
communicationId = communicationId,
communicationType = "chats",
request = request
).getOrThrow()
rateService.clear()
showThankYouScreen()
} catch (e: Exception) {
showErrorToast("Failed to submit feedback. Please try again.")
} finally {
submitButton.isEnabled = true
progressBar.isVisible = false
}
}
}
Chattranskripte herunterladen
Funktionen des SDK:Eine Methode zum Herunterladen des Chat-Transkripts als PDF-Datei.
Was Sie entwickeln: Den Download-Button in Ihrer Benutzeroberfläche und die Logik für die Dateiverarbeitung (Speichern, Freigeben oder Vorschau).
Implementierungsbeispiel
Dieser Code zeigt, wie das Transkript unter Android heruntergeladen wird: Das PDF wird als Datei abgerufen und dann in Ihrer App gespeichert, freigegeben oder als Vorschau angezeigt.
// Download to a file destination
val documentsDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
val transcriptFile = File(documentsDir, "chat_transcript.pdf")
lifecycleScope.launch {
try {
val transcriptFile = CCAI.chatService?.downloadChatTranscript()
if (transcriptFile != null) {
Log.d("CCAI", "Transcript downloaded to: ${transcriptFile.absolutePath}")
}
} catch (e: Exception) {
Log.e("CCAI", "Failed to download transcript: ${e.message}")
}
}
Die Android-Methode downloadChatTranscript() hat keine Parameter und gibt einen File? zurück, der auf das heruntergeladene PDF verweist. Die Methode downloadChatTranscriptData(), die rohe PDF-Daten direkt im Arbeitsspeicher zurückgibt, ohne sie auf der Festplatte zu speichern, ist nur unter iOS verfügbar. Achten Sie darauf, dass Ihre App die entsprechenden Berechtigungen für die Dateispeicherung hat, wenn Sie im freigegebenen Speicher speichern.
Sprachen und Lokalisierung
Da Sie eine benutzerdefinierte integrierte Benutzeroberfläche mit dem Headless Mobile SDK erstellen, sind Sie für die Übersetzung der Schaltflächen, Menüs und benutzerdefinierten Benachrichtigungen Ihrer App verantwortlich.
Warum muss das SDK die Sprache des Nutzers kennen?
Warteschlangen-Routing: CCAI Platform verwendet den Sprachcode, um den Nutzer an einen Kundenservicemitarbeiter weiterzuleiten, der diese Sprache spricht.
Systemnachrichten: Automatisierte Nachrichten, die vom Backend der CCAI-Plattform generiert werden (z. B. „Ein Kundenservicemitarbeiter wird sich in Kürze bei Ihnen melden“), werden in der aktiven Sprache gesendet.
APIs für Sprachdienste
Funktionen des SDK: Eine languageCode-Eigenschaft zum Lesen und Schreiben für die aktive SDK-Sprache.
Was Sie entwickeln: Eine Benutzeroberfläche zur Sprachauswahl (wenn Nutzer die Sprache manuell auswählen sollen) und die Logik zum Festlegen der Sprache vor Beginn einer Sitzung.
// Read the active language
val currentLanguage = CCAI.languageService?.languageCode
// Set the active language before the user starts a support session
CCAI.languageService?.languageCode = "es"
Das SDK bietet keine feste Liste der unterstützten Sprachen. Wenn in Ihrer App eine Sprachauswahl angezeigt wird, müssen Sie die Anzeigeliste der App selbst verwalten oder die vom SDK zurückgegebene Instanz- oder Unternehmenskonfiguration verwenden, um zu bestimmen, welche Sprachen angeboten werden sollen.
SDK-Sprache festlegen (Regel vor der Sitzung)
Funktionen des SDK: Ein LanguageService, das die von Ihnen angeforderte Sprache mit den Sprachen vergleicht, die Ihre Administratoren tatsächlich im CCAI Platform-Portal aktiviert haben.
Was Sie entwickeln müssen: Wenn Sie Nutzern die Möglichkeit geben möchten, die Sprache manuell zu überschreiben (anstatt sich nur auf die Standardeinstellungen ihres Geräts zu verlassen), müssen Sie die Auswahl-UI (z. B. ein Drop-down-Menü) entwickeln und dafür sorgen, dass sie nur bevor Nutzer auf einen Supportkanal tippen zugänglich ist.
Implementierungsbeispiel
In diesem Code wird gezeigt, wie die Sprache des SDKs mithilfe von Standard-Sprachcodes nach ISO 639 (z. B. "es" für Spanisch, "fr" für Französisch) explizit überschrieben wird. Die bevorzugte Sprache wird bei der SDK-Initialisierung in der Datenklasse InitOptions mit dem Parameter languageCode festgelegt. Sie können sie auch beim Re-Initialisieren des SDK festlegen:
// Set language during initialization
val initOptions = InitOptions(
key = "YOUR_COMPANY_KEY",
urlHost = "your_subdomain.ccaiplatform.com",
languageCode = "es" // for example, "es" for Spanish, "fr" for French
)
try {
CCAI.initialize(context = this, options = initOptions)
} catch (e: Exception) {
Log.e("CCAI", "Failed to initialize CCAI: ${e.message}")
}
Initialisierung des Chatmoduls (Android)
Wenn Sie das Chatmodul mit der Überladung initialisieren, die einen Sprachcode akzeptiert, können Sie die Sprache auch dort angeben:
val chatOptions = ChatOptions(
webFormInterface = WebFormManager(),
downloadTranscriptVisibility = DownloadTranscriptVisibility.SHOW_ALL,
greeting = "Hello! How can I help you?"
)
CCAI.initializeChat(context = this, options = chatOptions)
Sie können die Sprache auch beim Abrufen von Warteschlangenmenüs übergeben:
val menuResult = CCAI.queueMenuService?.get(key = null)
Überschreiben Sie die Einstellungen pro Sitzung mit ChatRequest:
val chatRequest = ChatRequest(
chat = Chat(
menuId = menuId,
languageCode = "fr" // This session will use French
)
)
So wird die endgültige Sprache in CCAI Platform festgelegt
Wenn Sie keine Sprache explizit festlegen, benötigt das SDK trotzdem einen Sprachcode für Routen und Systemmeldungen. Damit das Verhalten vorhersehbar bleibt, sollten Sie es selbst festlegen, bevor der Nutzer eine Supportsitzung startet.
Verwenden Sie diese Prioritätsreihenfolge:
Anstößige Sprache (empfohlen): Wenn Sie in
InitOptions.languageCodeeine Sprache festlegen, verwendet das SDK diese Sprache.Sprachaktualisierung vor der Sitzung (weiterhin explizit): Wenn Sie
CCAI.languageService?.languageCode = "es"festlegen, bevor der Nutzer einer Warteschlange beitritt, verwendet das SDK die aktualisierte Sprache.Überschreibung pro Sitzung (nur Chat): Wenn Sie
ChatRequest(chat = Chat(..., languageCode = "fr"))angeben, wird in der entsprechenden Chatsitzung der angeforderte Sprachcode verwendet.Wenn Sie nichts festlegen: Das Verhalten wird auf die beste verfügbare Option zurückgesetzt, die vom SDK in der Geräte- und Instanzkonfiguration ermittelt wird. Um konsistente Ergebnisse zu erzielen, sollten Sie sich nicht darauf verlassen und immer explizit eine Sprache festlegen (Schritte 1–3).
Fehlerbehandlung, Fallback und Sitzungsverwaltung
Selbst bei den robustesten Apps kann es zu Verbindungsabbrüchen, fehlenden Abhängigkeiten oder Authentifizierungsproblemen kommen. Das Headless Mobile SDK wurde entwickelt, um diese zugrunde liegenden Plattformprobleme zu erkennen und in Ihrer App anzuzeigen. So können Sie sie in Ihrer benutzerdefinierten Benutzeroberfläche elegant behandeln oder sich auf die automatischen Fallbacks der CCAI Platform verlassen.
SDK-Fehler behandeln
Was das SDK bietet: Neben den standardmäßigen Kotlin-Ausnahmen zwei Kategorien von typisierten Ausnahmen:
HttpExceptionWithCode– Wird von einer beliebigen asynchronen Dienstmethode ausgelöst, wenn eine HTTP-Anfrage an die CCAI-Plattform fehlschlägt. Stellt eineInt code-Property bereit, damit Sie anhand von Statuscodes verzweigen können (z. B.401für abgelaufene Authentifizierung,429für Ratenbegrenzung,5xxfür Serverfehler).CallCreationError.AfterHours: Ein versiegelter Fehler, der von der API für geplante Anrufe (callService.createScheduledCall) ausgegeben wird, wenn ein Slotkonflikt auftritt oder das Zeitfenster für Reservierungen geschlossen wurde. Enthält eine serverlokalisiertedisplayMessage, die direkt für den Nutzer angezeigt werden soll.Standardmäßige Kotlin- oder Java-Ausnahmen: Netzwerkfehler werden als
java.io.IOException, das Abbrechen von Coroutinen alskotlinx.coroutines.CancellationExceptionund alles Unerwartete als die BasisklasseExceptionangezeigt.
Was Sie erstellen: Eine geschichtete Try- oder Catch-Anweisung für jeden SDK-Dienstaufruf. Fangen Sie zuerst die spezifischste Ausnahme ab (domänenspezifische versiegelte Fehler wie CallCreationError.AfterHours, falls zutreffend, dann HttpExceptionWithCode für die Verzweigung des HTTP-Status) und weichen Sie bei Netzwerk-, System- und unerwarteten Fehlern auf einen generischen Exception-Handler aus.
Implementierungsbeispiel
In diesem Code wird ein SDK-Aufruf in einem mehrschichtigen Try- oder Catch-Muster umschlossen. Dabei wird zuerst HttpExceptionWithCode abgefangen, um den HTTP-Statuscode zu verzweigen, und dann wird auf einen generischen Handler für alles andere zurückgegriffen.
import kotlinx.coroutines.launch
import androidx.lifecycle.lifecycleScope
lifecycleScope.launch {
try {
CCAI.chatService?.start(chatRequest)
// Handle success - observe chat state using chatReceived
} catch (e: HttpExceptionWithCode) {
// Handle HTTP-level failures from CCAI endpoints - inspect e.code for status code
Log.e("CCAI", "HTTP ${e.code}: ${e.message}")
showErrorToast("Something went wrong. Please try again.")
} catch (e: Exception) {
// Handle other errors (examples: network and system)
Log.e("CCAI", "Error: ${e.message}")
showErrorToast("An unexpected error occurred.")
}
}
Best Practices
Umschließen Sie jeden SDK-Dienstaufruf mit einem mehrschichtigen Try/Catch-Block. Verwenden Sie
HttpExceptionWithCode, um HTTP-Statuscodes zu verzweigen, z. B. umccaiShouldAuthenticate()bei401(abgelaufenes Autorisierungstoken) neu auszulösen, einen Backoff bei429(Ratenbegrenzung) anzuwenden oder einen allgemeinen Fehler bei5xx-Antworten anzuzeigen.Fangen Sie bei APIs für geplante Anrufe
CallCreationError.AfterHoursvorHttpExceptionWithCodeab, damit 409 Slot-Konflikte mit der serverlokalisierten Meldung behandelt werden.Fangen Sie schließlich generische
Exceptionals Sicherheitsnetz fürIOException,CancellationExceptionund alle unerwarteten Fehler ab. Wenn Sie die Ausnahmedetails während der Entwicklung protokollieren, können Sie die Ursachen schnell ermitteln.
Sitzungen prüfen und schließen
Da der Lebenszyklus Ihrer App unabhängig vom Lebenszyklus des CCAI-Plattformsupports ist, müssen Sie den Sitzungsstatus verwalten, insbesondere bei Nutzerabmeldungen.
Funktionen des SDK: Utility-APIs, mit denen geprüft werden kann, ob eine Support-Sitzung noch läuft (auch nach App-Neustarts oder erzwungenen Beendigungen), und Methoden zum Löschen des im Cache gespeicherten SDK-Authentifizierungsstatus, der mit einem bestimmten Endnutzer verknüpft ist. So wird verhindert, dass der nächste angemeldete Nutzer die Sitzung des vorherigen Nutzers übernimmt.
Was Sie entwickeln: Pre-Flight-Prüfungen vor dem Start neuer Sitzungen und Bereinigungsroutinen, die ausgelöst werden, wenn sich ein Nutzer von Ihrer Haupt-App abmeldet.
Implementierungsbeispiel (Bereinigung nach dem Abmelden)
Beendet alle aktiven Sitzungen, löscht das im SDK zwischengespeicherte Authentifizierungstoken, löscht lokale App-Daten und leitet zum Anmeldebildschirm weiter. Dies ist die Mindestanforderung, um zu verhindern, dass Sitzungen beim Abmelden des Nutzers übernommen werden.
fun handleUserLogout() {
lifecycleScope.launch {
// 1. Check for an in-progress session and end it cleanly
try {
val activeChat = CCAI.chatService?.getLastChatInProgress()
if (activeChat != null) {
CCAI.chatService?.endChat()
Log.d("CCAI", "Ended active chat before logout.")
}
} catch (e: Exception) {
// Session may not exist - that's fine
Log.w("CCAI", "No active session to end: ${e.message}")
}
// 2. Clear the cached auth token
// (prevents the next user from inheriting the previous session)
CCAI.authService?.updateAuthToken(null)
// 3. Wipe your own app's user data
MyAuthManager.clearLocalData()
// 4. Navigate back to the login screen
navigateToLoginScreen()
}
}
Integration von Kotlin-Koroutinen und Flow
Das Headless Mobile SDK for Android basiert auf Kotlin-Coroutinen und Flow als primären reaktiven Mustern. Dies ist das Android-Äquivalent der Combine-Integration des iOS SDK.
Funktionen des SDK: Kotlin Flow-Streams und Suspend-Funktionen, die SDK-Echtzeitereignisse (eingehende Nachrichten, Änderungen des Bildschirmfreigabestatus) als beobachtbare reaktive Streams ausgeben.
Was Sie entwickeln: Auf Coroutinen basierende Integrationen, die diese Flows erfassen und Ihre Android-Benutzeroberfläche entsprechend aktualisieren.
Funktionen sperren
Viele SDK-Dienstmethoden sind Kotlin-Suspend-Funktionen. Das bedeutet, dass sie aus einem Koroutinenbereich aufgerufen werden können und angehalten (nicht blockiert) werden, während auf ein Ergebnis gewartet wird.
import kotlinx.coroutines.launch
import androidx.lifecycle.lifecycleScope
// In an Activity or Fragment
lifecycleScope.launch {
try {
// These are suspend functions - they suspend, not block
val menuResult = CCAI.queueMenuService?.get()
CCAI.chatService?.start(chatRequest)
val company = CCAI.companyService?.get()
} catch (e: Exception) {
handleError(e)
}
}
Abläufe im Chat-Dienst
Die chatService stellt Kotlin-SharedFlow-Properties zum Beobachten von Echtzeit-Chat-Ereignissen bereit. Erfassen Sie sie in einem lebenszyklusbezogenen Coroutine-Bereich (lifecycleScope oder viewModelScope).
| Flow | Emittiert |
|---|---|
messagesReceived |
Listen mit eingehenden Chatnachrichten (von Kundenservicemitarbeitern, virtuellen Assistenten oder dem System). |
typingEvent |
Wenn ein Nutzer oder ein Kundenservicemitarbeiter tippt. |
memberEvent |
Wenn ein Nutzer oder ein KI-Agent dem Chat beitritt oder ihn verlässt (einschließlich Agentenübertragungen und Trennungen). |
stateChanged |
Statusänderungen des Chatanbieters (Verbindung wird hergestellt, verbunden, getrennt, Fehler). |
chatReceived |
Daten zu Chat-Antworten, wenn ein Chat empfangen oder aktualisiert wird (einschließlich Statusänderungen, Zuweisung von Kundenservicemitarbeitern und Status nach der Sitzung). |
Die chatService stellt zusätzliche Abläufe für Übertragungsereignisse (transferEventSubject), Statusprüfergebnisse (checkStatusSubject) und Ergebnisse des Nachrichtenversands (messageSendResultSubject) bereit.
Implementierungsbeispiel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.distinctUntilChanged
// 1. Incoming messages
lifecycleScope.launch {
CCAI.chatService?.messagesReceived?.collect { messages ->
for (message in messages) {
renderIncomingMessage(message)
}
}
}
// 2. Typing indicators
lifecycleScope.launch {
CCAI.chatService?.typingEvent?.collect { event ->
when (event) {
is ChatTypingEvent.Started -> showTypingIndicator()
is ChatTypingEvent.Ended -> hideTypingIndicator()
}
}
}
// 3. Member join/leave
lifecycleScope.launch {
CCAI.chatService?.memberEvent?.collect { event ->
when (event) {
is MemberEvent.Joined -> Log.d("Chat", "Member joined")
is MemberEvent.Left -> Log.d("Chat", "Member left")
}
// Refresh chat status after member changes
try { CCAI.chatService?.checkStatus() } catch (_: Exception) {}
}
}
// 4. Chat provider state changes
lifecycleScope.launch {
CCAI.chatService?.stateChanged?.distinctUntilChanged()?.collect { state ->
// Update UI based on connection state (examples: connecting, connected)
updateConnectionStatus(state)
}
}
// 5. Chat metadata updates (agent assignment, status changes)
lifecycleScope.launch {
CCAI.chatService?.chatReceived?.collect { chat ->
Log.d("Chat", "Received chat update: ${chat.id}")
updateAgentInfo(chat)
handlePostSessionIfNeeded(chat)
}
}
Status der Bildschirmfreigabe
Funktionen des SDK: Der Status der Bildschirmfreigabesitzung wird über den onSessionStateChanged-Callback für ScreenShareCallbacks bereitgestellt, den Sie an ScreenShareManager.startSession() übergeben. Weitere Informationen finden Sie unter Headless Mobile SDK for Android: Voice, screen share, scheduled call, and email. Der Callback wird immer dann ausgelöst, wenn die Sitzung zwischen INACTIVE, PENDING und ACTIVE wechselt.
Was Sie erstellen: Ein Handler, der in ScreenShareCallbacks.onSessionStateChanged eingebunden ist und die Benutzeroberfläche aktualisiert, wenn die Sitzung zwischen den Status wechselt, sowie eine lokale Eigenschaft (z. B. currentScreenShareSessionState), wenn Sie den aktuellen Status außerhalb des Callbacks lesen müssen.
Implementierungsbeispiel
Zusätzlich zum Pfad ScreenShareCallbacks stellt ScreenShareManager auch eigenständige addStateChangeListener- und removeStateChangeListener-APIs sowie einen synchronen getSessionState()-Accessor zur Verfügung. Verwenden Sie diese, wenn Sie den Status einer anderen Komponente als der, die startSession() aufgerufen hat, beobachten oder einen einmaligen nicht reaktiven Lesevorgang ausführen müssen. Im Gegensatz zum ScreenShareCallbacks-Pfad, bei dem der Callback automatisch freigegeben wird, wenn die Sitzung endet, werden eigenständige Listener nicht automatisch freigegeben. Rufen Sie removeStateChangeListener(...) im Teardown des Lifecycle-Inhabers auf, um Lecks zu vermeiden.
// Register a state change listener
val listener: (ScreenShareSessionState) -> Unit = { state ->
when (state) {
ScreenShareSessionState.INACTIVE -> Log.d("ScreenShare", "No active session")
ScreenShareSessionState.PENDING -> Log.d("ScreenShare", "Session pending")
ScreenShareSessionState.ACTIVE -> Log.d("ScreenShare", "Session active")
}
}
ScreenShareManager.addStateChangeListener(listener)
// Get the current state directly (not reactive)
val currentState = ScreenShareManager.getSessionState()
// Clean up when done
ScreenShareManager.removeStateChangeListener(listener)
Benutzerdefinierte Daten
Funktionen des SDK: Ein Mechanismus zum Anhängen strukturierter Metadaten an Chatsitzungen, entweder als signierte JWTs (von Ihrem Backend überprüft) oder als unsignierte Nutzlasten (direkt im Client festgelegt).
Was Sie entwickeln: Die Logik für die Datenerhebung in Ihrer App und, für signierte Daten, den JWT-Signierungsendpunkt auf Ihrem Backend-Server (das vollständige Authentifizierungs- und JWT-Nutzlastschema finden Sie unter Headless Mobile SDK for Android: Get started).
Signierte benutzerdefinierte Daten
Für signierte benutzerdefinierte Daten wird ein JWT-Token verwendet, das mit dem Unternehmens-Secret auf Ihrem Backend-Server signiert ist. Dies ist der sichere Ansatz zum Übergeben vertraulicher oder vertrauenswürdiger Daten.
Implementierungsbeispiel
Signiertes benutzerdefiniertes Datenobjekt aus einem in Ihrem Backend generierten JWT erstellen
// JWT signed with company secret (signing must happen on your backend)
val customData = CustomData(signed = "header.payload.signature")
Nicht signierte benutzerdefinierte Daten
Nicht signierte benutzerdefinierte Daten werden direkt im Client mit CustomDataPayload und CustomDataItem festgelegt.
Implementierungsbeispiel
Erstellen Sie eine unsignierte Nutzlast mit sichtbaren und agentenverborgenen Datenelementen. CustomDataPayload akzeptiert MutableMap<String, CustomDataItem?>. Verwenden Sie daher die Zuweisung von Unterindizes (oder mutableMapOf), um jedes Element nach Schlüssel hinzuzufügen. Der von Ihnen ausgewählte Schlüssel (z. B. "user_name" oder "account_tier") wird zum Feldnamen, der dem Kundenservicemitarbeiter und für das Routing/die Analyse angezeigt wird.
val items = mutableMapOf<String, CustomDataItem?>()
items["user_name"] = CustomDataItem(
label = "Name",
value = "John"
)
items["user_age"] = CustomDataItem(
label = "Age",
value = 30,
type = CustomDataType.NUMBER,
invisibleToAgent = true
)
val payload = CustomDataPayload(items = items)
val customData = CustomData(unsigned = payload)
Benutzerdefinierte Datenelemente unterstützen die folgenden Eigenschaften:
label: Das Label, das dem Agenten angezeigt wird.value: Der Datenwert (Beispiele:String,Int,Bool).type: Datentyp (STRING,NUMBER,DATE,URL,BOOLEAN).invisibleToAgent: Wenntrue, werden die Daten vor Kundenservicemitarbeitern verborgen, sind aber für das Routing und die Analyse verfügbar.
Benutzerdefinierte Daten in Chatanfragen verwenden
Beim Starten einer Chatsitzung benutzerdefinierte Daten anhängen
Implementierungsbeispiel
val chatRequest = ChatRequest(
chat = Chat(
menuId = 123,
languageCode = "en",
customData = customData
)
)
lifecycleScope.launch {
try {
CCAI.chatService?.start(chatRequest)
// Chat started - observe chat state using chatReceived
} catch (e: Exception) {
Log.e("CCAI", "Failed to start chat: ${e.message}")
}
}
Externen Chat übertragen
Was das SDK bietet: Eine Datenstruktur (ExternalChatTransfer), mit der der Name des vorherigen Agents und das Konversations-Transkript in eine neue CCAI Platform-Sitzung übergeben werden können.
Was Sie entwickeln: Der Migrationsablauf, der Kontext aus Ihrem externen Chatsystem extrahiert und für das SDK verpackt.
Implementierungsbeispiel
Mit diesem Code wird ein externes Chat-Transferobjekt mit dem Namen des vorherigen Kundenservicemitarbeiters erstellt und an die benutzerdefinierten Daten der Sitzung angehängt.
// ExternalChatAgent also accepts an optional `avatar: String? = null` parameter
// for displaying the previous agent's avatar, for example:
// ExternalChatAgent(name = "John Smith", avatar = "https://cdn.example.com/avatars/jsmith.png")
val transfer = ExternalChatTransfer(
agent = ExternalChatAgent(name = "John Smith"),
transcript = emptyList()
)
// Attach to your custom data payload
val payload = CustomDataPayload()
payload.externalChatTransfer = transfer
val customData = CustomData(unsigned = payload)
Das ist nützlich, wenn Sie einen Nutzer von einem Drittanbieter-Chatsystem in eine CCAI Platform-basierte Sitzung migrieren und dabei den Unterhaltungskontext für den empfangenden Kundenservicemitarbeiter beibehalten.
Überlegungen zum Threading
Das Headless Mobile SDK for Android ist für die Verwendung mit Kotlin-Coroutinen konzipiert und ist größtenteils Main-safe. Bei Headless-Integrationen sind jedoch wichtige Aspekte in Bezug auf Threads zu beachten.
Sicherheit im Hauptthread
Alle SDK-Methoden sind threadsicher und können von jedem Thread aus aufgerufen werden. Die meisten SDK-Dienstaufrufe (z. B. chatService?.start(), queueMenuService?.get()) sind Suspend-Funktionen, die ihr eigenes Threading intern verarbeiten. Sie unterbrechen die aufrufende Coroutine, ohne den Thread zu blockieren. Sie können sie sicher aus dem Hauptthread in einem Coroutine-Bereich aufrufen:
// Safe to call from the main thread
lifecycleScope.launch {
val menu = CCAI.queueMenuService?.get() // Suspends, does not block
updateUi(menu) // Back on main thread
}
CCAIDelegate und Hintergrundthreads
Die Methode ccaiShouldAuthenticate() in Ihrem CCAIDelegate ist eine suspend-Funktion, sodass Sie darin sicher Netzwerkaufrufe ausführen können:
override suspend fun ccaiShouldAuthenticate(): String? {
// This runs in a coroutine context - safe to call suspend functions
return withContext(Dispatchers.IO) {
MyBackendApi.getSignedJwt() // Network call on IO dispatcher
}
}
UI-Aktualisierungen über SDK-Callbacks
Wenn Sie SDK-Ereignisse mit Flow beobachten, müssen UI-Aktualisierungen im Hauptthread erfolgen. Wenn Sie lifecycleScope verwenden, wird dies automatisch erledigt:
// lifecycleScope dispatches to Main by default
lifecycleScope.launch {
chatMessagesFlow.collect { messages ->
// Already on Main - safe to update UI
chatAdapter.submitList(messages)
}
}
Wenn Sie Daten von einem Dispatcher erfassen, der nicht der Haupt-Dispatcher ist, müssen Sie explizit zurückwechseln:
lifecycleScope.launch(Dispatchers.IO) {
// Processing on IO thread
val processed = heavyProcessing()
withContext(Dispatchers.Main) {
// Update UI on Main thread
updateChatUi(processed)
}
}
Initialisierungsthreading
CCAI.initialize() und zugehörige Initialisierungsaufrufe für Module wie initializeChat(), initializeCall() und initializeScreenShare() müssen im Hauptthread in Ihrem Application.onCreate() aufgerufen werden. Das sind synchrone Aufrufe, mit denen der interne Zustand des SDK eingerichtet wird.
class MainApplication : Application() {
override fun onCreate() {
super.onCreate() // Always on main thread
// All initialization must happen on main thread
CCAI.initialize(context = this, options = initOptions)
CCAI.initializeChat(context = this, options = ChatOptions())
CCAI.initializeCall(context = this)
}
}
Speicherverwaltung
Ein korrektes Speichermanagement ist unerlässlich, um Lecks zu vermeiden und für eine saubere Bereinigung von SDK-Ressourcen zu sorgen.
Lebenszyklus von Coroutine und Flow
Brechen Sie Coroutinen-Job-Verweise und Flow-Collectoren immer in Android-Lebenszyklusmethoden ab (onDestroy() für Aktivitäten, onCleared() für ViewModels). Andernfalls können Referenzen länger als beabsichtigt aktiv bleiben, was zu Speicherlecks führt.
import kotlinx.coroutines.Job
class ChatViewModel : ViewModel() {
private var chatJob: Job? = null
fun observeChatMessages() {
chatJob = viewModelScope.launch {
CCAI.chatService?.messagesReceived?.collect { messages ->
// Handle new messages
}
}
}
override fun onCleared() {
super.onCleared()
chatJob?.cancel()
}
}
Listener- und Callback-Referenzen
Verwenden Sie schwache Referenzen für Listener und Callbacks, um Retain-Zyklen zu vermeiden. Löschen Sie alle registrierten Callbacks, wenn Ihre Aktivität oder Ihr ViewModel zerstört wird.
class ChatActivity : AppCompatActivity() {
private var chatJob: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
chatJob = lifecycleScope.launch {
CCAI.chatService?.messagesReceived?.collect { messages ->
updateChatUI(messages)
}
}
}
override fun onDestroy() {
super.onDestroy()
chatJob?.cancel()
}
}
Best Practices
Job-Referenzen speichern: Speichern Sie immerJob-Referenzen, die vonlaunch {}zurückgegeben werden, um zu verhindern, dass Coroutinen, die ihren Gültigkeitsbereich überschreiten, weiter ausgeführt werden.Bereinigung in Lebenszyklusmethoden: Brechen Sie alle Jobs ab und löschen Sie alle Callbacks in
onDestroy()(Aktivitäten) oderonCleared()(ViewModels).Weak References für Listener verwenden: Seien Sie vorsichtig mit Lambdas, die
this(den einschließenden Aktivitäts- oder Fragmentkontext) implizit erfassen, da dies die automatische Speicherbereinigung verhindern kann.Dienste werden vom SDK verwaltet: Sie müssen SDK-Dienste nicht manuell freigeben. Sie werden vom Singleton-Objekt
CCAIverwaltet.
Fehlerbehebung
In diesem Abschnitt werden häufige Integrationsprobleme und ihre Lösungen behandelt.
Build- und Abhängigkeitsprobleme
In diesem Abschnitt werden häufige Probleme mit Builds und Abhängigkeiten behandelt.
Problem
Gradle kann com.ccaiplatform.android:CCAIKit nicht auflösen.
Ursache: Das CCAI-Maven-Repository fehlt oder verwendet die falsche URL.
Lösung: Achten Sie darauf, dass Ihr
settings.gradle.ktsFolgendes enthält:maven { url = uri("https://sdk.ujet.co/ccaip/android/") }Beachten Sie das Pfadsegment
/ccaip/. Mit der alten URL (https://sdk.ujet.co/android/) werden keine Artefakte aufgelöst.
Problem
Kompilierungsfehler aufgrund von Java 17
Ursache: Für dieses SDK ist Java 17 erforderlich.
Behebung: Aktualisieren Sie Ihre
build.gradle.kts:compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = "17" }
Problem
chatLibraryNotFound (Fehlercode 1100) zur Laufzeit.
Ursache: Das Modul
CCAIChatRedfehlt in den Abhängigkeiten.Lösung: Für den Chat sind sowohl
CCAIChatals auchCCAIChatRederforderlich. Hinzufügen:implementation("com.ccaiplatform.android:CCAIChat:ccaiVersion") implementation("com.ccaiplatform.android:CCAIChatRed:ccaiVersion")
Initialisierungsprobleme
In diesem Abschnitt werden häufige Initialisierungsprobleme behandelt.
Problem
NullPointerException beim Zugriff auf CCAI.chatService.
Ursache:
CCAI.initializeChat()wurde nicht oder vorCCAI.initialize()aufgerufen.Problembehebung: Achten Sie auf die Initialisierungsreihenfolge in
Application.onCreate():CCAI.initialize(context, options = initOptions)CCAI.initializeChat(context, options = chatOptions)CCAI.initializeCall(context)(bei Verwendung von Sprach- oder geplanten Anrufen)CCAI.initializeScreenShare(context, options)(bei Verwendung der Bildschirmfreigabe)
Problem
SDK-Dienste geben nach der Initialisierung null zurück.
Ursache:
CCAI.initialize()wurde nicht im Hauptthread aufgerufen oder die KlasseApplicationist nicht im Manifest registriert.Beheben: Prüfen Sie, ob die Zeile
android:name=".MainApplication"in Ihrer DateiAndroidManifest.xmlvorhanden ist und ob sich alle Init-Aufrufe inonCreate()befinden.
Authentifizierungsprobleme
In diesem Abschnitt werden häufige Authentifizierungsprobleme behandelt.
Problem
Die Authentifizierung schlägt ohne Fehlermeldung fehl oder ccaiShouldAuthenticate() wird nie aufgerufen.
Ursache:
CCAIDelegatewurde inInitOptionsnicht festgelegt.Problembehebung: Achten Sie darauf, dass
delegateanInitOptionsübergeben wird:val initOptions = InitOptions( key = "YOUR_KEY", urlHost = "your_subdomain.ccaiplatform.com", delegate = MyCCAIDelegate() // Must not be null )
Problem
JWT-Validierungsfehler (Fehlercode 101)
Ursache: Das JWT ist abgelaufen, fehlerhaft oder mit dem falschen Secret signiert.
Behebung: Prüfen Sie, ob Ihr Backend folgende Anforderungen erfüllt:
Der richtige vertrauliche Unternehmenscode wird verwendet.
Legt gültige
iat- undexp-Zeitstempel fest.Gibt einen korrekt formatierten JWT-String zurück.
Probleme mit Push-Benachrichtigungen
In diesem Abschnitt werden häufige Probleme mit Push-Benachrichtigungen behandelt.
Problem
Push-Benachrichtigungen werden nicht empfangen oder verarbeitet.
Ursache: Das FCM-Token ist nicht im SDK registriert, der Firebase-Messaging-Dienst ist nicht registriert oder eingehende Daten-Payloads werden nicht an das SDK weitergeleitet.
Behebung:
Rufen Sie
CCAI.pushNotificationService?.updatePushToken(token)sowohl inonNewToken()als auch beim Start auf.Leiten Sie
remoteMessage.datavon Ihrem Firebase-Messaging-Dienst anCCAI.pushNotificationService?.handlePushNotification(remoteMessage.data)weiter.Prüfen Sie, ob sich
google-services.jsonin Ihrem App-Modul befindet.Prüfen Sie, ob der Firebase-Dienstkontoschlüssel im Administratorportal der CCAI-Plattform konfiguriert ist.
Rendern Sie alle sichtbaren Benachrichtigungen oder Benutzeroberflächen für eingehende Anrufe in Ihrem eigenen App-Code.
Problem
Das SDK reagiert nicht auf eingehende Push-Benachrichtigungen (Nachrichten werden ignoriert).
Ursache: Der
handlePushNotification()-Methode wird der falsche Datentyp übergeben.Korrektur: Achten Sie darauf, dass Sie
remoteMessage.data(eineMap<String, String>) und nicht das gesamteRemoteMessage-Objekt übergeben.
Probleme bei Chatsitzungen
In diesem Abschnitt werden häufige Probleme mit Chatsitzungen behandelt.
Problem
chatService?.start() löst eine Ausnahme aus oder gibt null zurück.
Ursache: Ungültiger
menuId, Authentifizierungsfehler oder Netzwerkproblem.Behebung:
Prüfen Sie, ob
menuIdeiner gültigen Warteschlange in Ihrem Administratorportal entspricht.Prüfen Sie, ob
ccaiShouldAuthenticate()ein gültiges signiertes JWT überCCAI.authService?.authenticate(jwt)austauscht und das resultierende Autorisierungstoken zurückgibt.Prüfen Sie, ob das Gerät eine Netzwerkverbindung hat.
Schließen Sie den Aufruf in einen try- oder catch-Block ein und protokollieren Sie dann die Ausnahmedetails.
Problem
Chatnachrichten werden nicht in der Benutzeroberfläche angezeigt.
Ursache: Der Nachrichtenstream des Chatdienstes wird nicht beobachtet.
Lösung: Achten Sie darauf, dass Sie den Flow des Chatdienstes in einem lebenszyklusbewussten Bereich erfassen (siehe oben im Abschnitt Chatdienst-Flows).
Probleme mit der Bildschirmfreigabe
In diesem Abschnitt werden häufige Probleme bei der Bildschirmfreigabe behandelt.
Problem
Die Bildschirmfreigabe wird nicht gestartet, nachdem der Nutzer die Einwilligung erteilt hat.
Ursache: Das
CCAIScreenShare-Modul wurde nicht initialisiert oder AndroidMediaProjectionwurde nicht gestartet.Behebung:
Achten Sie darauf, dass
CCAI.initializeScreenShare()mit gültigenScreenShareOptionsaufgerufen wird.Prüfen Sie, ob Sie den
MediaProjectionManagerund den Dienst im Vordergrund von Android nach der Einwilligung korrekt starten.Achten Sie bei Android 14 und höher darauf, dass Ihr Diensttyp im Vordergrund
mediaProjectionenthält.
Allgemeine Tipps zur Fehlerbehebung
Aktivieren Sie während der Entwicklung das ausführliche Logging, um den internen SDK-Status zu sehen.
Prüfen Sie im Administratorportal von CCAI Platform die Warteschlangenkonfiguration, die Aktivierung von Channels und die Betriebszeiten.
Überwachen Sie den Netzwerkverkehr mit Tools wie Charles Proxy oder dem Network Inspector von Android Studio, um API-Aufrufe an
*.ccaiplatform.comzu prüfen.Modulversionen prüfen – alle
com.ccaiplatform.android-Module sollten dieselbe Versionsnummer verwenden, um Kompatibilitätsprobleme zu vermeiden.
Zusammenfassung der Reihe
Herzlichen Glückwunsch! Sie haben die fünfteilige Reihe zum Headless Mobile SDK für Android abgeschlossen. Ihre Integration umfasst jetzt Folgendes:
Einrichtung und Initialisierung (Headless Mobile SDK for Android: Erste Schritte)
Warteschlangen, Channels und Chat (Headless Mobile SDK for Android: Queues, channels, and chat)
Sprache, Bildschirmfreigabe, geplanter Anruf und E-Mail (Headless Mobile SDK for Android: Voice, screen share, scheduled call, and email)
Smarte Aktionen, Anhänge und Weiterleitung (Headless Mobile SDK for Android: Smart actions, attachments, and deflection)
Abläufe nach der Sitzung, Lokalisierung, Fehlerbehandlung und erweiterte Themen (dieser Artikel)
Setzen Sie ein Lesezeichen für die Headless Mobile SDK – Android API Reference und behalten Sie die Versionshinweise zur CCAI-Plattform im Blick, um über SDK-Updates informiert zu werden.