@getyoti/yoti-doc-scan-react-native 3.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,14 +10,14 @@ A react native wrapper of Yoti IDV for [Android](https://github.com/getyoti/yoti
10
10
  To integrate with Yoti IDV, a working infrastructure is needed (see [developers.yoti.com](https://developers.yoti.com/identity-verification/overview) for more details or get in touch with us [here](https://developers.yoti.com/support)).
11
11
 
12
12
  ## Requirements
13
- - [Android SDK 3+](https://github.com/getyoti/yoti-doc-scan-android/releases)
14
- - [iOS SDK 5+](https://github.com/getyoti/yoti-doc-scan-ios/releases)
13
+ - [Android SDK 4+](https://github.com/getyoti/yoti-doc-scan-android/releases)
14
+ - [iOS SDK 7+](https://github.com/getyoti/yoti-doc-scan-ios/releases)
15
15
 
16
16
  ## Integration
17
17
  Start your integration by adding the following dependency to your `package.json` file:
18
18
  ```json
19
19
  "dependencies": {
20
- "@getyoti/yoti-doc-scan-react-native": "^3.0.0"
20
+ "@getyoti/yoti-doc-scan-react-native": "^5.0.0"
21
21
  }
22
22
  ```
23
23
 
@@ -26,13 +26,13 @@ Continuing with your integration for Android, add the following property and rep
26
26
  ```groovy
27
27
  buildscript {
28
28
  ext {
29
- yotiSdkVersion = "3.4.0"
29
+ yotiSdkVersion = "4.0.0"
30
30
  }
31
31
  }
32
32
  allprojects {
33
33
  repositories {
34
34
  maven {
35
- url 'https://maven.microblink.com'
35
+ url 'https://maven.regulaforensics.com/RegulaDocumentReader'
36
36
  }
37
37
  }
38
38
  }
@@ -54,12 +54,14 @@ dependencies {
54
54
  ```
55
55
  If you're using Proguard or another obfuscation tool, you should also add the following configuration rules to your `proguard-rules.pro` file:
56
56
  ```groovy
57
+ -keepclassmembers class kotlinx.** {
58
+ volatile <fields>;
59
+ }
57
60
  -keep class com.yoti.** { *; }
58
- -keep class com.microblink.** { *; }
59
- -keep class com.microblink.**$* { *; }
60
- -dontwarn com.microblink.**
61
- -keep class com.facetec.zoom.** { *; }
61
+ -dontwarn com.facetec.sdk.**
62
+ -keep class com.facetec.sdk.** { *; }
62
63
  -dontwarn javax.annotation.Nullable
64
+ -keepclassmembers class io.ktor.** { volatile <fields>; }
63
65
  ```
64
66
 
65
67
  ### iOS
@@ -68,7 +70,7 @@ To continue your integration with iOS, you should add the following to your [`Po
68
70
  require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
69
71
  require_relative '../node_modules/react-native/scripts/react_native_pods'
70
72
 
71
- platform :ios, '11.0'
73
+ platform :ios, '13.0'
72
74
 
73
75
  target 'TargetName' do
74
76
  config = use_native_modules!
@@ -83,44 +85,50 @@ target 'TargetName' do
83
85
  pod 'YotiSDKFaceCapture' // Optional
84
86
  end
85
87
  ```
86
- In addition, you should add [`NSCameraUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nscamerausagedescription) to your `Info.plist`.
87
-
88
- And if you have included `YotiNFC` in your target, make sure to also:
89
- - Add [`NFCReaderUsageDescription`](https://developer.apple.com/documentation/bundleresources/information_property_list/nfcreaderusagedescription) to your `Info.plist`
90
- - Add [`com.apple.developer.nfc.readersession.iso7816.select-identifiers`](https://developer.apple.com/documentation/bundleresources/information_property_list/select-identifiers) to your `Info.plist` and include [`A0000002471001`](https://www.icao.int/publications/Documents/9303_p10_cons_en.pdf) as an application identifier for your app to support
91
- - Turn on [`Near Field Communication Tag Reading`](https://developer.apple.com/documentation/corenfc/building_an_nfc_tag-reader_app) under the Signing & Capabilities tab for your project’s target
88
+ In addition, you should [modify the properties and capabilities of your project's target](https://github.com/getyoti/yoti-doc-scan-ios?tab=readme-ov-file#5-modify-the-properties-and-capabilities-of-your-projects-target).
92
89
 
93
90
  ## Usage
94
91
  ### 1. Import module
95
92
  ```javascript
96
93
  import RNYotiDocScan from '@getyoti/yoti-doc-scan-react-native';
97
94
  ```
98
- ### 2. Launch a session
99
- Launch a session with its required parameters using the `startSession` function.
95
+ ### 2. Optional configuration and customization
96
+ For customization on Android, you can refer to the documentation outlined [here](https://github.com/getyoti/yoti-doc-scan-android?tab=readme-ov-file#customisation). In addition, you can choose to also set a request code:
100
97
  ```javascript
101
- const successCallback = (code, description) => {
102
- ...
103
- }
104
- const errorCallback = (code, description) => {
105
- ...
106
- }
107
- RNYotiDocScan.startSession(id, token, successCallback, errorCallback);
98
+ RNYotiDocScan.setRequestCode(0); // default: 9001
108
99
  ```
109
100
 
110
- ### 3. Customizations
111
- On iOS, you can set the primary color using the following API:
101
+ On iOS, the SDK expects launched sessions to contain multiple flows by default. To enable single-flow sessions, configure and include [yoti-doc-scan-react-native-configuration-ios.json](templates/yoti-doc-scan-react-native-configuration-ios.json) in your project’s target and then set the configuration as follows:
112
102
  ```javascript
113
- RNYotiDocScan.setPrimaryColorRGB(0, 0, 0); // default: (40, 117, 188)
103
+ RNYotiDocScan.setConfiguration({
104
+ bundle_identifier: "", // Optional: defaults to the main bundle identifier if not specified.
105
+ filename: "yoti-doc-scan-react-native-configuration-ios.json"
106
+ });
114
107
  ```
115
- To customize the colors on Android, please refer to its separate [documentation](https://github.com/getyoti/yoti-doc-scan-android#colours).
108
+ Ensure that only one module type property is set to `true` when `single_flow` is enabled.
116
109
 
117
- In addition, you can choose to also specify a request code on Android:
110
+ To customize the appearance on iOS, you can configure the SDK using [yoti-doc-scan-react-native-configuration-with-theme-ios.json](templates/yoti-doc-scan-react-native-configuration-with-theme-ios.json) instead, which supports the following options for theming:
111
+
112
+ - Light and dark mode color themes. We also support specifying only a primary color for each mode
113
+ - Typography theme (system and custom fonts, font weight, size, line height multiple and kern)
114
+ - Spacing mode (compact, regular and relaxed)
115
+ - Shape theme (corner radius and border width)
116
+ - Icon theme (custom vectors, system and custom SF Symbols, incl. localized ones)
117
+ - Illustration theme (custom vectors)
118
+
119
+ All customisation types are optional, and can be set independently from each other.
120
+
121
+ ### 3. Launch a session
122
+ Launch a session with its required parameters using the `start` function.
118
123
  ```javascript
119
- RNYotiDocScan.setRequestCode(0); // default: 9001
124
+ const completion = (code, description) => {
125
+ ...
126
+ }
127
+ RNYotiDocScan.start(sessionID, sessionToken, completion);
120
128
  ```
121
129
 
122
130
  ## Supported languages
123
- Yoti IDV supports the 9 languages listed in the table below, but their use is driven by the localization configuration of your target. If your target only supports a subset of our SDK's supported languages, our SDK will fall back to English on the ones your target doesn't support.
131
+ Our SDK supports the 9 languages listed in the table below, but their use is driven by the localization configuration of your target. If your target only supports a subset of our SDK's supported languages, our SDK will fall back to English on the ones your target doesn't support.
124
132
 
125
133
  Language | Code
126
134
  :-- | :--
@@ -134,10 +142,11 @@ Russian | ru
134
142
  Spanish | es
135
143
  Turkish | tr
136
144
 
137
- ## Error codes
145
+ ## Status codes
138
146
  Code | Description
139
147
  :-- | :--
140
- 1000 | No error occurred. The user cancelled the session
148
+ 0 | The user completed the session
149
+ 1000 | The user cancelled the session
141
150
  2000 | Unauthorised request (wrong or expired session token)
142
151
  2001 | Session not found
143
152
  2002 | Session expired
package/RNYotiDocScan.js CHANGED
@@ -1,3 +1,3 @@
1
- import { NativeModules } from 'react-native'
1
+ import {NativeModules} from 'react-native'
2
2
 
3
3
  export default NativeModules.RNYotiDocScan;
@@ -10,8 +10,8 @@ android {
10
10
  defaultConfig {
11
11
  minSdkVersion safeExtGet('minSdkVersion', 21)
12
12
  targetSdkVersion safeExtGet('targetSdkVersion', 33)
13
- versionCode 301
14
- versionName "3.0.1"
13
+ versionCode 500
14
+ versionName "5.0.0"
15
15
  ndk {
16
16
  abiFilters "armeabi-v7a", "x86"
17
17
  }
@@ -7,6 +7,7 @@ import com.facebook.react.bridge.BaseActivityEventListener;
7
7
  import com.facebook.react.bridge.Callback;
8
8
  import com.facebook.react.bridge.ReactApplicationContext;
9
9
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
10
+ import com.facebook.react.bridge.ReadableMap;
10
11
  import com.facebook.react.bridge.ReactMethod;
11
12
  import com.yoti.mobile.android.yotisdkcore.YotiSdk;
12
13
  import static com.yoti.mobile.android.yotisdkcore.YotiSdkKt.YOTI_SDK_REQUEST_CODE;
@@ -14,8 +15,7 @@ import static com.yoti.mobile.android.yotisdkcore.YotiSdkKt.YOTI_SDK_REQUEST_COD
14
15
  public class RNYotiDocScanModule extends ReactContextBaseJavaModule {
15
16
  private final static int SESSION_SUCCESS_CODE = 0;
16
17
  private YotiSdk mYotiSdk;
17
- private Callback mErrorCallback;
18
- private Callback mSuccessCallback;
18
+ private Callback mCompletion;
19
19
  private int mRequestCode = YOTI_SDK_REQUEST_CODE;
20
20
 
21
21
  private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
@@ -27,10 +27,10 @@ public class RNYotiDocScanModule extends ReactContextBaseJavaModule {
27
27
  int code = mYotiSdk.getSessionStatusCode();
28
28
  String description = mYotiSdk.getSessionStatusDescription();
29
29
  if (resultCode == Activity.RESULT_OK && code == SESSION_SUCCESS_CODE) {
30
- mSuccessCallback.invoke(code, description);
30
+ mCompletion.invoke(code, description);
31
31
  return;
32
32
  }
33
- mErrorCallback.invoke(code, description);
33
+ mCompletion.invoke(code, description);
34
34
  }
35
35
  };
36
36
 
@@ -46,12 +46,7 @@ public class RNYotiDocScanModule extends ReactContextBaseJavaModule {
46
46
  }
47
47
 
48
48
  @ReactMethod
49
- public void useCanadaService() {
50
- mYotiSdk.useCanadaService();
51
- }
52
-
53
- @ReactMethod
54
- public void setPrimaryColorRGB(double red, double green, double blue) {
49
+ public void setConfiguration(ReadableMap configuration) {
55
50
  // Required to maintain cross-platform API compatibility.
56
51
  }
57
52
 
@@ -61,19 +56,18 @@ public class RNYotiDocScanModule extends ReactContextBaseJavaModule {
61
56
  }
62
57
 
63
58
  @ReactMethod
64
- public void startSession(String sessionId, String clientSessionToken, Callback successCallback, Callback errorCallback) {
65
- mErrorCallback = errorCallback;
66
- mSuccessCallback = successCallback;
59
+ public void start(String sessionID, String sessionToken, Callback completion) {
60
+ mCompletion = completion;
67
61
  Activity currentActivity = getCurrentActivity();
68
62
  if (currentActivity == null) {
69
- mErrorCallback.invoke("E_ACTIVITY_DOES_NOT_EXIST");
63
+ mCompletion.invoke("E_ACTIVITY_DOES_NOT_EXIST");
70
64
  return;
71
65
  }
72
- boolean success = mYotiSdk.setSessionId(sessionId).setClientSessionToken(clientSessionToken).start(currentActivity, mRequestCode);
66
+ boolean success = mYotiSdk.setSessionId(sessionID).setClientSessionToken(sessionToken).start(currentActivity, mRequestCode);
73
67
  if (!success) {
74
68
  int code = mYotiSdk.getSessionStatusCode();
75
69
  String description = mYotiSdk.getSessionStatusDescription();
76
- mErrorCallback.invoke(code, description);
70
+ mCompletion.invoke(code, description);
77
71
  }
78
72
  }
79
73
  }
@@ -0,0 +1,48 @@
1
+ //
2
+ // Copyright © 2025 Yoti Ltd. All rights reserved.
3
+ //
4
+
5
+ struct Configuration: Decodable {
6
+ let singleFlow: Bool?
7
+ let includeIdentityDocumentModuleType: Bool?
8
+ let includeSupplementaryDocumentModuleType: Bool?
9
+ let includeFaceTecModuleType: Bool?
10
+ let includeFaceCaptureModuleType: Bool?
11
+ let theme: Theme?
12
+
13
+ init(from decoder: Decoder) throws {
14
+ let container = try decoder.container(keyedBy: CodingKeys.self)
15
+ singleFlow = try container.decodeIfPresent(Bool.self, forKey: .singleFlow)
16
+ includeIdentityDocumentModuleType = try container.decodeIfPresent(Bool.self, forKey: .includeIdentityDocumentModuleType)
17
+ includeSupplementaryDocumentModuleType = try container.decodeIfPresent(Bool.self, forKey: .includeSupplementaryDocumentModuleType)
18
+ includeFaceTecModuleType = try container.decodeIfPresent(Bool.self, forKey: .includeFaceTecModuleType)
19
+ includeFaceCaptureModuleType = try container.decodeIfPresent(Bool.self, forKey: .includeFaceCaptureModuleType)
20
+ theme = try container.decodeIfPresent(Theme.self, forKey: .theme)
21
+ }
22
+
23
+ private enum CodingKeys: String, CodingKey {
24
+ case singleFlow = "single_flow"
25
+ case includeIdentityDocumentModuleType = "include_identity_document_module_type"
26
+ case includeSupplementaryDocumentModuleType = "include_supplementary_document_module_type"
27
+ case includeFaceTecModuleType = "include_facetec_module_type"
28
+ case includeFaceCaptureModuleType = "include_face_capture_module_type"
29
+ case theme
30
+ }
31
+ }
32
+
33
+ extension Configuration {
34
+ init(fileConfiguration: FileConfiguration) {
35
+ let bundleIdentifier = fileConfiguration.bundleIdentifier ?? ""
36
+ guard let bundle = Bundle(identifier: bundleIdentifier) else {
37
+ preconditionFailure("Unable to locate bundle with identifier: \(bundleIdentifier)")
38
+ }
39
+ let filename = fileConfiguration.filename ?? ""
40
+ guard let url = bundle.url(forResource: filename, withExtension: nil), let data = try? Data(contentsOf: url) else {
41
+ preconditionFailure("Unable to locate file with name: \(filename)")
42
+ }
43
+ guard let configuration = try? JSONDecoder().decode(Self.self, from: data) else {
44
+ preconditionFailure("Unable to decode configuration")
45
+ }
46
+ self = configuration
47
+ }
48
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // Copyright © 2025 Yoti Ltd. All rights reserved.
3
+ //
4
+
5
+ struct FileConfiguration: Decodable {
6
+ var bundleIdentifier: String?
7
+ var filename: String?
8
+
9
+ init(from decoder: Decoder) throws {
10
+ let container = try decoder.container(keyedBy: CodingKeys.self)
11
+ if let bundleIdentifier = try container.decodeIfPresent(String.self, forKey: .bundleIdentifier), !bundleIdentifier.isEmpty {
12
+ self.bundleIdentifier = bundleIdentifier
13
+ } else if let bundleIdentifier = Bundle.main.bundleIdentifier, !bundleIdentifier.isEmpty {
14
+ self.bundleIdentifier = bundleIdentifier
15
+ }
16
+ if let filename = try container.decodeIfPresent(String.self, forKey: .filename), !filename.isEmpty {
17
+ self.filename = filename
18
+ }
19
+ }
20
+
21
+ private enum CodingKeys: String, CodingKey {
22
+ case bundleIdentifier = "bundle_identifier"
23
+ case filename
24
+ }
25
+ }
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright © 2025 Yoti Ltd. All rights reserved.
3
+ //
4
+
5
+ #import <React/RCTBridgeModule.h>
@@ -1,118 +1,13 @@
1
- #import "RNYotiDocScan.h"
2
- #import <React/RCTUtils.h>
3
- #import <YotiSDKCore/YotiSDKCore-Swift.h>
4
- #if __has_include(<YotiSDKIdentityDocument/YotiSDKIdentityDocument-Swift.h>)
5
- #import <YotiSDKIdentityDocument/YotiSDKIdentityDocument-Swift.h>
6
- #endif
7
- #if __has_include(<YotiSDKSupplementaryDocument/YotiSDKSupplementaryDocument-Swift.h>)
8
- #import <YotiSDKSupplementaryDocument/YotiSDKSupplementaryDocument-Swift.h>
9
- #endif
10
- #if __has_include(<YotiSDKFaceTec/YotiSDKFaceTec-Swift.h>)
11
- #import <YotiSDKFaceTec/YotiSDKFaceTec-Swift.h>
12
- #endif
13
- #if __has_include(<YotiSDKFaceCapture/YotiSDKFaceCapture-Swift.h>)
14
- #import <YotiSDKFaceCapture/YotiSDKFaceCapture-Swift.h>
15
- #endif
1
+ //
2
+ // Copyright © 2025 Yoti Ltd. All rights reserved.
3
+ //
16
4
 
17
- NSInteger const kYotiSuccessStatusCode = 0;
5
+ #import <React/RCTBridgeModule.h>
18
6
 
19
- @interface RNYotiDocScan()
7
+ @interface RCT_EXTERN_MODULE(RNYotiDocScan, NSObject)
20
8
 
21
- @property (nonatomic, strong) YotiSDKNavigationController *yotiSDKNavigationController;
22
- @property (nonatomic, strong) UIViewController *rootViewController;
23
- @property (nonatomic, strong) NSString *sessionID;
24
- @property (nonatomic, strong) NSString *sessionToken;
25
- @property (nonatomic, assign) BOOL setUpCanadaServerLocation;
26
- @property (nonatomic, strong) UIColor *primaryColor;
27
- @property (nonatomic, strong) RCTResponseSenderBlock errorCallback;
28
- @property (nonatomic, strong) RCTResponseSenderBlock successCallback;
29
- @end
30
-
31
- @implementation RNYotiDocScan
32
-
33
- RCT_EXPORT_MODULE(RNYotiDocScan);
34
-
35
- RCT_EXPORT_METHOD(useCanadaService) {
36
- _setUpCanadaServerLocation = YES;
37
- }
38
-
39
- RCT_EXPORT_METHOD(setPrimaryColorRGB:(double)red green:(double)green blue:(double)blue) {
40
- _primaryColor = [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0];
41
- }
42
-
43
- RCT_EXPORT_METHOD(setRequestCode:(NSNumber * _Nonnull)requestCode) {
44
- // Required to maintain cross-platform API compatibility.
45
- }
46
-
47
- RCT_EXPORT_METHOD(startSession:(NSString *)sessionId clientSessionToken:(NSString *)clientSessionToken successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback)
48
- {
49
- _sessionID = sessionId;
50
- _sessionToken = clientSessionToken;
51
- self.errorCallback = errorCallback;
52
- self.successCallback = successCallback;
53
- dispatch_async(dispatch_get_main_queue(), ^{
54
- self.yotiSDKNavigationController = [[YotiSDKNavigationController alloc] init];
55
- self.yotiSDKNavigationController.sdkDataSource = self;
56
- self.yotiSDKNavigationController.sdkDelegate = self;
57
- self.rootViewController = RCTPresentedViewController();
58
- [self.rootViewController presentViewController:self.yotiSDKNavigationController animated:YES completion:nil];
59
- });
60
- }
61
-
62
- // MARK: - YotiSDKDataSource
63
- - (NSArray<Class<YotiSDKModule>> * _Nonnull)supportedModuleTypesFor:(YotiSDKNavigationController * _Nonnull)navigationController {
64
- NSMutableArray *moduleTypes = [NSMutableArray array];
65
- #if __has_include(<YotiSDKIdentityDocument/YotiSDKIdentityDocument-Swift.h>)
66
- [moduleTypes addObject:[YotiSDKIdentityDocumentModule class]];
67
- #endif
68
- #if __has_include(<YotiSDKSupplementaryDocument/YotiSDKSupplementaryDocument-Swift.h>)
69
- [moduleTypes addObject:[YotiSDKSupplementaryDocumentModule class]];
70
- #endif
71
- #if __has_include(<YotiSDKFaceTec/YotiSDKFaceTec-Swift.h>)
72
- [moduleTypes addObject:[YotiSDKFaceTecModule class]];
73
- #endif
74
- #if __has_include(<YotiSDKFaceCapture/YotiSDKFaceCapture-Swift.h>)
75
- [moduleTypes addObject:[YotiSDKFaceCaptureModule class]];
76
- #endif
77
- return moduleTypes;
78
- }
79
-
80
- - (NSString * _Nonnull)sessionIDFor:(YotiSDKNavigationController * _Nonnull)navigationController {
81
- return _sessionID;
82
- }
83
-
84
- - (NSString * _Nonnull)sessionTokenFor:(YotiSDKNavigationController * _Nonnull)navigationController {
85
- return _sessionToken;
86
- }
87
-
88
- - (ServerLocation)serverLocationFor:(YotiSDKNavigationController * _Nonnull)navigationController {
89
- if (_setUpCanadaServerLocation) {
90
- return ServerLocationCanada;
91
- } else {
92
- return ServerLocationUnitedKingdom;
93
- }
94
- }
95
-
96
- - (BOOL)isReactNativeClientFor:(YotiSDKNavigationController * _Nonnull)navigationController {
97
- return YES;
98
- }
99
-
100
- // MARK: - YotiSDKDelegate
101
- - (UIColor * _Nonnull)primaryColorFor:(YotiSDKNavigationController * _Nonnull)navigationController {
102
- if (_primaryColor != nil) {
103
- return _primaryColor;
104
- } else {
105
- return [UIColor colorWithRed:40.0/255.0 green:117.0/255.0 blue:188.0/255.0 alpha:1.0];
106
- }
107
- }
108
-
109
- - (void)navigationController:(YotiSDKNavigationController * _Nonnull)navigationController didFinishWithStatusCode:(NSInteger)statusCode {
110
- [_rootViewController dismissViewControllerAnimated:YES completion:nil];
111
- if (statusCode == kYotiSuccessStatusCode) {
112
- _successCallback(@[[NSNumber numberWithLong:statusCode]]);
113
- return;
114
- }
115
- _errorCallback(@[[NSNumber numberWithLong:statusCode]]);
116
- }
9
+ RCT_EXTERN_METHOD(setConfiguration:(NSDictionary *)configuration);
10
+ RCT_EXTERN_METHOD(setRequestCode:(NSInteger)requestCode);
11
+ RCT_EXTERN_METHOD(start:(NSString *)sessionID sessionToken:(NSString *)sessionToken completion:(RCTResponseSenderBlock)completion);
117
12
 
118
13
  @end
@@ -0,0 +1,136 @@
1
+ //
2
+ // Copyright © 2025 Yoti Ltd. All rights reserved.
3
+ //
4
+
5
+ import Foundation
6
+ import React
7
+ import YotiSDKCore
8
+ import YotiSDKDesign
9
+ #if canImport(YotiSDKIdentityDocument)
10
+ import YotiSDKIdentityDocument
11
+ #endif
12
+ #if canImport(YotiSDKSupplementaryDocument)
13
+ import YotiSDKSupplementaryDocument
14
+ #endif
15
+ #if canImport(YotiSDKFaceTec)
16
+ import YotiSDKFaceTec
17
+ #endif
18
+ #if canImport(YotiSDKFaceCapture)
19
+ import YotiSDKFaceCapture
20
+ #endif
21
+
22
+ @objc(RNYotiDocScan) final class RNYotiDocScan: NSObject {
23
+ private var rootViewController: UIViewController?
24
+ private var navigationController: YotiSDKNavigationController?
25
+ private var sessionID = ""
26
+ private var sessionToken = ""
27
+ private var completion: RCTResponseSenderBlock?
28
+ private var _configuration: Configuration?
29
+ }
30
+
31
+ extension RNYotiDocScan {
32
+ @objc static func requiresMainQueueSetup() -> Bool {
33
+ false
34
+ }
35
+
36
+ @objc func setConfiguration(_ configuration: Dictionary<String, String>) {
37
+ guard let data = try? JSONSerialization.data(withJSONObject: configuration) else {
38
+ preconditionFailure("Unable to serialize configuration dictionary")
39
+ }
40
+ guard let fileConfiguration = try? JSONDecoder().decode(FileConfiguration.self, from: data) else {
41
+ preconditionFailure("Unable to decode file configuration")
42
+ }
43
+ _configuration = Configuration(fileConfiguration: fileConfiguration)
44
+ }
45
+
46
+ @objc func setRequestCode(_ requestCode: Int) {
47
+ // Required to maintain cross-platform API compatibility
48
+ }
49
+
50
+ @objc func start(_ sessionID: String, sessionToken: String, completion: @escaping RCTResponseSenderBlock) {
51
+ self.sessionID = sessionID
52
+ self.sessionToken = sessionToken
53
+ self.completion = completion
54
+ DispatchQueue.performOnMainThread { [weak self] in
55
+ guard let self else {
56
+ return
57
+ }
58
+ navigationController = YotiSDKNavigationController()
59
+ navigationController?.sdkDataSource = self
60
+ navigationController?.sdkDelegate = self
61
+ rootViewController = RCTPresentedViewController()
62
+ rootViewController?.present(navigationController!, animated: true)
63
+ }
64
+ }
65
+ }
66
+
67
+ extension RNYotiDocScan: YotiSDKDataSource, YotiSDKDelegate {
68
+ func configuration() -> YotiSDKConfiguration {
69
+ .init(
70
+ sessionID: sessionID,
71
+ sessionToken: sessionToken,
72
+ singleFlow: _configuration?.singleFlow ?? false,
73
+ moduleTypes: moduleTypes(),
74
+ theme: theme()
75
+ )
76
+ }
77
+
78
+ func isReactNativeClient() -> Bool {
79
+ true
80
+ }
81
+
82
+ func didFinish(statusCode: Int) {
83
+ rootViewController?.dismiss(animated: true)
84
+ completion?([statusCode])
85
+ }
86
+ }
87
+
88
+ fileprivate extension RNYotiDocScan {
89
+ func moduleTypes() -> [YotiSDKModule.Type] {
90
+ var moduleTypes = [YotiSDKModule.Type]()
91
+ let includeImportableModuleTypes = _configuration == nil
92
+ || (_configuration?.singleFlow == nil || _configuration?.singleFlow == false)
93
+ && _configuration?.includeIdentityDocumentModuleType == nil
94
+ && _configuration?.includeSupplementaryDocumentModuleType == nil
95
+ && _configuration?.includeFaceTecModuleType == nil
96
+ && _configuration?.includeFaceCaptureModuleType == nil
97
+ #if canImport(YotiSDKIdentityDocument)
98
+ if includeImportableModuleTypes || _configuration?.includeIdentityDocumentModuleType == true {
99
+ moduleTypes.append(YotiSDKIdentityDocumentModule.self)
100
+ }
101
+ #endif
102
+ #if canImport(YotiSDKSupplementaryDocument)
103
+ if includeImportableModuleTypes || _configuration?.includeSupplementaryDocumentModuleType == true {
104
+ moduleTypes.append(YotiSDKSupplementaryDocumentModule.self)
105
+ }
106
+ #endif
107
+ #if canImport(YotiSDKFaceTec)
108
+ if includeImportableModuleTypes || _configuration?.includeFaceTecModuleType == true {
109
+ moduleTypes.append(YotiSDKFaceTecModule.self)
110
+ }
111
+ #endif
112
+ #if canImport(YotiSDKFaceCapture)
113
+ if includeImportableModuleTypes || _configuration?.includeFaceCaptureModuleType == true {
114
+ moduleTypes.append(YotiSDKFaceCaptureModule.self)
115
+ }
116
+ #endif
117
+ return moduleTypes
118
+ }
119
+
120
+ func theme() -> YotiSDKTheme? {
121
+ guard let theme = _configuration?.theme else {
122
+ return nil
123
+ }
124
+ let builder = YotiSDKThemeBuilder()
125
+ builder.lightPrimaryColor = theme.lightPrimaryColor
126
+ builder.darkPrimaryColor = theme.darkPrimaryColor
127
+ builder.lightColorTheme = theme.lightColorTheme
128
+ builder.darkColorTheme = theme.darkColorTheme
129
+ builder.typographyTheme = theme.typographyTheme
130
+ builder.spacingMode = theme.spacingMode
131
+ builder.shapeTheme = theme.shapeTheme
132
+ builder.iconTheme = theme.iconTheme
133
+ builder.illustrationTheme = theme.illustrationTheme
134
+ return builder.build()
135
+ }
136
+ }