Skip to main content

SmartComply iOS SDK

Le SmartComply iOS SDK est une bibliothèque native Swift qui offre un flux de vérification d’identité entièrement autonome pour les applications iOS. Intégrez une seule vue SwiftUI et le SDK gère automatiquement la gestion des sessions, la sélection du pays et du type d’identifiant, la capture de documents, la vérification d’identité et la détection de vivacité.

Fonctionnalités

  • Vue SwiftUI prête à l’emploiSmartComplyFlowView gère le flux complet de vérification sans code UI requis
  • Deux modes de vérification — capture photo de document ou saisie de numéro d’identifiant, configurés depuis votre tableau de bord
  • Capture de document avec guide — recadre exactement ce qui se trouve à l’intérieur du cadre de la carte d’identité pour que l’image envoyée au backend soit toujours nette
  • Détection de vivacité — un scan facial passif (clignement plus mouvement naturel de la tête) s’exécute automatiquement après la vérification d’identité, sans invites pas à pas
  • Types d’identifiants dynamiques — les canaux et champs sont récupérés en direct depuis la configuration de votre tableau de bord
  • Support multi-pays — affiche automatiquement un sélecteur de pays lorsqu’un seul pays est configuré
  • Mode sombre et clair — le thème s’adapte au schéma de couleurs système ; surchargez avec preferredColorScheme
  • Retry automatique de téléchargement — les échecs de téléchargement transitoires sont retentés en interne
  • Votre marque, pas la nôtre — le nom, la description, la couleur et le logo proviennent du tableau de bord, et la police est transmise par votre app. Voir Image de marque
  • N’importe quel hôte backend — production, préproduction, ou le vôtre, sans reconstruction

Prérequis

  • iOS 16.0 ou ultérieur
  • Xcode 16 ou ultérieur. L’interface de module de l’XCFramework fourni nomme SwiftUICore dans les signatures publiques, un module qui apparaît pour la première fois dans le SDK iOS 18, donc Xcode 15 ne peut pas le compiler
  • Un appareil physique compatible ARKit face tracking. La vivacité dépend de ARFaceTrackingConfiguration.isSupported, qui couvre les iPhone X et ultérieurs ainsi que les appareils A12 et ultérieurs sans caméra TrueDepth. La vivacité ne peut pas s’exécuter dans le Simulateur

Installation

Le SDK est distribué via Swift Package Manager en tant qu’XCFramework précompilé. Le package que vous ajoutez contient le manifest Swift Package ; Xcode télécharge le binaire automatiquement et l’intègre dans votre app.

Xcode (recommandé)

  1. Ouvrez votre projet dans Xcode
  2. Allez dans File → Add Package Dependencies
  3. Entrez l’URL du dépôt : https://github.com/386konsult/smartcomply-ios-sdk
  4. Sélectionnez Up to Next Major Version et entrez 1.0.3
  5. Cliquez sur Add Package et sélectionnez la bibliothèque SmartComplySDK

Package.swift

La 1.0.3 modifie deux comportements. FlowResult.status contient désormais le vrai verdict, et l’écran de succès ne signifie plus une réussite. Lisez FlowResult avant de passer de la 1.0.2 ou d’une version antérieure. Elle ajoute aussi l’Image de marque et un hôte backend personnalisé.iOS et Android sont versionnés séparément. iOS 1.0.3 et Android 1.0.7 portent le même ensemble de fonctionnalités ; les numéros diffèrent parce que les deux ont toujours suivi leurs propres versions.
L’URL du package est smartcomply-ios-sdk, qui n’est pas la même que le dépôt source du SDK. Il fournit à la fois les tranches appareil et simulateur, donc la même dépendance construit pour un appareil physique et le Simulateur sans configuration supplémentaire.

Configuration de la plateforme

Ajoutez la clé suivante au Info.plist de votre app :
C’est la seule clé de description d’utilisation dont le SDK a besoin. Il n’enregistre pas d’audio, et le contrôle Importer depuis la bibliothèque utilise PHPickerViewController, qui s’exécute en dehors du processus et ne nécessite pas de clé de bibliothèque photo.

Identifiants

Les deux valeurs proviennent de votre tableau de bord Adhere et sont toutes deux permanentes. Réutilisez la même paire pour chaque vérification.
clientId n’est pas une valeur par tentative. Générer votre propre UUID retourne 404 SDK_CONFIG_NOT_FOUND dès le premier appel, car le serveur le résout par rapport à un enregistrement SDK Config existant.

Démarrage rapide

1. Créer l’instance du SDK

Créez une instance SmartComply une fois, par exemple dans votre vue model ou point d’entrée de l’app.
Passez toujours environment explicitement. SDKConfig utilise .sandbox par défaut, qui pointe vers http://localhost:8000 — voir Environnements.

2. Présenter la vue de flux

Intégrez SmartComplyFlowView n’importe où dans votre hiérarchie SwiftUI. Le SDK se charge automatiquement lorsque la vue apparaît.
Le SDK gère automatiquement le flux complet. Les étapes exactes dépendent du mode de vérification configuré dans votre tableau de bord : Mode document (capture photo) :
  1. Crée une session sécurisée
  2. Affiche un écran de bienvenue avec votre logo et les cartes de type d’identifiant
  3. Affiche un sélecteur de pays si plusieurs pays sont configurés
  4. L’utilisateur photographie le recto de son identité dans le cadre guide
  5. Photographie le verso, lorsque le requires_back_side du tableau de bord pour ce type d’identifiant est required ou optional. Sur optional, l’écran de capture affiche aussi un contrôle Ce document n’a pas de verso ; y toucher passe directement au scan de vivacité et l’entrée est soumise sans image du verso. Quand le backend n’envoie aucune valeur, le SDK retombe sur la correspondance du nom du type d’identifiant avec national, driver, resident et voter
  6. Exécute le scan de vivacité passif
  7. Retourne un FlowResult à votre handler de complétion
Mode données (saisie de numéro d’identifiant) :
  1. Crée une session sécurisée
  2. Affiche un écran de bienvenue avec sélection du type d’identifiant
  3. Affiche un sélecteur de pays si plusieurs pays sont configurés
  4. L’utilisateur saisit son numéro d’identifiant et les champs requis
  5. L’identité est vérifiée par rapport à la base de données nationale
  6. Exécute le scan de vivacité passif
  7. Retourne un FlowResult à votre handler de complétion

Images de document

Les photos de document sont plafonnées à 5 Mo côté serveur. Les deux voies, la caméra intégrée au SDK et Importer depuis la bibliothèque, sont réduites à 1280 px sur le bord long et ré-encodées en JPEG à une qualité de 0,72 avant l’envoi, généralement de 150 à 350 Ko, donc une photo de résolution complète depuis un téléphone ne dépasse pas la limite de taille. Avant l’écran de revue, le SDK vérifie que la photo recto montre un visage et un texte lisible : il faut un visage et au moins trois régions de texte. Un échec est un avertissement, pas un blocage. L’utilisateur peut quand même confirmer, car un faux négatif piégerait sinon une personne tenant une identité authentique mais inhabituelle. L’OCR backend est la vérification qui rejette réellement. La photo du verso n’est pas vérifiée.

Environnements

.sandbox cible un serveur exécuté sur l’appareil lui-même, pour le développement backend local. Ce n’est pas un environnement de test hébergé. Utilisez .production pour tout travail d’intégration.
.sandbox est une cible http:// simple, qu’App Transport Security bloque par défaut. Sans une autorisation explicite, le flux meurt à l’écran de chargement avec une erreur ATS qui ressemble à une panne backend. Si vous en avez réellement besoin, limitez l’exception à localhost plutôt que d’utiliser NSAllowsArbitraryLoads, qui affaiblit chaque connexion que votre app établit.
.production est en HTTPS et n’a besoin de rien de tout cela.

Un hôte différent

SDKEnvironment couvre les deux hôtes contre lesquels vous compilez, et l’un d’eux est en boucle sur l’appareil. Pour tout le reste — un déploiement de préproduction ou un build QA qui doit atteindre plus d’un backend sans être reconstruit —, remplacez-le. Ajouté en 1.0.3.
Une barre oblique finale est supprimée, et une valeur vide retombe sur environment plutôt que d’être traitée comme un hôte, donc un build qui lit cela depuis un champ vide n’envoie pas de vérifications vers une URL relative.

Image de marque

Le flux porte votre marque, pas celle d’Adhere. La couleur et le logo proviennent de la SDK Config sur le tableau de bord, donc ils changent sans publication d’app, et votre nom s’affiche pendant la préparation de la session. La police est la seule exception et est transmise par l’hôte. Le titre et le sous-titre de bienvenue sont du contenu SDK fixe : « Verify Your Identity », puis une ligne parmi deux selon le mode de vérification. Téléchargez-le sous Settings → Integrations → SDK → Brand Details. PNG, JPEG ou WebP, jusqu’à 512 Ko et 1024x1024 pixels. Requiert la 1.0.3. Il est dessiné seul, sans boîte ni bordure derrière lui, et contraint par la hauteur plutôt que d’être recadré en carré pour qu’un wordmark reste lisible. Seul le bouclier de repli du SDK s’affiche dans un cadre teinté. Le logo appartient à la SDK Config, pas à l’entreprise. Une branche exploitant plusieurs configs pour différents produits donne à chacune sa propre marque, et une config sans logo affiche le bouclier du SDK plutôt que de retomber sur le logo de l’entreprise sur votre page de profil. Si vous voulez la même marque partout, téléchargez-la dans chaque config.
Un logo ne retarde ni ne bloque jamais une vérification. Le SDK le récupère après que l’écran de bienvenue est déjà affiché, avec un budget de trois secondes, et conserve son propre bouclier si la récupération échoue. Il est aussi décodé sous un plafond de pixels, donc une image surdimensionnée ne peut pas épuiser la mémoire de l’appareil.
Le logo est rendu par les SDK iOS et Android. Le Web SDK ne l’affiche pas encore, donc une config utilisée par les deux portera votre marque sur mobile et la valeur par défaut sur le web.

Police

Transmise par votre app, car le SDK n’embarque ni ne télécharge de fichiers de police : votre chargement, mise en cache et licence restent les vôtres. Requiert la 1.0.3. Une graisse répertoriée sous UIAppFonts, ou enregistrée à l’exécution, est disponible à l’échelle du processus, donc le SDK n’a besoin que de son nom PostScript.
Les noms sont par graisse car Font.custom(_:size:) sélectionne une graisse par nom et ne prend pas d’argument de poids, donc un seul nom rendrait chaque écran en une seule graisse. Seul regular est requis ; tout ce qui est omis retombe sur le nom le plus proche que vous avez fourni.
Un nom non enregistré journalise un avertissement sous le sous-système com.smartcomply.sdk et retombe sur la police système plutôt que de rendre vide. Dynamic Type s’applique de toute façon.

Vivacité

Deux actions sont tirées de .blink et .turnHead en ordre aléatoire et détectées passivement. Les deux sont surveillées à chaque image, aucune n’est nommée à l’utilisateur, et le HUD ne rapporte que combien sont terminées : il n’y a pas de séquence guidée. Le lacet de la tête est mesuré par rapport au téléphone, pas par rapport au monde, et les images pendant lesquelles l’appareil lui-même tourne ne sont pas créditées : tourner le téléphone ne satisfait pas le défi. Le scan a une limite de 20 secondes.
Atteindre la limite échoue la vérification. Rien n’est téléchargé et rien n’est facturé, et l’utilisateur se voit proposer Réessayer. Les versions précédentes soumettaient quand même et signalaient un succès sans aucune action terminée : si vous êtes en version 1.0.2 ou antérieure, attendez-vous à ce comportement.
La vivacité nécessite une caméra TrueDepth et ne peut pas s’exécuter sur le Simulateur. Testez sur un iPhone X ou ultérieur.

Accessibilité

Depuis la 1.0.3, le flux respecte le paramètre de taille de texte de l’utilisateur (Settings → Accessibility → Display & Text Size → Larger Text). Les versions précédentes utilisaient des tailles de points fixes partout, donc le paramètre n’avait aucun effet sur aucun écran. La mise à l’échelle est limitée à .accessibility1. L’ovale guide, le cadre du document et les boutons sont dimensionnés pour s’adapter à leur contenu, et les tailles d’accessibilité au-dessus de cette limite les débordent : la borne maintient tout en dessous utilisable plutôt que de fournir des mises en page qui cassent en haut de la plage.

Ce que signifie « Vérification terminée »

Rien à voir avec le verdict. Chaque entrée soumise atteint cet écran, que le backend ait réussi ou échoué la vérification. L’appel de soumission retourne processing, car le backend résout la concordance faciale sur un worker moments plus tard. Le SDK interroge pendant environ 15 secondes et met ce qu’il apprend dans FlowResult.status, puis affiche l’écran de succès dans les deux cas. Un utilisateur qui a échoué n’en est pas informé et ne se voit pas proposer de nouvelle tentative. C’est une décision produit, pas un oubli : les clients ont demandé que l’utilisateur final voie une vérification soumise comme acceptée, et qu’ils agissent eux-mêmes sur le vrai verdict depuis le tableau de bord et le webhook. Cela signifie que vous devez boucler la boucle avec un utilisateur qui a échoué. Les échecs avant soumission sont inchangés et affichent toujours l’écran d’échec avec Réessayer : une caméra refusée, une erreur de configuration ou de réseau, et l’atteinte de la limite de 20 secondes de vivacité. Rien n’a été facturé à ce stade et l’utilisateur peut se rétablir sur place.

Savoir que l’utilisateur a abandonné

onComplete ne se déclenche que sur une vérification. Passez le onDismiss optionnel pour savoir que le flux s’est terminé sans vérification : l’utilisateur a fermé l’écran d’échec, ou une erreur n’a laissé rien à retenter. Le passer ajoute également un contrôle Fermer à l’écran d’échec, qui autrement ne propose que Réessayer.

Configuration du SDK

Augmentez requestTimeout si votre flux utilise un canal d’identifiants en mode données.onboarding/verify bloque sur un fournisseur d’identité gouvernemental et tourne sur ce même budget de 30 secondes. Quand il expire côté client, le serveur continue, termine la vérification et la facture, donc vous êtes débité pour une vérification que votre app a signalée comme échouée. L’utilisateur reste sur l’écran de saisie d’identifiant avec une erreur et ressoumet généralement, ce qui facture à nouveau. Passez requestTimeout: 90 lorsqu’un canal de mode données est activé.Contrairement au verifyTimeoutMs d’Android, ce n’est pas spécifique à la vérification. Cela s’applique à chaque appel hors téléchargement, y compris l’interrogation de résultat que le SDK exécute après la soumission, donc une valeur augmentée allonge aussi le pire cas sur l’écran de traitement. C’est le seul levier qu’expose la 1.0.3.

FlowResult

Délivré à votre closure onComplete lorsque l’utilisateur termine le flux dans l’app.
Croisez status. Atteindre onComplete n’est pas une réussite.Depuis la 1.0.3, le SDK interroge le backend pour le résultat terminal et le place ici, donc "passed" signifie réussi et "failed" signifie échoué. Mais chaque entrée soumise montre à l’utilisateur final l’écran de succès, y compris une entrée échouée. C’est délibéré et demandé : les clients voulaient que leur utilisateur voie une vérification soumise comme acceptée et qu’ils lisent eux-mêmes le vrai verdict. L’écran est neutre-positif ; cette valeur ne l’est pas.Donc onComplete qui se déclenche avec un status de "failed" est un résultat normal que vous devez gérer. Un code qui traite onComplete comme une réussite admettra des utilisateurs qui ont échoué la vérification."processing" signifie que le backend n’a pas résolu en environ 15 secondes. L’entrée existe et est facturée, et le résultat arrive sur votre webhook.Sur la 1.0.2 et antérieure, status était toujours "processing" et ne portait aucun verdict, donc le résultat était un reçu de soumission.
verifiedName et idNumber sont renseignés depuis l’interrogation ainsi que depuis la soumission, depuis la 1.0.3. En mode document, ils n’apparaissaient auparavant que lorsque l’OCR finissait avant que l’utilisateur termine la vivacité, donc savoir si un utilisateur voyait son propre nom relevait du timing.
verifiedName et idNumber sont toujours nil sur la 1.0.1 et antérieure, dans les deux modes de vérification. Si vous êtes fixé sur l’une de ces versions, lisez l’identité vérifiée depuis le payload du webhook à la place et ne construisez pas d’UI qui dépend de ces deux propriétés. Mettez à jour vers la 1.0.3.
Depuis la 1.0.2, les deux sont remplis. En vérification de document, ils proviennent de l’OCR du document capturé ; en vérification de données, ils proviennent de la réponse du fournisseur d’identité. verifiedName est le nom complet lorsque le fournisseur en envoie un, sinon il est composé à partir des champs de prénom, deuxième prénom et nom de famille.Ils ne sont toujours aussi bons que la soumission qui les a produits, donc traitez-les comme un reçu de ce qui a été lu, pas comme un verdict. Le webhook reste la source de vérité pour le résultat final.
Le webhook est toujours le système d’enregistrement. Le statut d’une entrée passe par pending, processing, puis passed, failed ou expired, et le statut final, les champs extraits et toute raison d’échec sont délivrés à l’URL du webhook configurée sur votre SDK Config. Voir Webhooks pour le payload complet.Ce qui a changé en 1.0.3, c’est que onComplete ne se déclenche plus avant ce verdict. Il attend que le backend atteigne un statut terminal, donc status est en accord avec ce que le webhook dira. Réconciliez à partir du webhook pour tout ce que vous persistez : un processus qui n’a pas résolu en environ 15 secondes retourne toujours "processing".

Gestion des erreurs

SmartComplyFlowView gère et affiche les états d’erreur automatiquement. Pour l’API headless, toutes les méthodes du SDK lancent des erreurs en cas d’échec :
SDKError expose message: String, statusCode: Int et errorCode: String?. AuthError, NetworkError et AlreadySubmittedError sont tous des sous-classes, donc un seul catch let error as SDKError couvre tous les cas.
Depuis la 1.0.3, l’erreur porte le propre code du backend. errorCode était auparavant codé en dur à AUTH_ERROR pour chaque 401 et 403, donc SDK_CONFIG_NOT_FOUND, une session expirée et une clé invalide étaient indiscernables et la logique hôte basée sur le code ne pouvait pas fonctionner. Les échecs de validation signalaient également uniquement le générique "One or more fields failed validation." ; la raison par champ est désormais exposée.AlreadySubmittedError est levé lorsqu’un retry de téléchargement est rejeté comme doublon, ce qui signifie que la tentative initiale a atteint le serveur et que l’entrée existe et a été facturée : la réponse a simplement été perdue au retour. Le flux intégré le traite comme tel et lit le résultat plutôt que de signaler un échec. Gérez-le de la même manière si vous pilotez les modules vous-même.