@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 +43 -34
- package/RNYotiDocScan.js +1 -1
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/yoti/reactnative/docscan/RNYotiDocScanModule.java +10 -16
- package/ios/Configuration.swift +48 -0
- package/ios/FileConfiguration.swift +25 -0
- package/ios/RNYotiDocScan-Bridging-Header.h +5 -0
- package/ios/RNYotiDocScan.m +8 -113
- package/ios/RNYotiDocScan.swift +136 -0
- package/ios/RNYotiDocScan.xcodeproj/project.pbxproj +84 -3
- package/ios/RNYotiDocScan.xcodeproj/xcshareddata/xcschemes/RNYotiDocScan.xcscheme +1 -1
- package/ios/Theme/ColorTheme.swift +128 -0
- package/ios/Theme/FontDesign.swift +28 -0
- package/ios/Theme/FontWeight.swift +42 -0
- package/ios/Theme/Icon.swift +62 -0
- package/ios/Theme/IconTheme.swift +121 -0
- package/ios/Theme/Illustration.swift +36 -0
- package/ios/Theme/IllustrationTheme.swift +120 -0
- package/ios/Theme/ShapeTheme.swift +26 -0
- package/ios/Theme/SpacingMode.swift +24 -0
- package/ios/Theme/SymbolWeight.swift +46 -0
- package/ios/Theme/Theme.swift +52 -0
- package/ios/Theme/TypographyStyle.swift +41 -0
- package/ios/Theme/TypographyTheme.swift +115 -0
- package/ios/Theme/UIColor+Extension.swift +24 -0
- package/package.json +4 -10
- package/yoti-doc-scan-react-native.podspec +3 -1
- package/ios/RNYotiDocScan.h +0 -7
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
|
|
14
|
-
- [iOS SDK
|
|
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": "^
|
|
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 = "
|
|
29
|
+
yotiSdkVersion = "4.0.0"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
allprojects {
|
|
33
33
|
repositories {
|
|
34
34
|
maven {
|
|
35
|
-
url 'https://maven.
|
|
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
|
-
-
|
|
59
|
-
-keep class com.
|
|
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, '
|
|
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
|
|
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.
|
|
99
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
108
|
+
Ensure that only one module type property is set to `true` when `single_flow` is enabled.
|
|
116
109
|
|
|
117
|
-
|
|
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
|
-
|
|
124
|
+
const completion = (code, description) => {
|
|
125
|
+
...
|
|
126
|
+
}
|
|
127
|
+
RNYotiDocScan.start(sessionID, sessionToken, completion);
|
|
120
128
|
```
|
|
121
129
|
|
|
122
130
|
## Supported languages
|
|
123
|
-
|
|
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
|
-
##
|
|
145
|
+
## Status codes
|
|
138
146
|
Code | Description
|
|
139
147
|
:-- | :--
|
|
140
|
-
|
|
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
package/android/build.gradle
CHANGED
|
@@ -10,8 +10,8 @@ android {
|
|
|
10
10
|
defaultConfig {
|
|
11
11
|
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
12
12
|
targetSdkVersion safeExtGet('targetSdkVersion', 33)
|
|
13
|
-
versionCode
|
|
14
|
-
versionName "
|
|
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
|
|
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
|
-
|
|
30
|
+
mCompletion.invoke(code, description);
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
|
|
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
|
|
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
|
|
65
|
-
|
|
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
|
-
|
|
63
|
+
mCompletion.invoke("E_ACTIVITY_DOES_NOT_EXIST");
|
|
70
64
|
return;
|
|
71
65
|
}
|
|
72
|
-
boolean success = mYotiSdk.setSessionId(
|
|
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
|
-
|
|
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
|
+
}
|
package/ios/RNYotiDocScan.m
CHANGED
|
@@ -1,118 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
5
|
+
#import <React/RCTBridgeModule.h>
|
|
18
6
|
|
|
19
|
-
@interface RNYotiDocScan
|
|
7
|
+
@interface RCT_EXTERN_MODULE(RNYotiDocScan, NSObject)
|
|
20
8
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
+
}
|