Ir al contenido principal
DocumentacióniOS
Versión 0.2.0iOS 15.1 o posterior

Integra el SDK de iOS de DobroDesk

Añade el Swift Package firmado, crea el cliente nativo y presenta el widget compartido desde un view controller.

En esta página

Tu app de iOS presenta el widget nativo de DobroDesk con estado duradero por cuenta y preferencias de movimiento del sistema.

Añade el Swift Package publicado

En Xcode añade el repositorio https://github.com/comstud-io/dobrodesk-mobile-sdk.git en la versión 0.2.0 y añade DobroDeskSDK y DobroDeskUI al target de la app. El paquete binario admite iOS 15.1 y posteriores. La versión contiene artefactos. No incluye el código fuente de la implementación nativa.

Swift Package
https://github.com/comstud-io/dobrodesk-mobile-sdk.git

Inicializa y presenta el cliente nativo

La app debe proporcionar un JWT de identidad del cliente de corta duración mediante credentialProvider. La autenticación nativa requiere un usuario firmado: usa un backend del host y nunca incluyas un signing secret ni un support API token en la app.

Con la concurrencia estricta de Swift 6, declara el loader del host como un closure @Sendable () async throws -> String y pásalo a credentialProvider.

Presentación en Swift
import Foundation
import UIKit
import DobroDeskSDK
import DobroDeskUI

let loadDobroDeskToken: @Sendable () async throws -> String = {
  // Replace this placeholder with a request to your host backend.
  "short-lived-token-from-host-backend"
}

let client = try DobroDeskClient(
  configuration: DobroDeskConfiguration(
    apiOrigin: URL(string: "https://dobrodesk.com")!,
    integrationId: "wgt_0123456789abcdef0123456789abcdef",
    accountScope: currentCustomer.id,
    locale: "en",
    credentialProvider: loadDobroDeskToken,
    pollInterval: 1
  )
)

try await DobroDeskWidgetBridgePresenter.shared.present(
  client: client,
  options: ["locale": "en"],
  from: viewController
)

Usar un disparador propio o una superficie integrada

Para una superficie integrada, usa un UIView propio con constraints para safeArea top, leading y trailing y un anclaje inferior a keyboardLayoutGuide. Define una altura inicial de 560 puntos con priority .defaultHigh y monta solo después de que la vista esté conectada a window. Crea un presenter propio en cada montaje para que un close fallido o antiguo no cierre otra superficie.

El botón propio debe ser accesible con teclado y exponer aria-controls y aria-expanded. El wrapper del host debe capturar los errores de embed con do/catch y reenviarlos a su propio callback onError tipado para mostrar la recuperación. 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.

Integración integrada
import UIKit
import DobroDeskSDK
import DobroDeskUI

@MainActor
final class SupportPanelHost {
  private let client: DobroDeskClient
  private weak var parent: UIViewController?
  private let onError: (Error) -> Void
  private let supportContainer = UIView()
  private var presenter: DobroDeskWidgetBridgePresenter?
  private var mountTask: Task<Void, Never>?
  private var mountGeneration = 0
  private var isMounted = false

  init(
    client: DobroDeskClient,
    parent: UIViewController,
    onError: @escaping (Error) -> Void
  ) {
    self.client = client
    self.parent = parent
    self.onError = onError
    supportContainer.translatesAutoresizingMaskIntoConstraints = false
    parent.view.addSubview(supportContainer)
    let safeArea = parent.view.safeAreaLayoutGuide
    let keyboardGuide = parent.view.keyboardLayoutGuide
    let height = supportContainer.heightAnchor.constraint(equalToConstant: 560)
    height.priority = .defaultHigh
    NSLayoutConstraint.activate([
      supportContainer.topAnchor.constraint(equalTo: safeArea.topAnchor),
      supportContainer.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
      supportContainer.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
      supportContainer.bottomAnchor.constraint(equalTo: keyboardGuide.topAnchor),
      height,
    ])
  }

  func mountAfterAppearance() {
    guard mountTask == nil, !isMounted, let parent, supportContainer.window != nil else { return }
    mountGeneration += 1
    let generation = mountGeneration
    let mountPresenter = DobroDeskWidgetBridgePresenter()
    let client = self.client
    let supportContainer = self.supportContainer
    presenter = mountPresenter
    mountTask = Task { @MainActor [weak self] in
      defer {
        if let self, self.mountGeneration == generation {
          self.mountTask = nil
        }
      }
      do {
        try await mountPresenter.embed(
          client: client,
          options: ["locale": "en", "view": "home"],
          in: supportContainer,
          parent: parent
        )
        guard let self, self.mountGeneration == generation else {
          mountPresenter.close()
          return
        }
        isMounted = true
      } catch {
        guard let self, self.mountGeneration == generation else { return }
        mountPresenter.close()
        presenter = nil
        onError(error)
      }
    }
  }

  func setVisible(_ visible: Bool) {
    guard isMounted else { return }
    presenter?.setEmbeddedVisible(visible)
  }

  func close() {
    mountGeneration += 1
    mountTask?.cancel()
    mountTask = nil
    presenter?.close()
    presenter = nil
    isMounted = false
  }
}

Mantén explícitos la presentación y el ciclo de la cuenta

Presenta desde un UIViewController en primer plano y llama a close cuando se elimine la pantalla host. Llama a client.resetSession() cuando el cliente descarte intencionadamente la conversación. El cliente iOS directo no tiene logout: restablécelo, descártalo y crea un cliente nuevo antes de cambiar accountScope.

El presenter nativo usa el mismo contrato visual del widget que el widget web. Omite reduceMotion salvo que el cliente haya elegido una opción explícita en la app. La preferencia del sistema para reducir movimiento sigue teniendo prioridad.

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.

  1. Al volver a montar, reutiliza el mismo cliente y dimensiones estables del contenedor.
  2. Usa la función de visibilidad para ocultar temporalmente, no una función de reinicio de sesión.
  3. Finaliza la sesión solo al cerrar sesión o cambiar de cuenta de forma intencionada.

Verifica el flujo de iOS

  1. Abre el widget desde una pantalla en primer plano y confirma que el primer intento no crea un segundo controlador al tocar dos veces el botón.
  2. Inicia una conversación, cierra y vuelve a abrir el widget, y confirma que el borrador y el envío pendiente siguen vinculados a la misma cuenta.
  3. Gira o envía la app al segundo plano durante una operación pendiente y espera el estado explícito de reconexión o reintento antes de probar de nuevo.
  4. Restablece y descarta el cliente iOS directo antes de cambiar de cuenta. Después crea el cliente siguiente y confirma que no puede ver la conversación anterior.

Vista previa de los SDK nativos

Consulta el mismo flujo de soporte con controles nativos de iOS y Android.

Pantalla de chat del SDK nativo de iOS de DobroDesk con un mensaje de soporte, compositor y navegación inferior
SDK de iOS: conversación de soporte con compositor nativo y barra de pestañas.