Votre app iOS présente le widget natif DobroDesk avec un état durable lié au compte et les préférences système de mouvement.
Ajouter le Swift Package publié
Dans Xcode, ajoutez le dépôt https://github.com/comstud-io/dobrodesk-mobile-sdk.git à la release 0.2.0 et ajoutez DobroDeskSDK et DobroDeskUI à la cible de l'app. Le package binaire prend en charge iOS 15.1 et les versions ultérieures. Cette release contient seulement des artefacts. Le code source de l'implémentation native n'est pas inclus.
https://github.com/comstud-io/dobrodesk-mobile-sdk.gitInitialiser et présenter le client natif
L'app doit fournir un JWT d'identité client de courte durée via credentialProvider. L'authentification native exige un utilisateur signé : utilisez un backend de l'hôte et ne livrez jamais le signing secret ni un support API token dans l'app.
Avec la concurrence stricte de Swift 6, déclarez le loader de l'hôte comme une closure @Sendable () async throws -> String et transmettez cette closure à credentialProvider.
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
)Utiliser un déclencheur personnalisé ou une surface intégrée
Pour une surface intégrée, utilisez un UIView dédié avec des contraintes vers safeArea top, leading et trailing ainsi qu'un ancrage inférieur sur keyboardLayoutGuide. Définissez une hauteur initiale de 560 points avec priority .defaultHigh et montez la vue seulement après sa connexion à window. Créez un presenter propre à chaque montage afin qu'un close échoué ou obsolète ne ferme pas une autre surface.
Le bouton personnalisé doit rester accessible au clavier et exposer aria-controls ainsi que aria-expanded. Le wrapper de l'hôte doit intercepter les erreurs de embed avec do/catch et les transmettre à son propre callback onError typé pour l'interface de récupération. Lors d'un nouveau montage, réutilisez le même client, la même session et le même brouillon.
Les API inline font partie des artefacts publiés de Mobile SDK 0.2.0. Utilisez la surface inline lorsque l'hôte contrôle son placement et la présentation modale lorsque l'hôte doit gérer tout l'écran.
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
}
}Garder la présentation et le cycle du compte explicites
Présentez depuis un UIViewController au premier plan et appelez close lorsque l'écran hôte est détruit. Appelez client.resetSession() lorsque le client abandonne volontairement la conversation. Le client iOS direct ne possède pas logout : réinitialisez-le, détruisez-le et créez un nouveau client avant de changer accountScope.
Le presenter natif utilise le même contrat d'apparence que le widget web. Omettez reduceMotion sauf si le client a choisi un réglage explicite dans l'app. Le réglage système de réduction des mouvements reste prioritaire.
Gérer le chargement, la visibilité et l'accessibilité
Utilisez les hooks de chargement ou les événements typés pour l'état de l'écran hôte. La surface affiche elle-même le chargement des messages, l'attente et les nouvelles tentatives afin d'éviter un second indicateur sur le champ de saisie.
Masquez ou affichez la surface lors d'une navigation temporaire en conservant le client. Le widget respecte les préférences système de réduction des mouvements. Le retrait ou la fermeture ne supprime ni la session ni le brouillon.
- Lors du nouveau montage, réutilisez le même client et des dimensions stables pour le conteneur.
- Utilisez la fonction de visibilité pour un masquage temporaire, sans réinitialiser la session.
- Terminez la session uniquement lors de la déconnexion ou d'un changement de compte volontaire.
Vérifier le flux iOS
- Ouvrez le widget depuis un écran au premier plan et confirmez qu'un double appui sur le bouton ne crée pas de second contrôleur.
- Démarrez une conversation, fermez puis rouvrez le widget et confirmez que le brouillon et l'envoi en attente restent liés au même compte.
- Faites pivoter ou mettez l'app en arrière-plan pendant une opération en attente et attendez l'état explicite de reconnexion ou de nouvelle tentative avant de recommencer.
- Réinitialisez et détruisez le client iOS direct avant de changer de compte. Créez ensuite le client suivant et confirmez qu'il ne peut pas voir la conversation précédente.
