# Guide de migration du SDK Terminal Découvrez comment migrer vers la version 5.0.0 du SDK Stripe Terminal. Les SDK Stripe Terminal pour iOS et Android ont été mis à jour avec un certain nombre de changements majeurs au niveau des API et du comportement, dont certains nécessitent que vous mettiez à jour votre intégration avec le SDK Stripe Terminal. Nous apportons régulièrement des modifications aux mises à jour de versions majeures susceptibles d’affecter le fonctionnement ou le comportement de votre intégration, afin d’améliorer la cohérence entre nos SDK et de simplifier la logique et l’intégration de votre application. Ce guide vous présente les dernières modifications pour vous aider à mettre à niveau votre intégration. > Vous créez une nouvelle intégration à Stripe Terminal ? Consultez la page [Conception d’une intégration](https://docs.stripe.com/terminal/designing-integration.md) pour savoir quelles sont les premières étapes. ## Migrer vers la version 5.0.0 Voici les éléments à retenir concernant les SDK de Stripe Terminal pour iOS et Android : - Intégration simplifiée des paiements - Traitez les paiements, configurez les intentions et effectuez les remboursements à l’aide d’un seul appel de méthode combinant les étapes de collecte et de confirmation. - Prend en charge les variantes asynchrones modernes de Swift et les coroutines Kotlin pour simplifier les flux asynchrones complexes - Concurrence Swift (async/await) pour iOS et Kotlin Coroutines pour Android. - Annulation par le client activée par défaut - Sur les lecteurs pris en charge, les clients peuvent désormais annuler les transactions par défaut pendant les flux de paiement, de configuration, de remboursement et de collecte de données. - Amélioration de l’observabilité de la reconnexion automatique du lecteur mobile et du lecteur Tap to Pay - Gestion améliorée de la reconnexion automatique des lecteurs avec davantage d’états de connexion pour les lecteurs mobiles (Bluetooth et USB) et les lecteurs Tap to Pay. - Découvrez la prise en charge des cartes acceptées pour Tap to Pay sur Android (Aperçu public) - Acceptez les paiements par carte Discover avec Tap to Pay sur Android. - Mises à jour vers les versions minimales des plateformes prises en charge pour iOS 14.0 et iOS 15.0 # iOS > This is a iOS for when terminal-sdk-platform is ios. View the full page at https://docs.stripe.com/terminal/references/sdk-migration-guide?terminal-sdk-platform=ios. Si votre application utilise actuellement une version du SDK Terminal iOS antérieure à la version 5.0.0, vous devez effectuer plusieurs modifications pour la mettre à niveau. Pour obtenir la liste détaillée des modifications apportées entre les versions 4.x et 5.0.0, consultez le journal des [modifications du SDK](https://github.com/stripe/stripe-terminal-ios/blob/master/CHANGELOG.md). ## Mettez à jour votre version minimale prise en charge vers iOS 15 ou une version plus récente Nous mettons régulièrement à jour la version minimale prise en charge de nos SDK afin de rationaliser nos efforts de support aux développeurs. Les versions 4.X existantes du SDK Terminal iOS continueront de prendre en charge les appareils exécutant *iOS 14* et versions ultérieures. ## Intégration simplifiée des paiements ### Mise à jour vers le traitement des paiements unifié Le SDK v5 comprend des méthodes qui combinent les étapes collecter et confirmer en une seule opération. Bien que les méthodes `collectPaymentMethod` et `confirmPaymentIntent` existantes continuent de fonctionner, nous vous recommandons d’utiliser les méthodes unifiées pour des intégrations plus simples. #### Traitement des paiements avec processPaymentIntent Remplacer les étapes collecter et confirmer en deux temps par un appel de méthode `processPaymentIntent` unique. _Avant _ #### Swift ```swift // Step 1: Collect payment method Terminal.shared.collectPaymentMethod(paymentIntent, collectConfig: collectConfig) { collectedPaymentIntent, collectError in guard let collectedPaymentIntent = collectedPaymentIntent else { // Payment method collection failed return } // Step 2: Confirm the payment Terminal.shared.confirmPaymentIntent(collectedPaymentIntent) { confirmedPaymentIntent, confirmError in if let confirmedPaymentIntent = confirmedPaymentIntent { // Payment successful } else { // Payment confirmation failed } } } ``` _Après _ #### Swift ```swift // Process and confirm the payment in one step Terminal.shared.processPaymentIntent(paymentIntent, collectConfig: collectConfig) { processedPaymentIntent, processError in if let processedPaymentIntent = processedPaymentIntent { // Payment successful } else { // Payment failed } } ``` #### Traitement des remboursements avec processRefund Les méthodes `collectRefundPaymentMethod` et `confirmRefund` sont désormais obsolètes. Utilisez plutôt `processRefund`. _Avant _ #### Swift ```swift // Step 1: Collect refund payment method Terminal.shared.collectRefundPaymentMethod(refundParams) { collectError in guard collectError == nil else { // Refund collection failed return } // Step 2: Confirm the refund Terminal.shared.confirmRefund { refund, confirmError in if let refund = refund { // Refund successful } else { // Refund confirmation failed } } } ``` _Après _ #### Swift ```swift // Process the refund in one step Terminal.shared.processRefund(refundParams) { refund, refundError in if let refund = refund { // Refund successful } else { // Refund failed } } ``` #### Traitement des SetupIntents avec processSetupIntent Remplacer les étapes collecter et confirmer en deux temps par un appel de méthode `processSetupIntent` unique. _Avant _ #### Swift ```swift // Step 1: Collect setup intent payment method Terminal.shared.collectSetupIntentPaymentMethod(setupIntent, customerConsentCollected: true) { collectedSetupIntent, collectError in guard let collectedSetupIntent = collectedSetupIntent else { // Setup intent collection failed return } // Step 2: Confirm the setup intent Terminal.shared.confirmSetupIntent(collectedSetupIntent) { confirmedSetupIntent, confirmError in if let confirmedSetupIntent = confirmedSetupIntent { // Setup intent successful } else { // Setup intent confirmation failed } } } ``` _Après _ #### Swift ```swift // Configure with allowRedisplay let config = try CollectSetupIntentConfigurationBuilder() .setAllowRedisplay(.always) .build() // Process the setup intent in one step Terminal.shared.processSetupIntent(setupIntent, collectConfig: config) { processedSetupIntent, setupError in if let processedSetupIntent = processedSetupIntent { // Setup intent successful } else { // Setup intent failed } } ``` ### Prise en charge de la variante asynchrone Swift Le SDK fournit désormais des variantes asynchrones pour les méthodes Terminal. Vous pouvez écrire un code plus propre et séquentiel au lieu d’imbriquer des gestionnaires de complétion. _Avant _ ```swift let cancelable = Terminal.shared.collectPaymentMethod(paymentIntent, collectConfig: collectConfig) { collectedPaymentIntent, collectError in guard let collectedPaymentIntent = collectedPaymentIntent else { // Payment method collection failed return } Terminal.shared.confirmPaymentIntent(collectedPaymentIntent) { confirmedPaymentIntent, confirmError in // Handle confirmation } } ``` _Après _ ```swift let collectTask = Task { do { let collectedIntent = try await Terminal.shared.collectPaymentMethod(paymentIntent, collectConfig: collectConfig) let confirmedIntent = try await Terminal.shared.confirmPaymentIntent(collectedIntent) // Payment successful } catch { // Handle error } } // Use collectTask.cancel() to cancel the operation when needed ``` ## Plateforme et initialisation ### Mise à jour Initialisation du terminal La méthode `setTokenProvider` a été supprimée. Vous devez maintenant initialiser le SDK avec la méthode statique `Terminal.initWithTokenProvider(_tokenProvider:)` avant d’accéder au singleton `Terminal.shared`. _Avant _ #### Swift ```swift // In your AppDelegate or scene delegate Terminal.setTokenProvider(yourTokenProvider) ``` _Après _ #### Swift ```swift // In your AppDelegate or scene delegate, at app launch Terminal.initWithTokenProvider(yourTokenProvider) ``` ## Détection et connexion du lecteur ### Mise à jour de l’initialisation de DiscoveryConfiguration Vous ne pouvez plus initialiser les objets `DiscoveryConfiguration` directement avec `Init` ou `New`. Vous devez désormais utiliser leurs classes de génération associées. _Avant _ #### Swift ```swift let config = SCPInternetDiscoveryConfiguration(isSimulated: true) ``` _Après _ #### Swift ```swift let config = InternetDiscoveryConfiguration.Builder() .setSimulated(true) .build() ``` ### Gérer les changements d’état de reconnexion Une nouvelle valeur `.reconnecting` a été ajoutée à l’énumération `ConnectionStatus`. Lors d’une reconnexion, `Terminal.shared.connectedReader` aura désormais une valeur `null` jusqu’à ce que la reconnexion aboutisse. _Avant _ #### Swift ```swift func terminal(_ terminal: Terminal, didChange connectionStatus: ConnectionStatus) { switch connectionStatus { case .notConnected: // Handle not connected case .connected: // Handle connected @unknown default: break } } ``` _Après _ #### Swift ```swift func terminal(_ terminal: Terminal, didChange connectionStatus: ConnectionStatus) { switch connectionStatus { case .notConnected: // Handle not connected case .connected: // Handle connected case .reconnecting: // Handle reconnection in progress @unknown default: break } } ``` ### Connexion simplifiée avec easyConnect Pour les lecteurs intelligents, Tap to Pay et les intégrations d’applications sur appareils utilisant le SDK iOS 5.1 ou une version plus récente, vous pouvez désormais utiliser `Terminal.shared.easyConnect`, qui combine la détection et la connexion en un seul appel de méthode. _Avant _ #### Swift ```swift // Step 1: Discover the reader Terminal.shared.discoverReaders(config, delegate: discoveryDelegate) { error in if let error = error { // Handle discovery error } } // In your DiscoveryDelegate func terminal(_ terminal: Terminal, didUpdateDiscoveredReaders readers: [Reader]) { guard let selectedReader = readers.first else { return } // Step 2: Connect to the reader Terminal.shared.connectReader(selectedReader, connectionConfig: connectionConfig) { reader, error in if let reader = reader { // Handle successful connection } else if let error = error { // Handle connection error } } } ``` _Après _ #### Swift ```swift // Discover and connect in one step by providing discovery filter let discoveryConfig = try InternetDiscoveryConfigurationBuilder() .setLocationId("tml_1234567890") // optional, specify your location ID .setDiscoveryFilter(.bySerial("YOUR-READER-SERIAL-NUMBER")) .build() let connectionConfig = try InternetConnectionConfigurationBuilder() .setFailIfInUse(false) .build() let easyConnectConfig = InternetEasyConnectConfiguration( discoveryConfiguration: discoveryConfig, connectionConfiguration: connectionConfig ) Terminal.shared.easyConnect( easyConnectConfig, delegate: internetReaderDelegate ) { reader, error in if let reader = reader { // Handle successful connection } else if let error = error { // Handle failure } } ``` ### Filtrage de détection lecteur Internet La détection des lecteurs Internet prend désormais en charge le filtrage par ID de lecteur ou numéro de série. Définissez la propriété `discoveryFilter` dans `InternetDiscoveryConfigurationBuilder` pour découvrir un lecteur spécifique. _Avant _ #### Swift ```swift let config = InternetDiscoveryConfigurationBuilder() .setLocationId("tml_1234567890") .build() ``` _Après _ #### Swift ```swift let config = try InternetDiscoveryConfigurationBuilder() .setLocationId("tml_1234567890") // optional .setDiscoveryFilter(.bySerial("READER-SERIAL-NUMBER")) // or .byReaderId("tmr_YOUR-READER-STRIPE-ID") to filter by reader id .build() ``` ## Acceptation des paiements et recouvrement des données ### L’annulation par le client est désormais activée par défaut. Sur les lecteurs pris en charge, la possibilité pour les clients d’annuler des transactions est désormais *activée par défaut*. La propriété `customerCancellation` est passée d’un état `Bool` à la nouvelle énumération `SCPCustomerCancellation`. _Avant _ #### Swift ```swift let collectConfig = try CollectConfigurationBuilder() .setEnableCustomerCancellation(false) .build() ``` _Après _ #### Swift ```swift let collectConfig = try CollectPaymentIntentConfigurationBuilder() .setCustomerCancellation(.disableIfAvailable) .build() ``` ### Mises à jour des paramètres remboursement Interac Si vous créez des `SCPRefundParameters` pour un remboursement Interac à l’aide d’un ID PaymentIntent, vous devez désormais également transmettre la `clé secrète du client` de la PaymentIntent. Vous pouvez également continuer à utiliser l’ID de facturation, qui ne nécessite pas la `clé secrète du client`. _Avant _ #### Swift ```swift let refundParams = try RefundParametersBuilder( paymentIntentId: "pi_123", amount: 1000, currency: "cad" ).build() ``` _Après _ #### Swift ```swift let refundParams = try RefundParametersBuilder( paymentIntentId: "pi_123", clientSecret: "pi_123_secret_abc", amount: 1000, currency: "cad" ).build() ``` # Android > This is a Android for when terminal-sdk-platform is android. View the full page at https://docs.stripe.com/terminal/references/sdk-migration-guide?terminal-sdk-platform=android. Si votre application utilise actuellement une version du SDK Android Terminal antérieure à la version 5.0.0, vous devez effectuer plusieurs modifications pour la mettre à niveau. Pour obtenir la liste détaillée des modifications apportées entre les versions 4.x et 5.0.0, consultez les [ logs de modifications du SDK](https://github.com/stripe/stripe-terminal-android/blob/master/CHANGELOG.md). ## Intégration simplifiée des paiements ### Mise à jour vers le traitement des paiements unifié Le SDK v5 introduit des méthodes simplifiées qui combinent les étapes collecter et confirmer en une seule opération. Bien que les méthodes `collectPaymentMethod` et `confirmPaymentIntent` existantes continuent de fonctionner, nous vous recommandons d’utiliser les nouvelles méthodes unifiées, pour des intégrations plus simples. #### Traitement des paiements avec processPaymentIntent Remplacer les étapes collecter et confirmer en deux temps par un appel de méthode `processPaymentIntent` unique. _Avant _ #### Kotlin ```kotlin // Step 1: Collect payment method Terminal.getInstance().collectPaymentMethod( paymentIntent, collectConfig, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Step 2: Confirm the payment Terminal.getInstance().confirmPaymentIntent(paymentIntent, object : PaymentIntentCallback { override fun onSuccess(confirmedPaymentIntent: PaymentIntent) { // Payment successful } override fun onFailure(e: TerminalException) { // Payment confirmation failed } }) } override fun onFailure(e: TerminalException) { // Payment method collection failed } } ) ``` _Après _ #### Kotlin ```kotlin // Process and confirm the payment in one step Terminal.getInstance().processPaymentIntent( paymentIntent, collectConfig, confirmConfig, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Payment successful } override fun onFailure(e: TerminalException) { // Payment failed } } ) ``` #### Traitement des remboursements avec processRefund Les méthodes `collectRefundPaymentMethod` et `confirmRefund` sont désormais obsolètes. Utilisez plutôt `processRefund`. _Avant _ #### Kotlin ```kotlin // Step 1: Collect refund payment method val refundParams = RefundParameters.ByChargeId( id = "ch_123", amount = 1000L, currency = "cad" ).build() Terminal.getInstance().collectRefundPaymentMethod( refundParams, object : Callback { override fun onSuccess() { // Step 2: Confirm the refund Terminal.getInstance().confirmRefund(object : RefundCallback { override fun onSuccess(refund: Refund) { // Refund successful } override fun onFailure(e: TerminalException) { // Refund confirmation failed } }) } override fun onFailure(e: TerminalException) { // Refund collection failed } } ) ``` _Après _ #### Kotlin ```kotlin val refundParams = RefundParameters.ByChargeId( id = "ch_123", amount = 1000, currency = "cad" ).build() // Process the refund in one step Terminal.getInstance().processRefund( refundParams, object : RefundCallback { override fun onSuccess(refund: Refund) { // Refund successful } override fun onFailure(e: TerminalException) { // Refund failed } } ) ``` #### Traitement des SetupIntents avec processSetupIntent Remplacer les étapes collecter et confirmer en deux temps par un appel de méthode `processSetupIntent` unique. _Avant _ #### Kotlin ```kotlin // Step 1: Collect setup intent payment method Terminal.getInstance().collectSetupIntentPaymentMethod( intent = setupIntent, allowRedisplay = AllowRedisplay.ALWAYS, callback = object : SetupIntentCallback { override fun onSuccess(setupIntent: SetupIntent) { // Step 2: Confirm the setup intent Terminal.getInstance().confirmSetupIntent(setupIntent, object : SetupIntentCallback { override fun onSuccess(confirmedSetupIntent: SetupIntent) { // Setup intent successful } override fun onFailure(e: TerminalException) { // Setup intent confirmation failed } }) } override fun onFailure(e: TerminalException) { // Setup intent collection failed } } ) ``` _Après _ #### Kotlin ```kotlin // Configure with allowRedisplay val config = CollectSetupIntentConfiguration.Builder() .build() // Process the setup intent in one step Terminal.getInstance().processSetupIntent( intent = setupIntent, allowRedisplay = AllowRedisplay.ALWAYS, collectConfig = config, callback = object : SetupIntentCallback { override fun onSuccess(setupIntent: SetupIntent) { // Setup intent successful } override fun onFailure(e: TerminalException) { // Setup intent failed } } ) ``` ### Prise en charge des coroutines Kotlin Pour les développeurs Kotlin, un nouveau module facultatif `stripeterminal-ktx` fournit des wrappers de fonctions `de suspension` pour les API Terminal asynchrones. > Ajoutez cette dépendance : `implementation(« com.stripe:stripeterminal-ktx:5.0.0 »)` _Avant _ ```kotlin Terminal.getInstance().discoverReaders(config, object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List) { val selectedReader = readers[0] Terminal.getInstance().connectReader(selectedReader, connectionConfig, object : ReaderCallback { override fun onSuccess(reader: Reader) { // Handle successful connection } override fun onFailure(e: TerminalException) { // Handle connection failure } }) } }) ``` _Après _ ```kotlin // Add dependency: implementation("com.stripe:stripeterminal-ktx:5.0.0") coroutineScope { try { val readers = Terminal.getInstance().discoverReaders(discoveryConfig) .filter { it.isNotEmpty() } .first() val selectedReader = readers.first() val reader = Terminal.getInstance().connectReader(selectedReader, connectConfig) // Handle successful connection } catch(e: TerminalException) { // Handle failures on discovery or connect } } ``` ## Plateforme et initialisation ### Mise à jour Initialisation du terminal La méthode `Terminal.initTerminal` a été renommée `Terminal.init`. Elle nécessite désormais un paramètre `OfflineListener` annulable. _Avant _ #### Kotlin ```kotlin Terminal.initTerminal(applicationContext, LogLevel.VERBOSE, tokenProvider, terminalListener) ``` _Après _ #### Kotlin ```kotlin Terminal.init(applicationContext, LogLevel.VERBOSE, tokenProvider, terminalListener, offlineListener) ``` ## Détection et connexion du lecteur ### Gérer les changements d’état de reconnexion Une nouvelle valeur `RECONNECTING` a été ajoutée à l’énumération `ConnectionStatus`. Lors de la connexion initiale`, Terminal.getInstance().getConnectedReader()` aura la valeur `null` jusqu’à ce que la tentative de connexion aboutisse. _Avant _ #### Kotlin ```kotlin override fun onConnectionStatusChange(status: ConnectionStatus) { when (status) { ConnectionStatus.NOT_CONNECTED -> { // Handle not connected } ConnectionStatus.CONNECTED -> { // Handle connected } } } ``` _Après _ #### Kotlin ```kotlin override fun onConnectionStatusChange(status: ConnectionStatus) { when (status) { ConnectionStatus.NOT_CONNECTED -> { // Handle not connected } ConnectionStatus.CONNECTED -> { // Handle connected } ConnectionStatus.RECONNECTING -> { // Handle reconnection in progress } } } ``` ### Connexion simplifiée avec easyConnect Pour les lecteurs intelligents, Tap to Pay et les intégrations d’applications sur appareils, vous pouvez désormais utiliser `Terminal.easyConnect`, qui combine la détection et la connexion en un seul appel de méthode. _Avant _ #### Kotlin ```kotlin // Step 1: Discover the reader Terminal.getInstance().discoverReaders(config, object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List) { val selectedReader = readers[0] // Step 2: Connect to the reader Terminal.getInstance().connectReader(selectedReader, connectionConfig, readerCallback) } }) ``` _Après _ #### Kotlin ```kotlin // Discover and connect in one step by providing discovery filter val easyConnectConfig = InternetEasyConnectConfiguration( discoveryConfiguration = DiscoveryConfiguration.InternetDiscoveryConfiguration( location = "YOUR-LOCATION-ID", // optional discoveryFilter = DiscoveryFilter.BySerial("YOUR-READER-SERIAL-NUMBER"), ), connectionConfiguration = ConnectionConfiguration.InternetConnectionConfiguration( internetReaderListener = internetReaderListener, ) ) Terminal.getInstance().easyConnect( easyConnectConfig, object : ReaderCallback { override fun onSuccess(reader: Reader) { // Handle successful connection } override fun onFailure(e: TerminalException) { // Handle failure } } ) ``` ### Filtrage de détection lecteur Internet La détection de lecteur Internet prend désormais en charge le filtrage par ID de lecteur ou numéro de série. Définissez la propriété `discoveryFilter` sur `InternetDiscoveryConfiguration`, pour découvrir un lecteur spécifique. _Avant _ #### Kotlin ```kotlin val config = InternetDiscoveryConfiguration(location = "tml_1234567890") ``` _Après _ #### Kotlin ```kotlin val config = InternetDiscoveryConfiguration( location = "tml_1234567890", // optional discoveryFilter = DiscoveryFilter.BySerial("READER-SERIAL-NUMBER"), // or DiscoveryFilter.ByReaderId("tmr_YOUR-READER-STRIPE-ID) to filter by reader id ) ``` ## Acceptation des paiements et recouvrement des données ### L’annulation par le client est désormais activée par défaut. Sur les lecteurs Android, la possibilité pour les clients d’annuler des transactions est désormais *activée par défaut*. Vous pouvez désactiver cette fonctionnalité en définissant `customerCancellation` sur `DISABLE_IF_AVAILABLE`. _Avant _ #### Kotlin ```kotlin val config = CollectConfiguration.Builder() .setEnableCustomerCancellation(false) .build() ``` _Après _ #### Kotlin ```kotlin val config = CollectPaymentIntentConfiguration.Builder() .setCustomerCancellation(CustomerCancellation.DISABLE_IF_AVAILABLE) .build() ``` ### Mises à jour des paramètres remboursement Interac Si vous créez des `RefundParameters` pour un remboursement Interac à l’aide d’un ID PaymentIntent, vous devez désormais également transmettre la `clé secrète du client` de la PaymentIntent. Vous pouvez également continuer à utiliser l’ID de facturation, qui ne nécessite pas la `clé secrète du client`. _Avant _ #### Kotlin ```kotlin val refundParams = RefundParameters.Builder( RefundParameters.Id.PaymentIntent("pi_123"), 1000, "cad" ).build() ``` _Après _ #### Kotlin ```kotlin val refundParams = RefundParameters.ByPaymentIntentId( paymentIntentId = "pi_123", clientSecret = "pi_123_secret_abc", amount = 1000, currency = "cad" ).build() ``` ## Mettre à jour votre intégration Apps on Devices Les coordonnées Maven de la fonctionnalité Apps on Devices sont désormais `com.stripe:stripeterminal-appsondevices:5.0.0`. Mettez à jour vos dépendances pour pointer vers le nouvel artefact. Stripe ne mettra plus à jour l’ancien artefact `handoffclient`. Nous avons renommé toutes les classes `Handoff` en `AppsOnDevices` afin de mieux décrire les fonctionnalités associées. _Avant _ #### Kotlin ```kotlin dependencies { implementation("com.stripe:stripeterminal-handoffclient:4.0.0") } ``` _Après _ #### Kotlin ```kotlin dependencies { implementation("com.stripe:stripeterminal-appsondevices:5.0.0") } ``` ### Renommer les classes Handoff en AppsOnDevices Nous avons renommé toutes les classes `Handoff` en `AppsOnDevices` pour la configuration de découverte, la configuration de connexion, les écouteurs et les fournisseurs de tokens. _Avant _ #### Kotlin ```kotlin val discoveryConfig = HandoffDiscoveryConfiguration() Terminal.getInstance().discoverReaders( discoveryConfig, object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List) { val reader = readers.first() val connectionConfig = HandoffConnectionConfiguration( handoffReaderListener = object : HandoffReaderListener { override fun onDisconnect(reason: DisconnectReason) { // Handle disconnect } } ) Terminal.getInstance().connectReader(reader, connectionConfig, readerCallback) } } ) val tokenProvider = HandoffConnectionTokenProvider() ``` _Après _ #### Kotlin ```kotlin val discoveryConfig = AppsOnDevicesDiscoveryConfiguration() Terminal.getInstance().discoverReaders( discoveryConfig, object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List) { val reader = readers.first() val connectionConfig = AppsOnDevicesConnectionConfiguration( appsOnDevicesListener = object : AppsOnDevicesListener { override fun onDisconnect(reason: DisconnectReason) { // Handle disconnect } } ) Terminal.getInstance().connectReader(reader, connectionConfig, readerCallback) } } ) val tokenProvider = AppsOnDevicesConnectionTokenProvider() ``` ## Mise à jour de l’intégration Tap to Pay sur Android ### Exigences du système Tap to Pay sur Android 5.0.0 et ses versions ultérieures nécessitent que votre appareil Android fonctionne sous Android 13 ou toute version ultérieure. Cette version exige également que le KeyStore de votre appareil Android prenne en charge les contrats de clés garantis par le matériel. Cela est vérifié automatiquement pour vous par `supportsReadersOfType()`, mais peut également être vérifié en s’assurant que la version [`FEATURE_HARDWARE_KEYSTORE`](https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_HARDWARE_KEYSTORE) de votre appareil est 100 ou supérieure. Cette exigence dépendant des capacités matérielles d’un appareil, il est donc possible qu’elle ne soit pas satisfaite par les appareils qui ont été initialement proposés sous Android 12 ou inférieur, même s’ils ont été mis à niveau pour répondre à l’exigence d’exécution d’Android 13. Cette nouvelle exigence signifie que les appareils comme la Samsung Galaxy Tab Active4 Pro ne sont plus pris en charge dans les versions 5.0.0 et supérieures du SDK. Pour les environnements de production, la découverte du lecteur échoue avec une erreur `TAP_TO_PAY_INSECURE_ENVIRONMENT` si les options développeur, le débogage USB ou Wi-Fi, ou d’autres options de débogage sont activées sur l’appareil. Cela ne s’applique pas à l’utilisation du lecteur Tap to Pay simulé. ### Refonte de la configuration TapZone La classe `TapToPayUxConfiguration.TapZone` a été remaniée. Les champs `indicateur` et `position` sont remplacés par un objet `TapZone` unique. _Avant _ #### Kotlin ```kotlin val config = TapToPayUxConfiguration.Builder() .setTapZone( indicator = TapZoneIndicator.ABOVE, position = TapZonePosition.Manual(0.5f, 0.2f) ) .build() ``` _Après _ #### Kotlin ```kotlin // Position the tap zone above the reader UI val config = TapToPayUxConfiguration.Builder() .setTapZone(TapZone.Above(horizontalBias = 0.2f)) .build() // Or position it on the left side of the screen val config2 = TapToPayUxConfiguration.Builder() .setTapZone(TapZone.Left()) // Center vertically by default .build() ```