diff --git a/CHANGELOG.md b/CHANGELOG.md index 840c41fb..9491cff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Release Notes +## 10.1.0 + +* Moved SmartSelfie enrollment and authentication to synchronous endpoints +* Introduced polling methods for products + * SmartSelfie + * Biometric kyc + * Document verification + * Enhanced document verification + ## 10.0.12 * Fixed a bug where SmartSelfieEnrollment and SmartSelfieAuthentication would return invalid `livenessImages` in `onSuccess` diff --git a/android/build.gradle b/android/build.gradle index 87858091..423da98c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group "com.smileidentity.flutter" -version findProperty("SDK_VERSION") ?: "10.0.4" +version findProperty("SDK_VERSION") ?: "10.1.2" buildscript { ext.kotlin_version = "1.9.10" diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt index 6482bff1..c446793b 100644 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt +++ b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt @@ -21,17 +21,26 @@ import SmileIDApi import android.app.Activity import android.content.Context import com.smileidentity.SmileID +import com.smileidentity.networking.pollBiometricKycJobStatus +import com.smileidentity.networking.pollDocumentVerificationJobStatus +import com.smileidentity.networking.pollEnhancedDocumentVerificationJobStatus +import com.smileidentity.networking.pollSmartSelfieJobStatus import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.net.URL +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds class SmileIDPlugin : FlutterPlugin, SmileIDApi, ActivityAware { - private var activity: Activity? = null private lateinit var appContext: Context @@ -172,13 +181,104 @@ class SmileIDPlugin : FlutterPlugin, SmileIDApi, ActivityAware { callback = callback, ) - override fun getServices( - callback: (Result) -> Unit, + override fun getServices(callback: (Result) -> Unit) = + launch( + work = { SmileID.api.getServices().toResponse() }, + callback = callback, + ) + + override fun pollSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollSmartSelfieJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + override fun pollDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollDocumentVerificationJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + override fun pollBiometricKycJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, ) = launch( - work = { SmileID.api.getServices().toResponse() }, + work = { + pollJobStatus( + apiCall = SmileID.api::pollBiometricKycJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, callback = callback, ) + override fun pollEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollEnhancedDocumentVerificationJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + private suspend fun pollJobStatus( + apiCall: suspend (RequestType, Duration, Int) -> Flow, + request: RequestType, + interval: Long, + numAttempts: Long, + transform: (ResponseType) -> FlutterResponseType, + ): FlutterResponseType { + return try { + val response = + withContext(Dispatchers.IO) { + apiCall(request, interval.milliseconds, numAttempts.toInt()) + .map { transform(it) } + .single() + } + response + } catch (e: Exception) { + throw e + } + } + /** * https://stackoverflow.com/a/62206235 * @@ -205,9 +305,10 @@ private fun launch( callback: (Result) -> Unit, scope: CoroutineScope = CoroutineScope(Dispatchers.IO), ) { - val handler = CoroutineExceptionHandler { _, throwable -> - callback.invoke(Result.failure(throwable)) - } + val handler = + CoroutineExceptionHandler { _, throwable -> + callback.invoke(Result.failure(throwable)) + } scope.launch(handler) { callback.invoke(Result.success(work())) } diff --git a/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt b/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt index c0184173..8bfb3391 100644 --- a/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt +++ b/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt @@ -1859,6 +1859,10 @@ interface SmileIDApi { fun getProductsConfig(request: FlutterProductsConfigRequest, callback: (Result) -> Unit) fun getValidDocuments(request: FlutterProductsConfigRequest, callback: (Result) -> Unit) fun getServices(callback: (Result) -> Unit) + fun pollSmartSelfieJobStatus(request: FlutterJobStatusRequest, interval: Long, numAttempts: Long, callback: (Result) -> Unit) + fun pollDocumentVerificationJobStatus(request: FlutterJobStatusRequest, interval: Long, numAttempts: Long, callback: (Result) -> Unit) + fun pollBiometricKycJobStatus(request: FlutterJobStatusRequest, interval: Long, numAttempts: Long, callback: (Result) -> Unit) + fun pollEnhancedDocumentVerificationJobStatus(request: FlutterJobStatusRequest, interval: Long, numAttempts: Long, callback: (Result) -> Unit) companion object { /** The codec used by SmileIDApi. */ @@ -2161,6 +2165,94 @@ interface SmileIDApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.smileid.SmileIDApi.pollSmartSelfieJobStatus", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.pollSmartSelfieJobStatus(requestArg, intervalArg, numAttemptsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.smileid.SmileIDApi.pollDocumentVerificationJobStatus", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.pollDocumentVerificationJobStatus(requestArg, intervalArg, numAttemptsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.smileid.SmileIDApi.pollBiometricKycJobStatus", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.pollBiometricKycJobStatus(requestArg, intervalArg, numAttemptsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.smileid.SmileIDApi.pollEnhancedDocumentVerificationJobStatus", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { if (it is Int) it.toLong() else it as Long } + api.pollEnhancedDocumentVerificationJobStatus(requestArg, intervalArg, numAttemptsArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } } } } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 8587525a..6332a335 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -2,10 +2,12 @@ PODS: - Flutter (1.0.0) - integration_test (0.0.1): - Flutter - - smile_id (10.0.11): + - lottie-ios (4.4.3) + - smile_id (10.1.0): - Flutter - - SmileID (= 10.0.11) - - SmileID (10.0.11): + - SmileID (= 10.1.3) + - SmileID (10.1.3): + - lottie-ios (~> 4.4.2) - Zip (~> 2.1.0) - Zip (2.1.2) @@ -16,6 +18,7 @@ DEPENDENCIES: SPEC REPOS: trunk: + - lottie-ios - SmileID - Zip @@ -28,10 +31,11 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/smile_id/ios" SPEC CHECKSUMS: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - integration_test: 13825b8a9334a850581300559b8839134b124670 - smile_id: 82636e504fcef7d98dbffeb2b15ac51df9c0604a - SmileID: 93d6f6bee1b988d12c2dc8872e7113dbe9edd5a1 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 + lottie-ios: fcb5e73e17ba4c983140b7d21095c834b3087418 + smile_id: a17b29545bbd29dabe9279c4d5016e866993bede + SmileID: 61ae985152b559099730bf211b74c9fbbcc4e516 Zip: b3fef584b147b6e582b2256a9815c897d60ddc67 PODFILE CHECKSUM: 929954fb8941cef06249e96bd1516fd2a22ed7a5 diff --git a/example/pubspec.lock b/example/pubspec.lock index f0dc100e..b7332eb6 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" cupertino_icons: dependency: "direct main" description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -98,14 +98,30 @@ packages: description: flutter source: sdk version: "0.0.0" - js: + leak_tracker: dependency: transitive description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -118,42 +134,42 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.12.0" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -166,10 +182,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" sky_engine: dependency: transitive description: flutter @@ -181,7 +197,7 @@ packages: path: ".." relative: true source: path - version: "10.0.8" + version: "10.1.0" source_span: dependency: transitive description: @@ -194,18 +210,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -234,10 +250,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.0" vector_math: dependency: transitive description: @@ -250,18 +266,18 @@ packages: dependency: transitive description: name: vm_service - sha256: f3743ca475e0c9ef71df4ba15eb2d7684eecd5c8ba20a462462e4e8b561b2e11 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "11.6.0" + version: "14.2.1" webdriver: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" sdks: - dart: ">=3.0.5 <4.0.0" - flutter: ">=3.0.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/SmileIDBiometricKYC.swift b/ios/Classes/SmileIDBiometricKYC.swift index 15db7234..37464fa7 100644 --- a/ios/Classes/SmileIDBiometricKYC.swift +++ b/ios/Classes/SmileIDBiometricKYC.swift @@ -4,6 +4,7 @@ import SmileID import SwiftUI class SmileIDBiometricKYC : NSObject, FlutterPlatformView, BiometricKycResultDelegate { + private var _view: UIView private var _channel: FlutterMethodChannel private var _childViewController: UIViewController? @@ -58,14 +59,12 @@ class SmileIDBiometricKYC : NSObject, FlutterPlatformView, BiometricKycResultDel return _view } - func didSucceed(selfieImage: URL, livenessImages: [URL], jobStatusResponse: BiometricKycJobStatusResponse) { + func didSucceed(selfieImage: URL, livenessImages: [URL], didSubmitBiometricJob: Bool) { _childViewController?.removeFromParent() - let encoder = JSONEncoder() - let jsonData = try! encoder.encode(jobStatusResponse) _channel.invokeMethod("onSuccess", arguments: """ {"selfieFile": "\(selfieImage.absoluteString)", - "livenessImages": "\(livenessImages.map{ $0.absoluteString })", - "jobStatusResponse": \(String(data: jsonData, encoding: .utf8)!)} + "livenessImages": \(livenessImages.map{ $0.absoluteString }), + "didSubmitBiometricJob": \(didSubmitBiometricJob), """) } diff --git a/ios/Classes/SmileIDDocumentVerification.swift b/ios/Classes/SmileIDDocumentVerification.swift index 36b49c7f..e9f19476 100644 --- a/ios/Classes/SmileIDDocumentVerification.swift +++ b/ios/Classes/SmileIDDocumentVerification.swift @@ -4,6 +4,7 @@ import SmileID import SwiftUI class SmileIDDocumentVerification : NSObject, FlutterPlatformView, DocumentVerificationResultDelegate { + private var _view: UIView private var _channel: FlutterMethodChannel private var _childViewController: UIViewController? @@ -55,21 +56,13 @@ class SmileIDDocumentVerification : NSObject, FlutterPlatformView, DocumentVerif return _view } - func didSucceed( - selfie: URL, - documentFrontImage: URL, - documentBackImage: URL?, - jobStatusResponse: DocumentVerificationJobStatusResponse - ) { + func didSucceed(selfie: URL, documentFrontImage: URL, documentBackImage: URL?, didSubmitDocumentVerificationJob: Bool) { _childViewController?.removeFromParent() - let encoder = JSONEncoder() - let jsonData = try! encoder.encode(jobStatusResponse) - let documentBackFileJson = documentBackImage.map{ "\"\($0.absoluteString)\"" } ?? "null" _channel.invokeMethod("onSuccess", arguments: """ {"selfieFile": "\(selfie.absoluteString)", - "documentFrontFile": "\(documentFrontImage.absoluteString)", - "documentBackFile": \(documentBackFileJson), - "jobStatusResponse": \(String(data: jsonData, encoding: .utf8)!)} + "documentFrontImage": \(documentFrontImage.absoluteString), + "documentBackImage": \(documentBackImage?.absoluteString ?? ""), + "didSubmitDocumentVerificationJob": \(didSubmitDocumentVerificationJob), """) } diff --git a/ios/Classes/SmileIDEnhancedDocumentVerification.swift b/ios/Classes/SmileIDEnhancedDocumentVerification.swift index 69f014fa..51e8c475 100644 --- a/ios/Classes/SmileIDEnhancedDocumentVerification.swift +++ b/ios/Classes/SmileIDEnhancedDocumentVerification.swift @@ -4,6 +4,7 @@ import SmileID import SwiftUI class SmileIDEnhancedDocumentVerification : NSObject, FlutterPlatformView, EnhancedDocumentVerificationResultDelegate { + private var _view: UIView private var _channel: FlutterMethodChannel private var _childViewController: UIViewController? @@ -72,6 +73,16 @@ class SmileIDEnhancedDocumentVerification : NSObject, FlutterPlatformView, Enhan "jobStatusResponse": \(String(data: jsonData, encoding: .utf8)!)} """) } + + func didSucceed(selfie: URL, documentFrontImage: URL, documentBackImage: URL?, didSubmitEnhancedDocVJob: Bool) { + _childViewController?.removeFromParent() + _channel.invokeMethod("onSuccess", arguments: """ + {"selfieFile": "\(selfie.absoluteString)", + "documentFrontImage": \(documentFrontImage.absoluteString), + "documentBackImage": \(documentBackImage?.absoluteString ?? ""), + "didSubmitEnhancedDocVJob": \(didSubmitEnhancedDocVJob), + """) + } func didError(error: Error) { print("[Smile ID] An error occurred - \(error.localizedDescription)") diff --git a/ios/Classes/SmileIDMessages.g.swift b/ios/Classes/SmileIDMessages.g.swift index 04af2289..2bf0ef63 100644 --- a/ios/Classes/SmileIDMessages.g.swift +++ b/ios/Classes/SmileIDMessages.g.swift @@ -1854,6 +1854,10 @@ protocol SmileIDApi { func getProductsConfig(request: FlutterProductsConfigRequest, completion: @escaping (Result) -> Void) func getValidDocuments(request: FlutterProductsConfigRequest, completion: @escaping (Result) -> Void) func getServices(completion: @escaping (Result) -> Void) + func pollSmartSelfieJobStatus(request: FlutterJobStatusRequest, interval: Int64, numAttempts: Int64, completion: @escaping (Result) -> Void) + func pollDocumentVerificationJobStatus(request: FlutterJobStatusRequest, interval: Int64, numAttempts: Int64, completion: @escaping (Result) -> Void) + func pollBiometricKycJobStatus(request: FlutterJobStatusRequest, interval: Int64, numAttempts: Int64, completion: @escaping (Result) -> Void) + func pollEnhancedDocumentVerificationJobStatus(request: FlutterJobStatusRequest, interval: Int64, numAttempts: Int64, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -2108,5 +2112,81 @@ class SmileIDApiSetup { } else { getServicesChannel.setMessageHandler(nil) } + let pollSmartSelfieJobStatusChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.smileid.SmileIDApi.pollSmartSelfieJobStatus", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pollSmartSelfieJobStatusChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! FlutterJobStatusRequest + let intervalArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let numAttemptsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.pollSmartSelfieJobStatus(request: requestArg, interval: intervalArg, numAttempts: numAttemptsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pollSmartSelfieJobStatusChannel.setMessageHandler(nil) + } + let pollDocumentVerificationJobStatusChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.smileid.SmileIDApi.pollDocumentVerificationJobStatus", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pollDocumentVerificationJobStatusChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! FlutterJobStatusRequest + let intervalArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let numAttemptsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.pollDocumentVerificationJobStatus(request: requestArg, interval: intervalArg, numAttempts: numAttemptsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pollDocumentVerificationJobStatusChannel.setMessageHandler(nil) + } + let pollBiometricKycJobStatusChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.smileid.SmileIDApi.pollBiometricKycJobStatus", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pollBiometricKycJobStatusChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! FlutterJobStatusRequest + let intervalArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let numAttemptsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.pollBiometricKycJobStatus(request: requestArg, interval: intervalArg, numAttempts: numAttemptsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pollBiometricKycJobStatusChannel.setMessageHandler(nil) + } + let pollEnhancedDocumentVerificationJobStatusChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.smileid.SmileIDApi.pollEnhancedDocumentVerificationJobStatus", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pollEnhancedDocumentVerificationJobStatusChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let requestArg = args[0] as! FlutterJobStatusRequest + let intervalArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32) + let numAttemptsArg = args[2] is Int64 ? args[2] as! Int64 : Int64(args[2] as! Int32) + api.pollEnhancedDocumentVerificationJobStatus(request: requestArg, interval: intervalArg, numAttempts: numAttemptsArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + pollEnhancedDocumentVerificationJobStatusChannel.setMessageHandler(nil) + } } } diff --git a/ios/Classes/SmileIDPlugin.swift b/ios/Classes/SmileIDPlugin.swift index 4d8c765a..e5647c20 100644 --- a/ios/Classes/SmileIDPlugin.swift +++ b/ios/Classes/SmileIDPlugin.swift @@ -4,13 +4,14 @@ import SmileID import Combine public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { + private var subscribers = Set() - + public static func register(with registrar: FlutterPluginRegistrar) { let messenger: FlutterBinaryMessenger = registrar.messenger() let api: SmileIDApi & NSObjectProtocol = SmileIDPlugin() SmileIDApiSetup.setUp(binaryMessenger: messenger, api: api) - + let documentVerificationFactory = SmileIDDocumentVerification.Factory( messenger: registrar.messenger() ) @@ -26,7 +27,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { enhancedDocumentVerificationFactory, withId: SmileIDEnhancedDocumentVerification.VIEW_TYPE_ID ) - + let smartSelfieEnrollmentFactory = SmileIDSmartSelfieEnrollment.Factory( messenger: registrar.messenger() ) @@ -34,7 +35,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { smartSelfieEnrollmentFactory, withId: SmileIDSmartSelfieEnrollment.VIEW_TYPE_ID ) - + let smartSelfieAuthenticationFactory = SmileIDSmartSelfieAuthentication.Factory( messenger: registrar.messenger() ) @@ -52,19 +53,19 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { ) } - + func initialize() { SmileID.initialize() } - + func setEnvironment(useSandbox: Bool) { SmileID.setEnvironment(useSandbox: useSandbox) } - + func setCallbackUrl(callbackUrl: String) { SmileID.setCallbackUrl(url: URL(string: callbackUrl)) } - + func authenticate( request: FlutterAuthenticationRequest, completion: @escaping (Result) -> Void @@ -82,7 +83,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func prepUpload( request: FlutterPrepUploadRequest, completion: @escaping (Result) -> Void @@ -100,7 +101,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func upload( url: String, request: FlutterUploadRequest, @@ -121,7 +122,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { completion(.failure(error)) } } - + func doEnhancedKyc( request: FlutterEnhancedKycRequest, completion: @escaping (Result) -> Void @@ -139,7 +140,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func doEnhancedKycAsync( request: FlutterEnhancedKycRequest, completion: @escaping (Result) -> Void @@ -157,7 +158,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getSmartSelfieJobStatus( request: FlutterJobStatusRequest, completion: @escaping (Result) -> Void @@ -175,7 +176,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getDocumentVerificationJobStatus( request: FlutterJobStatusRequest, completion: @escaping (Result) -> Void @@ -193,7 +194,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getBiometricKycJobStatus( request: FlutterJobStatusRequest, completion: @escaping (Result) -> Void @@ -211,7 +212,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getEnhancedDocumentVerificationJobStatus( request: FlutterJobStatusRequest, completion: @escaping (Result) -> Void @@ -229,7 +230,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getProductsConfig( request: FlutterProductsConfigRequest, completion: @escaping (Result) -> Void @@ -247,7 +248,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getValidDocuments( request: FlutterProductsConfigRequest, completion: @escaping (Result) -> Void @@ -265,7 +266,7 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } - + func getServices( completion: @escaping (Result) -> Void ) { @@ -282,4 +283,129 @@ public class SmileIDPlugin: NSObject, FlutterPlugin, SmileIDApi { }) .store(in: &subscribers) } + + + func pollSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + interval: Int64, + numAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + + pollJobStatus( + apiCall: SmileID.api.pollSmartSelfieJobStatus, + request: request.toRequest(), + interval: interval, + numAttempts: numAttempts, + completion: { result in + switch result { + case .success(let response): + completion(.success(response.toResponse())) + case .failure(let error): + completion(.failure(error)) + } + } + ) + } + + func pollDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Int64, + numAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + + pollJobStatus( + apiCall: SmileID.api.pollDocumentVerificationJobStatus, + request: request.toRequest(), + interval: interval, + numAttempts: numAttempts, + completion: { result in + switch result { + case .success(let response): + completion(.success(response.toResponse())) + case .failure(let error): + completion(.failure(error)) + } + } + ) + } + + + func pollBiometricKycJobStatus( + request: FlutterJobStatusRequest, + interval: Int64, + numAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + + pollJobStatus( + apiCall: SmileID.api.pollBiometricKycJobStatus, + request: request.toRequest(), + interval: interval, + numAttempts: numAttempts, + completion: { result in + switch result { + case .success(let response): + completion(.success(response.toResponse())) + case .failure(let error): + completion(.failure(error)) + } + } + ) + } + + func pollEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Int64, + numAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + pollJobStatus( + apiCall: SmileID.api.pollEnhancedDocumentVerificationJobStatus, + request: request.toRequest(), + interval: interval, + numAttempts: numAttempts, + completion: { result in + switch result { + case .success(let response): + completion(.success(response.toResponse())) + case .failure(let error): + completion(.failure(error)) + } + } + ) + } + + func pollJobStatus( + apiCall: @escaping (RequestType, TimeInterval, Int) -> AnyPublisher, + request: RequestType, + interval: Int64, + numAttempts: Int64, + completion: @escaping (Result) -> Void + ) { + let timeInterval = convertToTimeInterval(milliSeconds: interval) + guard let numAttemptsInt = Int(exactly: numAttempts) else { + completion(.failure(NSError(domain: "Invalid numAttempts value", code: -1, userInfo: nil))) + return + } + + apiCall(request, timeInterval, numAttemptsInt) + .sink(receiveCompletion: { status in + switch status { + case .failure(let error): + completion(.failure(error)) + case .finished: + break + } + }, receiveValue: { response in + completion(.success(response)) + }) + .store(in: &subscribers) + } + + func convertToTimeInterval(milliSeconds:Int64) -> TimeInterval { + let seconds = milliSeconds/1000 + return TimeInterval(seconds) + } } diff --git a/ios/Classes/SmileIDSmartSelfieAuthentication.swift b/ios/Classes/SmileIDSmartSelfieAuthentication.swift index c5ec5479..e54389d1 100644 --- a/ios/Classes/SmileIDSmartSelfieAuthentication.swift +++ b/ios/Classes/SmileIDSmartSelfieAuthentication.swift @@ -4,6 +4,7 @@ import SmileID import SwiftUI class SmileIDSmartSelfieAuthentication : NSObject, FlutterPlatformView, SmartSelfieResultDelegate { + private var _view: UIView private var _channel: FlutterMethodChannel private var _childViewController: UIViewController? @@ -47,20 +48,13 @@ class SmileIDSmartSelfieAuthentication : NSObject, FlutterPlatformView, SmartSel return _view } - func didSucceed(selfieImage: URL, livenessImages: [URL], jobStatusResponse: SmartSelfieJobStatusResponse?) { + + func didSucceed(selfieImage: URL, livenessImages: [URL], didSubmitSmartSelfieJob: Bool) { _childViewController?.removeFromParent() - let encoder = JSONEncoder() - let jobStatusResponseJson: String - if let jobStatusResponse = jobStatusResponse { - let jsonData = try! encoder.encode(jobStatusResponse) - jobStatusResponseJson = String(data: jsonData, encoding: .utf8)! - } else { - jobStatusResponseJson = "null" - } _channel.invokeMethod("onSuccess", arguments: """ {"selfieFile": "\(selfieImage.absoluteString)", - "livenessImages": \(livenessImages.map { $0.absoluteString }), - "jobStatusResponse": \(jobStatusResponseJson)} + "livenessImages": \(livenessImages.map{ $0.absoluteString }), + "didSubmitSmartSelfieJob": \(didSubmitSmartSelfieJob), """) } diff --git a/ios/Classes/SmileIDSmartSelfieEnrollment.swift b/ios/Classes/SmileIDSmartSelfieEnrollment.swift index 2e8e552f..3cc6ec95 100644 --- a/ios/Classes/SmileIDSmartSelfieEnrollment.swift +++ b/ios/Classes/SmileIDSmartSelfieEnrollment.swift @@ -4,6 +4,7 @@ import SmileID import SwiftUI class SmileIDSmartSelfieEnrollment : NSObject, FlutterPlatformView, SmartSelfieResultDelegate { + private var _view: UIView private var _channel: FlutterMethodChannel private var _childViewController: UIViewController? @@ -47,21 +48,12 @@ class SmileIDSmartSelfieEnrollment : NSObject, FlutterPlatformView, SmartSelfieR return _view } - func didSucceed(selfieImage: URL, livenessImages: [URL], jobStatusResponse: SmartSelfieJobStatusResponse?) { + func didSucceed(selfieImage: URL, livenessImages: [URL], didSubmitSmartSelfieJob: Bool) { _childViewController?.removeFromParent() - let encoder = JSONEncoder() - let jobStatusResponseJson: String - if let jobStatusResponse = jobStatusResponse { - let jsonData = try! encoder.encode(jobStatusResponse) - jobStatusResponseJson = String(data: jsonData, encoding: .utf8)! - } else { - jobStatusResponseJson = "null" - } - let jsonData = try! encoder.encode(jobStatusResponse) _channel.invokeMethod("onSuccess", arguments: """ {"selfieFile": "\(selfieImage.absoluteString)", "livenessImages": \(livenessImages.map{ $0.absoluteString }), - "jobStatusResponse": \(jobStatusResponseJson)} + "didSubmitSmartSelfieJob": \(didSubmitSmartSelfieJob), """) } diff --git a/ios/smile_id.podspec b/ios/smile_id.podspec index daba5104..bb4edcef 100644 --- a/ios/smile_id.podspec +++ b/ios/smile_id.podspec @@ -4,7 +4,7 @@ Pod::Spec.new do |s| s.name = 'smile_id' # NB! Keep this version in sync with the Native iOS SDK version - s.version = '10.0.11' + s.version = '10.1.3' s.summary = 'Official Smile ID SDK for Flutter' s.description = <<-DESC A new Flutter project. @@ -15,7 +15,7 @@ A new Flutter project. s.source_files = 'Classes/**/*' s.dependency 'Flutter' # NB! Update the s.version above when changing this version - s.dependency 'SmileID', '10.0.11' + s.dependency 'SmileID', '10.1.3' s.platform = :ios, '13.0' # Flutter.framework does not contain a i386 slice. diff --git a/lib/smile_id_service.dart b/lib/smile_id_service.dart index 01784282..fa40d4e1 100644 --- a/lib/smile_id_service.dart +++ b/lib/smile_id_service.dart @@ -46,26 +46,30 @@ class SmileIDService { /// Fetches the status of a Job. This can be used to check if a Job is complete, and if so, /// whether it was successful. This should be called when the Job is known to be a /// SmartSelfie Authentication/Registration. - Future getSmartSelfieJobStatus(FlutterJobStatusRequest request) { + Future getSmartSelfieJobStatus( + FlutterJobStatusRequest request) { return platformInterface.getSmartSelfieJobStatus(request); } /// Fetches the status of a Job. This can be used to check if a Job is complete, and if so, /// whether it was successful. This should be called when the Job is known to be a /// Document Verification. - Future getDocumentVerificationJobStatus(FlutterJobStatusRequest request) { + Future getDocumentVerificationJobStatus( + FlutterJobStatusRequest request) { return platformInterface.getDocumentVerificationJobStatus(request); } /// Fetches the status of a Job. This can be used to check if a Job is complete, and if so, /// whether it was successful. This should be called when the Job is known to be a Biometric KYC. - Future getBiometricKycJobStatus(FlutterJobStatusRequest request) { + Future getBiometricKycJobStatus( + FlutterJobStatusRequest request) { return platformInterface.getBiometricKycJobStatus(request); } /// Fetches the status of a Job. This can be used to check if a Job is complete, and if so, /// whether it was successful. This should be called when the Job is known to be Enhanced DocV. - Future getEnhancedDocumentVerificationJobStatus(FlutterJobStatusRequest request) { + Future + getEnhancedDocumentVerificationJobStatus(FlutterJobStatusRequest request) { return platformInterface.getEnhancedDocumentVerificationJobStatus(request); } @@ -84,4 +88,192 @@ class SmileIDService { Future getServices() { return platformInterface.getServices(); } + + /// Polls the status of a Smart Selfie job. + /// + /// The function returns a [Future] that completes with a + /// [FlutterSmartSelfieJobStatusResponse], which contains the status of the job. + /// + /// Example usage: + /// ```dart + /// var request = FlutterJobStatusRequest(/* parameters */); + /// var response = await pollSmartSelfieJobStatus(request, 1000, 5); + /// ``` + /// + /// This example polls the job status every 1000 milliseconds (1 second) up to 5 times. + /// + /// The [FlutterJobStatusRequest] should be configured according to the job + /// requirements and platform interface specifications. + /// + /// The [interval] parameter specifies the duration (in milliseconds) between + /// each polling attempt. + /// + /// The [numAttempts] parameter defines the number of times the job status will + /// be polled before giving up. + /// + /// If the job status is successfully retrieved within the specified attempts, + /// the [Future] completes with the job status. If not, the [Future] may complete + /// with an error or the last status retrieved, depending on the platform interface + /// implementation. + /// + /// Throws: + /// - [PlatformException] if there is an error in the platform interface. + /// + /// Params: + /// - [request]: The request object containing the job status request details. + /// - [interval]: The interval duration (in milliseconds) between each polling attempt. + /// - [numAttempts]: The number of polling attempts before stopping. + /// + /// Returns: + /// - A [Future] that completes with the job status. + /// + /// See also: + /// - [FlutterJobStatusRequest] + /// - [FlutterSmartSelfieJobStatusResponse] + /// ``` + Future pollSmartSelfieJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts) { + return platformInterface.pollSmartSelfieJobStatus(request, interval, numAttempts); + } + + /// Polls the status of a document verification job + /// + /// The function returns a [Future] that completes with a + /// [FlutterDocumentVerificationJobStatusResponse], which contains the status of the job. + /// + /// Example usage: + /// ```dart + /// var request = FlutterJobStatusRequest(/* parameters */); + /// var response = await pollDocumentVerificationJobStatus(request, 1000, 5); + /// ``` + /// + /// This example polls the job status every 1000 milliseconds (1 second) up to 5 times. + /// + /// The [FlutterJobStatusRequest] should be configured according to the job + /// requirements and platform interface specifications. + /// + /// The [interval] parameter specifies the duration (in milliseconds) between + /// each polling attempt. + /// + /// The [numAttempts] parameter defines the number of times the job status will + /// be polled before giving up. + /// + /// If the job status is successfully retrieved within the specified attempts, + /// the [Future] completes with the job status. If not, the [Future] may complete + /// with an error or the last status retrieved, depending on the platform interface + /// implementation. + /// + /// Throws: + /// - [PlatformException] if there is an error in the platform interface. + /// + /// Params: + /// - [request]: The request object containing the job status request details. + /// - [interval]: The interval duration (in milliseconds) between each polling attempt. + /// - [numAttempts]: The number of polling attempts before stopping. + /// + /// Returns: + /// - A [Future] that completes with the job status. + /// + /// See also: + /// - [FlutterJobStatusRequest] + /// - [FlutterDocumentVerificationJobStatusResponse] + /// ``` + Future pollDocumentVerificationJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts) { + return platformInterface.pollDocumentVerificationJobStatus(request, interval, numAttempts); + } + + /// Polls the status of a biometric kyc job + /// + /// The function returns a [Future] that completes with a + /// [FlutterBiometricKycJobStatusResponse], which contains the status of the job. + /// + /// Example usage: + /// ```dart + /// var request = FlutterJobStatusRequest(/* parameters */); + /// var response = await pollBiometricKycJobStatus(request, 1000, 5); + /// ``` + /// + /// This example polls the job status every 1000 milliseconds (1 second) up to 5 times. + /// + /// The [FlutterJobStatusRequest] should be configured according to the job + /// requirements and platform interface specifications. + /// + /// The [interval] parameter specifies the duration (in milliseconds) between + /// each polling attempt. + /// + /// The [numAttempts] parameter defines the number of times the job status will + /// be polled before giving up. + /// + /// If the job status is successfully retrieved within the specified attempts, + /// the [Future] completes with the job status. If not, the [Future] may complete + /// with an error or the last status retrieved, depending on the platform interface + /// implementation. + /// + /// Throws: + /// - [PlatformException] if there is an error in the platform interface. + /// + /// Params: + /// - [request]: The request object containing the job status request details. + /// - [interval]: The interval duration (in milliseconds) between each polling attempt. + /// - [numAttempts]: The number of polling attempts before stopping. + /// + /// Returns: + /// - A [Future] that completes with the job status. + /// + /// See also: + /// - [FlutterJobStatusRequest] + /// - [FlutterBiometricKycJobStatusResponse] + /// ``` + Future pollBiometricKycJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts) { + return platformInterface.pollBiometricKycJobStatus(request, interval, numAttempts); + } + + /// Polls the status of a an enhanced document verification job + /// + /// The function returns a [Future] that completes with a + /// [FlutterEnhancedDocumentVerificationJobStatusResponse], which contains the status of the job. + /// + /// Example usage: + /// ```dart + /// var request = FlutterJobStatusRequest(/* parameters */); + /// var response = await pollEnhancedDocumentVerificationJobStatus(request, 1000, 5); + /// ``` + /// + /// This example polls the job status every 1000 milliseconds (1 second) up to 5 times. + /// + /// The [FlutterJobStatusRequest] should be configured according to the job + /// requirements and platform interface specifications. + /// + /// The [interval] parameter specifies the duration (in milliseconds) between + /// each polling attempt. + /// + /// The [numAttempts] parameter defines the number of times the job status will + /// be polled before giving up. + /// + /// If the job status is successfully retrieved within the specified attempts, + /// the [Future] completes with the job status. If not, the [Future] may complete + /// with an error or the last status retrieved, depending on the platform interface + /// implementation. + /// + /// Throws: + /// - [PlatformException] if there is an error in the platform interface. + /// + /// Params: + /// - [request]: The request object containing the job status request details. + /// - [interval]: The interval duration (in milliseconds) between each polling attempt. + /// - [numAttempts]: The number of polling attempts before stopping. + /// + /// Returns: + /// - A [Future] that completes with the job status. + /// + /// See also: + /// - [FlutterJobStatusRequest] + /// - [FlutterEnhancedDocumentVerificationJobStatusResponse] + /// ``` + Future pollEnhancedDocumentVerificationJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts) { + return platformInterface.pollEnhancedDocumentVerificationJobStatus(request, interval, numAttempts); + } } diff --git a/lib/smileid_messages.g.dart b/lib/smileid_messages.g.dart index f0cde96c..bef6c4cb 100644 --- a/lib/smileid_messages.g.dart +++ b/lib/smileid_messages.g.dart @@ -2482,4 +2482,112 @@ class SmileIDApi { return (__pigeon_replyList[0] as FlutterServicesResponse?)!; } } + + Future pollSmartSelfieJobStatus(FlutterJobStatusRequest request, int interval, int numAttempts) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.smileid.SmileIDApi.pollSmartSelfieJobStatus'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([request, interval, numAttempts]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as FlutterSmartSelfieJobStatusResponse?)!; + } + } + + Future pollDocumentVerificationJobStatus(FlutterJobStatusRequest request, int interval, int numAttempts) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.smileid.SmileIDApi.pollDocumentVerificationJobStatus'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([request, interval, numAttempts]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as FlutterDocumentVerificationJobStatusResponse?)!; + } + } + + Future pollBiometricKycJobStatus(FlutterJobStatusRequest request, int interval, int numAttempts) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.smileid.SmileIDApi.pollBiometricKycJobStatus'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([request, interval, numAttempts]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as FlutterBiometricKycJobStatusResponse?)!; + } + } + + Future pollEnhancedDocumentVerificationJobStatus(FlutterJobStatusRequest request, int interval, int numAttempts) async { + const String __pigeon_channelName = 'dev.flutter.pigeon.smileid.SmileIDApi.pollEnhancedDocumentVerificationJobStatus'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([request, interval, numAttempts]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as FlutterEnhancedDocumentVerificationJobStatusResponse?)!; + } + } } diff --git a/pigeon.sh b/pigeon.sh index ff6347e0..9345e367 100755 --- a/pigeon.sh +++ b/pigeon.sh @@ -1,4 +1,4 @@ -flutter pub run pigeon --input pigeon/messages.dart +dart run pigeon --input pigeon/messages.dart # Before use it, in the first time, you must guarantee some running permissions: # chmod +x pigeon.sh diff --git a/pigeon/messages.dart b/pigeon/messages.dart index 35cc1771..6045cf7f 100644 --- a/pigeon/messages.dart +++ b/pigeon/messages.dart @@ -9,7 +9,14 @@ import 'package:pigeon/pigeon.dart'; swiftOptions: SwiftOptions(), dartPackageName: 'smileid', )) -enum FlutterJobType { enhancedKyc, documentVerification, biometricKyc, enhancedDocumentVerification, smartSelfieEnrollment,smartSelfieAuthentication } +enum FlutterJobType { + enhancedKyc, + documentVerification, + biometricKyc, + enhancedDocumentVerification, + smartSelfieEnrollment, + smartSelfieAuthentication +} /// Custom values specific to partners can be placed in [extras] class FlutterPartnerParams { @@ -773,13 +780,15 @@ abstract class SmileIDApi { FlutterSmartSelfieJobStatusResponse getSmartSelfieJobStatus(FlutterJobStatusRequest request); @async - FlutterDocumentVerificationJobStatusResponse getDocumentVerificationJobStatus(FlutterJobStatusRequest request); + FlutterDocumentVerificationJobStatusResponse getDocumentVerificationJobStatus( + FlutterJobStatusRequest request); @async FlutterBiometricKycJobStatusResponse getBiometricKycJobStatus(FlutterJobStatusRequest request); @async - FlutterEnhancedDocumentVerificationJobStatusResponse getEnhancedDocumentVerificationJobStatus(FlutterJobStatusRequest request); + FlutterEnhancedDocumentVerificationJobStatusResponse getEnhancedDocumentVerificationJobStatus( + FlutterJobStatusRequest request); @async FlutterProductsConfigResponse getProductsConfig(FlutterProductsConfigRequest request); @@ -789,4 +798,20 @@ abstract class SmileIDApi { @async FlutterServicesResponse getServices(); + + @async + FlutterSmartSelfieJobStatusResponse pollSmartSelfieJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts); + + @async + FlutterDocumentVerificationJobStatusResponse pollDocumentVerificationJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts); + + @async + FlutterBiometricKycJobStatusResponse pollBiometricKycJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts); + + @async + FlutterEnhancedDocumentVerificationJobStatusResponse pollEnhancedDocumentVerificationJobStatus( + FlutterJobStatusRequest request, int interval, int numAttempts); } diff --git a/pubspec.yaml b/pubspec.yaml index 786610eb..6de409b0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: smile_id description: The Official Smile ID Flutter SDK -version: 10.0.12 +version: 10.1.0 homepage: "https://usesmileid.com" environment: