Tu app de Android presenta el widget de DobroDesk con estado protegido por cuenta y reintentos explícitos.
Instala el bundle de release de Android
Descarga https://github.com/comstud-io/dobrodesk-mobile-sdk/releases/download/v0.2.0/dobrodesk-mobile-sdk-0.2.0-bundle.tar.gz y extráelo en un directorio estable que no se incluya en el código fuente de la app ni en una carga pública. El archivo contiene el repositorio Maven local en native/maven. Registra ese directorio desde el archivo de configuración del host para que los proyectos Gradle con FAIL_ON_PROJECT_REPOS sigan siendo válidos. Esta versión de Mobile SDK 0.2.0 añade superficies nativas inline y correcciones de wrappers. También incluye la corrección de Android para el almacenamiento protegido. La API pública y el contrato de la UI nativa siguen siendo compatibles.
Se admite Android API 26 y posteriores. Los artefactos base no se descargan de Maven Central. Voice y push usan coordenadas separadas y no deben añadirse salvo que el host también prepare los permisos y proveedores correspondientes.
Usa para el ejemplo Android nativo la combinación probada del host Android directo: Android Gradle Plugin 8.13.2, Kotlin Gradle Plugin 2.2.0, Gradle 8.14.3 y Java 17 con compileSdk 36 y minSdk 26. En otro proyecto Android actual, conserva las versiones generadas por su release de Android o del framework cuando sean compatibles con el SDK.
import org.gradle.api.initialization.resolve.RepositoriesMode
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("<extracted-bundle>/native/maven") }
}
}
// android/app/build.gradle.kts
android {
compileSdk = 36
defaultConfig { minSdk = 26 }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}Declara los tres artefactos base de Android
El repositorio local extraído contiene las coordenadas del motor, del controlador UI y del UI AAR. Declara los tres en el módulo de la app. El wrapper no añade un repositorio a nivel de proyecto ni incluye silenciosamente los módulos opcionales de voz y push.
dependencies {
implementation("com.dobrodesk:dobrodesk-sdk:0.2.0")
implementation("com.dobrodesk:dobrodesk-ui-controller:0.2.0")
implementation("com.dobrodesk:dobrodesk-ui:0.2.0")
}Presenta desde una Activity en primer plano
Las siguientes funciones del host llaman al endpoint de token de tu backend y devuelven el ID estable del cliente actual y su JWT de identidad de corta duración. El SDK solo presenta mientras la Activity está en primer plano.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import com.dobrodesk.sdk.DobroDeskConfiguration
import com.dobrodesk.sdk.ui.DobroDeskAndroidClientFactory
import com.dobrodesk.sdk.ui.DobroDeskWidgetBridgePresenter
import java.time.Duration
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private var presenter: DobroDeskWidgetBridgePresenter? = null
private val client by lazy {
DobroDeskAndroidClientFactory.create(
context = this,
configuration = DobroDeskConfiguration(
apiOrigin = "https://dobrodesk.com",
integrationId = "wgt_0123456789abcdef0123456789abcdef",
accountScope = currentCustomerId(),
credentialProvider = { loadDobroDeskToken() },
pollInterval = Duration.ofSeconds(1),
),
)
}
override fun onCreate(state: Bundle?) {
super.onCreate(state)
lifecycleScope.launch {
presenter = DobroDeskWidgetBridgePresenter.present(
activity = this@MainActivity,
client = client,
options = mapOf("locale" to "en"),
onClosed = { presenter = null },
)
}
}
override fun onDestroy() {
presenter?.detach()
presenter = null
super.onDestroy()
}
}Usar un disparador propio o una superficie integrada
Pasa al suspend helper una Activity visible y un FrameLayout ya conectado a window. El helper crea las opciones JsonObject necesarias, añade handle.view mediante Dispatchers.Main.immediate y cierra el handle si el host se desconecta antes o después del montaje.
El botón propio debe ser accesible con teclado y exponer aria-controls y aria-expanded. Al volver a montar, reutiliza el mismo cliente, la misma sesión y el mismo borrador.
Las API inline forman parte de los artefactos publicados de Mobile SDK 0.2.0. Usa la superficie inline cuando el host controla la ubicación y la presentación modal cuando el host necesita gestionar toda la pantalla.
import android.app.Activity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import com.dobrodesk.sdk.DobroDeskClient
import com.dobrodesk.sdk.ui.DobroDeskWidgetBridgePresenter
import com.dobrodesk.sdk.ui.DobroDeskWidgetEmbeddedHandle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
suspend fun mountSupportPanel(
activity: Activity,
client: DobroDeskClient,
supportContainer: FrameLayout,
): DobroDeskWidgetEmbeddedHandle? {
check(supportContainer.isAttachedToWindow) {
"Attach the support container before mounting the widget"
}
var embeddedHandle: DobroDeskWidgetEmbeddedHandle? = null
val detachListener = object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(view: View) = Unit
override fun onViewDetachedFromWindow(view: View) {
embeddedHandle?.close()
}
}
val handle = DobroDeskWidgetBridgePresenter.createEmbedded(
activity = activity,
client = client,
options = buildJsonObject {
put("locale", "en")
put("view", "home")
},
onClosed = {
supportContainer.removeOnAttachStateChangeListener(detachListener)
embeddedHandle = null
},
)
embeddedHandle = handle
var attached = false
withContext(Dispatchers.Main.immediate) {
if (supportContainer.isAttachedToWindow && !activity.isFinishing && !activity.isDestroyed) {
supportContainer.addView(
handle.view,
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
),
)
supportContainer.addOnAttachStateChangeListener(detachListener)
handle.setVisible(true)
attached = true
}
}
if (!attached) {
handle.close()
return null
}
return handle
}Gestiona el ciclo de vida de Android y la identidad
credentialProvider es una función suspend proporcionada por el host que devuelve un JWT de identidad del cliente de corta duración. El código nativo protege la outbox duradera con Android Keystore y la limita a accountScope. No guardes un support API token en las preferencias de la app.
Llama a presenter.close() cuando se elimine la pantalla host y a client.resetSession() cuando el cliente descarte una conversación. El cliente Android directo no tiene logout: restablécelo, descártalo y crea un cliente nuevo antes de cambiar accountScope. Sin override explícito, el widget sigue la preferencia del sistema para reducir movimiento.
Gestionar carga, visibilidad y accesibilidad
Usa los hooks de carga o los eventos tipados para el estado de la pantalla anfitriona. La superficie muestra por sí misma la carga de mensajes, la espera y los reintentos para evitar un segundo spinner sobre el campo de entrada.
Oculta o muestra la superficie cuando una ruta cambia temporalmente y conserva el cliente. El widget respeta las preferencias del sistema para reducir movimiento. Quitar o cerrar la vista no descarta la sesión ni el borrador.
- Al volver a montar, reutiliza el mismo cliente y dimensiones estables del contenedor.
- Usa la función de visibilidad para ocultar temporalmente, no una función de reinicio de sesión.
- Finaliza la sesión solo al cerrar sesión o cambiar de cuenta de forma intencionada.
Verifica el flujo de Android
- Presenta desde una Activity en primer plano y confirma que los toques repetidos no crean presenters superpuestos.
- Envía un mensaje con un idempotency key estable, pasa la app al segundo plano y vuelve a abrirla. Confirma que el mensaje pendiente se reintenta con la misma clave al volver la red.
- Usa resetSession para un descarte deliberado. Restablece y descarta el cliente Android directo antes de cambiar de cuenta, crea un cliente nuevo y confirma que la siguiente cuenta empieza con una conversación vacía.
