uqudosdk-react-native 3.4.2 → 3.5.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/CHANGELOG.md CHANGED
@@ -1,4 +1,28 @@
1
+ ## 3.5.0
2
+
3
+ * New Document Support:
4
+ - Added support for Indonesian ID and Iraqi Resident ID documents.
5
+ * Document Classification Improvements:
6
+ - Enhanced classification for Qatari ID. Previously, low scores on the back side could cause rejections during scanning; this issue has been addressed.
7
+ * Android SDK:
8
+ - Upgraded CameraX library to version 1.4.2.
9
+ - Fixed a potential crash during NFC reading of Emirates ID if the user removed the phone at a critical point in the final reading step.
10
+ * iOS SDK:
11
+ - Updated the OpenSSL dependency to version 3.3.3001 for NFC reading functionality. Using version 1.x will cause the SDK to crash.
12
+ - Fixed a rare crash related to camera selection. If the camera is unavailable, the SDK now safely ends the session with status code `SESSION_INVALIDATED_CAMERA_NOT_AVAILABLE`.
13
+ - Removed legacy `assets.bundle` and optimized existing assets, reducing total asset size by about 2MB.
14
+ * NFC / Chip Reading Enhancements:
15
+ - Improved support for EAC-CA (Chip Authentication), especially for passports. The SDK now handles defective chip implementations more gracefully by ignoring chip authentication failures. You can check if chip authentication was enabled in the verification object.
16
+ * Facial Liveness – New Active Liveness Feature:
17
+ - Introduced a new active liveness option in the facial recognition configuration. The SDK randomly prompts the user to perform one of six actions: move closer, move further, tilt right, tilt left, turn right, or turn left. You can disable one gesture type (move, tilt, or turn) to reduce the pool to four actions.
18
+ - ⚠️ Important: Enable this feature only if required by compliance, as it may reduce conversion rates. See the documentation for configuration details.
19
+ * New NFC/Reading Flow:
20
+ - Added a dedicated NFC/Reading flow, allowing verification processes to begin from the NFC step. You must supply required data to unlock the chip. Refer to the documentation for full details.
21
+ * General:
22
+ - Minor bug fixes and performance improvements.
23
+
1
24
  ## 3.4.2
25
+
2
26
  * New Feature
3
27
  - Facial recognition is now supported when using the MRZ document type in combination with NFC. Previously, facial recognition was disabled with MRZ as it only involved scanning the machine-readable zone (MRZ) of the document. From this version onward, facial recognition can be enabled and if there is a successful NFC reading during onboarding, the user will proceed to the facial recognition step, otherwise the step is automatically skipped.
4
28
  * Document Scanning
@@ -20,6 +20,7 @@ rootProject.allprojects {
20
20
  android {
21
21
  compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
22
22
  buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)
23
+ namespace "io.sdk.uqudoid"
23
24
  defaultConfig {
24
25
  minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
25
26
  targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
@@ -33,5 +34,5 @@ android {
33
34
 
34
35
  dependencies {
35
36
  implementation 'com.facebook.react:react-native:+'
36
- implementation 'io.uqudo.sdk:Uqudo:3.4.2'
37
+ implementation 'io.uqudo.sdk:Uqudo:3.5.0'
37
38
  }
@@ -42,6 +42,7 @@ import io.uqudo.sdk.core.domain.model.BackgroundCheckType;
42
42
  import io.uqudo.sdk.core.domain.model.ObfuscationType;
43
43
  import io.uqudo.sdk.core.domain.model.Document;
44
44
  import io.uqudo.sdk.core.domain.model.DocumentType;
45
+ import io.uqudo.sdk.core.domain.model.LivenessGesture;
45
46
  import java.text.SimpleDateFormat;
46
47
  import java.util.TimeZone;
47
48
 
@@ -53,6 +54,7 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
53
54
  public static final int REQUEST_CODE_ACCOUNT_RECOVERY = 1002;
54
55
  public static final int REQUEST_CODE_FACE_SESSION = 1003;
55
56
  public static final int REQUEST_CODE_LOOKUP = 1004;
57
+ public static final int REQUEST_CODE_READING = 1005;
56
58
 
57
59
  public UqudoIdModule(ReactApplicationContext reactContext) {
58
60
  super(reactContext);
@@ -170,6 +172,25 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
170
172
  if (faceObject.has("isOneToNVerificationEnabled") && faceObject.getBoolean("isOneToNVerificationEnabled")) {
171
173
  faceBuilder.enableOneToNVerification();
172
174
  }
175
+
176
+ if (faceObject.has("enableActiveLiveness") && faceObject.getBoolean("enableActiveLiveness")) {
177
+ LivenessGesture disableGesture = null;
178
+ if (faceObject.has("disableLivenessGesture")) {
179
+ String gesture = faceObject.getString("disableLivenessGesture");
180
+ switch (gesture) {
181
+ case "FACE_MOVE":
182
+ disableGesture = LivenessGesture.FACE_MOVE;
183
+ break;
184
+ case "FACE_TILT":
185
+ disableGesture = LivenessGesture.FACE_TILT;
186
+ break;
187
+ case "FACE_TURN":
188
+ disableGesture = LivenessGesture.FACE_TURN;
189
+ break;
190
+ }
191
+ }
192
+ faceBuilder.enableActiveLiveness(disableGesture);
193
+ }
173
194
 
174
195
  enrollment.enableFacialRecognition(faceBuilder.build());
175
196
  }
@@ -371,6 +392,14 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
371
392
  faceSession.enableAuditTrailImageObfuscation(ObfuscationType.FILLED_WHITE);
372
393
  }
373
394
  }
395
+ if (json.has("enableActiveLiveness") && json.getBoolean("enableActiveLiveness")) {
396
+ if (json.has("disableLivenessGesture")) {
397
+ LivenessGesture gesture = LivenessGesture.valueOf(json.getString("disableLivenessGesture"));
398
+ faceSession.enableActiveLiveness(gesture);
399
+ } else {
400
+ faceSession.enableActiveLiveness(null);
401
+ }
402
+ }
374
403
  Intent intent = faceSession.build(context);
375
404
  if (json.has("appearanceMode")) {
376
405
  if ("LIGHT".equals(json.getString("appearanceMode"))) {
@@ -443,6 +472,25 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
443
472
  if (faceObject.has("isOneToNVerificationEnabled") && faceObject.getBoolean("isOneToNVerificationEnabled")) {
444
473
  faceBuilder.enableOneToNVerification();
445
474
  }
475
+
476
+ if (faceObject.has("enableActiveLiveness") && faceObject.getBoolean("enableActiveLiveness")) {
477
+ LivenessGesture disableGesture = null;
478
+ if (faceObject.has("disableLivenessGesture")) {
479
+ String gesture = faceObject.getString("disableLivenessGesture");
480
+ switch (gesture) {
481
+ case "FACE_MOVE":
482
+ disableGesture = LivenessGesture.FACE_MOVE;
483
+ break;
484
+ case "FACE_TILT":
485
+ disableGesture = LivenessGesture.FACE_TILT;
486
+ break;
487
+ case "FACE_TURN":
488
+ disableGesture = LivenessGesture.FACE_TURN;
489
+ break;
490
+ }
491
+ }
492
+ faceBuilder.enableActiveLiveness(disableGesture);
493
+ }
446
494
  lookupBuilder.enableFacialRecognition(faceBuilder.build());
447
495
  }
448
496
  if (json.has("backgroundCheckConfiguration")) {
@@ -531,6 +579,159 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
531
579
  sendError(promise, SessionStatusCode.UNEXPECTED_ERROR.name(), "Expected valid document type as argument", null);
532
580
  }
533
581
  }
582
+
583
+ @ReactMethod
584
+ public void reading(String message, Promise promise) {
585
+ if (message != null && message.length() > 0) {
586
+ try {
587
+ JSONObject json = new JSONObject(message);
588
+ UqudoBuilder.Reading readingBuilder = new UqudoBuilder.Reading();
589
+
590
+ if (json.has("authorizationToken")) {
591
+ readingBuilder.setToken(json.getString("authorizationToken"));
592
+ }
593
+
594
+ if (json.has("sessionId")) {
595
+ readingBuilder.setSessionId(json.getString("sessionId"));
596
+ }
597
+
598
+ if (json.has("userIdentifier")) {
599
+ readingBuilder.setUserIdentifier(UUID.fromString(json.getString("userIdentifier")));
600
+ }
601
+
602
+ if (json.has("nonce")) {
603
+ readingBuilder.setNonce(json.getString("nonce"));
604
+ }
605
+
606
+ if (json.has("documentType")) {
607
+ readingBuilder.setDocumentType(DocumentType.valueOf(json.getString("documentType")));
608
+ }
609
+
610
+ if (json.has("documentNumber")) {
611
+ readingBuilder.setDocumentNumber(json.getString("documentNumber"));
612
+ }
613
+
614
+ if (json.has("dateOfBirth")) {
615
+ readingBuilder.setDateOfBirth(json.getString("dateOfBirth"));
616
+ }
617
+
618
+ if (json.has("dateOfExpiry")) {
619
+ readingBuilder.setDateOfExpiry(json.getString("dateOfExpiry"));
620
+ }
621
+
622
+ if (json.has("mrz")) {
623
+ readingBuilder.setMRZ(json.getString("mrz"));
624
+ }
625
+
626
+ if (json.has("isReturnDataForIncompleteSession") && json.getBoolean("isReturnDataForIncompleteSession")) {
627
+ readingBuilder.returnDataForIncompleteSession();
628
+ }
629
+
630
+ if (json.has("isSecuredWindowsDisabled") && json.getBoolean("isSecuredWindowsDisabled")) {
631
+ readingBuilder.disableSecureWindow();
632
+ }
633
+
634
+ if (json.has("facialRecognitionSpecification")) {
635
+ FacialRecognitionConfigurationBuilder faceBuilder = new FacialRecognitionConfigurationBuilder();
636
+ JSONObject faceObject = json.getJSONObject("facialRecognitionSpecification");
637
+ if (faceObject.has("enrollFace") && faceObject.getBoolean("enrollFace")) {
638
+ faceBuilder.enrollFace();
639
+ }
640
+ if (faceObject.has("scanMinimumMatchLevel") && faceObject.getInt("scanMinimumMatchLevel") > 0) {
641
+ faceBuilder.setScanMinimumMatchLevel(faceObject.getInt("scanMinimumMatchLevel"));
642
+ }
643
+ if (faceObject.has("readMinimumMatchLevel") && faceObject.getInt("readMinimumMatchLevel") > 0) {
644
+ faceBuilder.setReadMinimumMatchLevel(faceObject.getInt("readMinimumMatchLevel"));
645
+ }
646
+ if (faceObject.has("lookupMinimumMatchLevel") && faceObject.getInt("lookupMinimumMatchLevel") > 0) {
647
+ faceBuilder.setLookupMinimumMatchLevel(faceObject.getInt("lookupMinimumMatchLevel"));
648
+ }
649
+ if (faceObject.has("maxAttempts") && faceObject.getInt("maxAttempts") > 0) {
650
+ faceBuilder.setMaxAttempts(faceObject.getInt("maxAttempts"));
651
+ }
652
+ if (faceObject.has("allowClosedEyes") && faceObject.getBoolean("allowClosedEyes")) {
653
+ faceBuilder.allowClosedEyes();
654
+ }
655
+ if (faceObject.has("obfuscationType")){
656
+ if (faceObject.getString("obfuscationType").equals("FILLED")){
657
+ faceBuilder.enableAuditTrailImageObfuscation(ObfuscationType.FILLED);
658
+ } else if (faceObject.getString("obfuscationType").equals("BLURRED")){
659
+ faceBuilder.enableAuditTrailImageObfuscation(ObfuscationType.BLURRED);
660
+ } else if (faceObject.getString("obfuscationType").equals("FILLED_WHITE")){
661
+ faceBuilder.enableAuditTrailImageObfuscation(ObfuscationType.FILLED_WHITE);
662
+ }
663
+ }
664
+
665
+ if (faceObject.has("isOneToNVerificationEnabled") && faceObject.getBoolean("isOneToNVerificationEnabled")) {
666
+ faceBuilder.enableOneToNVerification();
667
+ }
668
+
669
+ if (faceObject.has("enableActiveLiveness") && faceObject.getBoolean("enableActiveLiveness")) {
670
+ LivenessGesture disableGesture = null;
671
+ if (faceObject.has("disableLivenessGesture")) {
672
+ String gesture = faceObject.getString("disableLivenessGesture");
673
+ switch (gesture) {
674
+ case "FACE_MOVE":
675
+ disableGesture = LivenessGesture.FACE_MOVE;
676
+ break;
677
+ case "FACE_TILT":
678
+ disableGesture = LivenessGesture.FACE_TILT;
679
+ break;
680
+ case "FACE_TURN":
681
+ disableGesture = LivenessGesture.FACE_TURN;
682
+ break;
683
+ }
684
+ }
685
+ faceBuilder.enableActiveLiveness(disableGesture);
686
+ }
687
+
688
+ readingBuilder.enableFacialRecognition(faceBuilder.build());
689
+ }
690
+
691
+ if (json.has("backgroundCheckConfiguration")) {
692
+ BackgroundCheckConfigurationBuilder backgroundCheckConfigurationBuilder = new BackgroundCheckConfigurationBuilder();
693
+ JSONObject backgroundObject = json.getJSONObject("backgroundCheckConfiguration");
694
+ if (backgroundObject.has("disableConsent") && backgroundObject.getBoolean("disableConsent")) {
695
+ backgroundCheckConfigurationBuilder.disableConsent();
696
+ }
697
+ if (backgroundObject.has("backgroundCheckType")) {
698
+ backgroundCheckConfigurationBuilder.setBackgroundCheckType(BackgroundCheckType.valueOf(backgroundObject.getString("backgroundCheckType")));
699
+ }
700
+ if (backgroundObject.has("monitoringEnabled") && backgroundObject.getBoolean("monitoringEnabled")) {
701
+ backgroundCheckConfigurationBuilder.enableMonitoring();
702
+ }
703
+ if (backgroundObject.has("skipView") && backgroundObject.getBoolean("skipView")) {
704
+ backgroundCheckConfigurationBuilder.skipView();
705
+ }
706
+ readingBuilder.enableBackgroundCheck(backgroundCheckConfigurationBuilder.build());
707
+ }
708
+
709
+ if (json.has("isLookupEnabled") && json.getBoolean("isLookupEnabled")) {
710
+ readingBuilder.enableLookup();
711
+ }
712
+
713
+ Intent intent = readingBuilder.build(context);
714
+ if (json.has("appearanceMode")) {
715
+ if ("LIGHT".equals(json.getString("appearanceMode"))) {
716
+ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
717
+ } else if ("DARK".equals(json.getString("appearanceMode"))) {
718
+ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
719
+ } else if ("SYSTEM".equals(json.getString("appearanceMode"))) {
720
+ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
721
+ }
722
+ } else {
723
+ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
724
+ }
725
+ getReactApplicationContext().startActivityForResult(intent, REQUEST_CODE_READING, null);
726
+ mPromises.put(REQUEST_CODE_READING, promise);
727
+ } catch (Exception e) {
728
+ Log.e("UqudoIdModule", e.getMessage(), e);
729
+ sendError(promise, SessionStatusCode.UNEXPECTED_ERROR.name(), e.getMessage(), null);
730
+ }
731
+ } else {
732
+ sendError(promise, SessionStatusCode.UNEXPECTED_ERROR.name(), "Expected reading object as argument.", null);
733
+ }
734
+ }
534
735
 
535
736
  private void sendError(Promise promise, String code, String message, String task) {
536
737
  sendError(promise, code, message, task, null);
@@ -555,7 +756,7 @@ public class UqudoIdModule extends ReactContextBaseJavaModule implements Activit
555
756
  if (promise == null) {
556
757
  return;
557
758
  }
558
- if (requestCode == REQUEST_CODE_ENROLLMENT || requestCode == REQUEST_CODE_ACCOUNT_RECOVERY || requestCode == REQUEST_CODE_FACE_SESSION || requestCode == REQUEST_CODE_LOOKUP) {
759
+ if (requestCode == REQUEST_CODE_ENROLLMENT || requestCode == REQUEST_CODE_ACCOUNT_RECOVERY || requestCode == REQUEST_CODE_FACE_SESSION || requestCode == REQUEST_CODE_LOOKUP || requestCode == REQUEST_CODE_READING) {
559
760
  if (resultCode == Activity.RESULT_OK) {
560
761
  WritableMap map = Arguments.createMap();
561
762
  map.putString("result", data.getStringExtra("data"));
package/index.js CHANGED
@@ -1 +1 @@
1
- export * from "./uqudoBuilder/uqudo";
1
+ export * from "./uqudoBuilder/uqudo.js";
package/ios/UqudoId.m CHANGED
@@ -103,6 +103,21 @@ RCT_EXPORT_METHOD(enroll:(NSString *)enrollObj resolver:(RCTPromiseResolveBlock)
103
103
  if (facialRecognitionSpecification[@"isOneToNVerificationEnabled"]) {
104
104
  config.enableOneToNVerification = [[facialRecognitionSpecification valueForKey:@"isOneToNVerificationEnabled"] boolValue];
105
105
  }
106
+
107
+ if (facialRecognitionSpecification[@"enableActiveLiveness"] && [facialRecognitionSpecification[@"enableActiveLiveness"] boolValue]) {
108
+ config.enableActiveLiveness = YES;
109
+ }
110
+
111
+ if (facialRecognitionSpecification[@"disableLivenessGesture"]) {
112
+ NSString *gesture = facialRecognitionSpecification[@"disableLivenessGesture"];
113
+ if ([gesture isEqualToString:@"FACE_MOVE"]) {
114
+ config.disableLivenessGesture = FACE_MOVE;
115
+ } else if ([gesture isEqualToString:@"FACE_TILT"]) {
116
+ config.disableLivenessGesture = FACE_TILT;
117
+ } else if ([gesture isEqualToString:@"FACE_TURN"]) {
118
+ config.disableLivenessGesture = FACE_TURN;
119
+ }
120
+ }
106
121
 
107
122
  enrollmentBuilder.facialRecognitionConfig = config;
108
123
  }
@@ -128,8 +143,8 @@ RCT_EXPORT_METHOD(enroll:(NSString *)enrollObj resolver:(RCTPromiseResolveBlock)
128
143
  if (backgroundCheckConfiguration[@"disableConsent"]) {
129
144
  isDisableConsent = [[backgroundCheckConfiguration valueForKey:@"disableConsent"] boolValue];
130
145
  }
131
- if (backgroundCheckConfiguration[@"backgroudCheckType"]) {
132
- if ([backgroundCheckConfiguration[@"backgroudCheckType"] isEqual:@"RDC"]) {
146
+ if (backgroundCheckConfiguration[@"backgroundCheckType"]) {
147
+ if ([backgroundCheckConfiguration[@"backgroundCheckType"] isEqual:@"RDC"]) {
133
148
  type = RDC;
134
149
  } else {
135
150
  type = DOW_JONES;
@@ -394,6 +409,21 @@ RCT_EXPORT_METHOD(faceSession:(NSString *)configuration resolver:(RCTPromiseReso
394
409
  }
395
410
  }
396
411
 
412
+ if (json[@"enableActiveLiveness"] && [json[@"enableActiveLiveness"] boolValue]) {
413
+ faceSessionBuilder.enableActiveLiveness = YES;
414
+ }
415
+
416
+ if (json[@"disableLivenessGesture"]) {
417
+ NSString *gesture = json[@"disableLivenessGesture"];
418
+ if ([gesture isEqualToString:@"FACE_MOVE"]) {
419
+ faceSessionBuilder.disableLivenessGesture = FACE_MOVE;
420
+ } else if ([gesture isEqualToString:@"FACE_TILT"]) {
421
+ faceSessionBuilder.disableLivenessGesture = FACE_TILT;
422
+ } else if ([gesture isEqualToString:@"FACE_TURN"]) {
423
+ faceSessionBuilder.disableLivenessGesture = FACE_TURN;
424
+ }
425
+ }
426
+
397
427
  builderController.delegate = self;
398
428
  UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
399
429
  builderController.appViewController = rootViewController;
@@ -511,6 +541,21 @@ RCT_EXPORT_METHOD(lookup:(NSString *)lookupObj resolver:(RCTPromiseResolveBlock)
511
541
  if (facialRecognitionSpecification[@"isOneToNVerificationEnabled"]) {
512
542
  config.enableOneToNVerification = [[facialRecognitionSpecification valueForKey:@"isOneToNVerificationEnabled"] boolValue];
513
543
  }
544
+
545
+ if (facialRecognitionSpecification[@"enableActiveLiveness"] && [facialRecognitionSpecification[@"enableActiveLiveness"] boolValue]) {
546
+ config.enableActiveLiveness = YES;
547
+ }
548
+
549
+ if (facialRecognitionSpecification[@"disableLivenessGesture"]) {
550
+ NSString *gesture = facialRecognitionSpecification[@"disableLivenessGesture"];
551
+ if ([gesture isEqualToString:@"FACE_MOVE"]) {
552
+ config.disableLivenessGesture = FACE_MOVE;
553
+ } else if ([gesture isEqualToString:@"FACE_TILT"]) {
554
+ config.disableLivenessGesture = FACE_TILT;
555
+ } else if ([gesture isEqualToString:@"FACE_TURN"]) {
556
+ config.disableLivenessGesture = FACE_TURN;
557
+ }
558
+ }
514
559
 
515
560
  lookupBuilder.facialRecognitionConfig = config;
516
561
 
@@ -522,8 +567,8 @@ RCT_EXPORT_METHOD(lookup:(NSString *)lookupObj resolver:(RCTPromiseResolveBlock)
522
567
  if (backgroundCheckConfiguration[@"disableConsent"]) {
523
568
  isDisableConsent = [[backgroundCheckConfiguration valueForKey:@"disableConsent"] boolValue];
524
569
  }
525
- if (backgroundCheckConfiguration[@"backgroudCheckType"]) {
526
- if ([backgroundCheckConfiguration[@"backgroudCheckType"] isEqual:@"RDC"]) {
570
+ if (backgroundCheckConfiguration[@"backgroundCheckType"]) {
571
+ if ([backgroundCheckConfiguration[@"backgroundCheckType"] isEqual:@"RDC"]) {
527
572
  type = RDC;
528
573
  } else {
529
574
  type = DOW_JONES;
@@ -657,6 +702,198 @@ RCT_EXPORT_METHOD(isLookupFacialRecognitionSupported:(NSString *)documentType re
657
702
  }
658
703
  }
659
704
 
705
+ RCT_EXPORT_METHOD(reading:(NSString *)readingObj resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
706
+ self.promiseResolve = resolve;
707
+ self.promiseReject = reject;
708
+
709
+ @try {
710
+ if (readingObj != nil && [readingObj length] > 0) {
711
+ UQBuilderController *builderController = [UQBuilderController defaultBuilder];
712
+ dispatch_sync(dispatch_get_main_queue(), ^{
713
+ NSData *data = [readingObj dataUsingEncoding:NSUTF8StringEncoding];
714
+ NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
715
+
716
+ UQReadingBuilder *readingBuilder = [[UQReadingBuilder alloc] init];
717
+
718
+ if (json[@"authorizationToken"]) {
719
+ [readingBuilder setToken:json[@"authorizationToken"]];
720
+ }
721
+
722
+ if (json[@"sessionId"]) {
723
+ [readingBuilder setSessionId:json[@"sessionId"]];
724
+ }
725
+
726
+ NSString* userIdentifier = json[@"userIdentifier"];
727
+ if (userIdentifier && userIdentifier.length > 0) {
728
+ NSUUID *userID = [[NSUUID alloc] initWithUUIDString:userIdentifier];
729
+ if (userID) {
730
+ [readingBuilder setUserIdentifier:userID];
731
+ }
732
+ }
733
+
734
+ if (json[@"nonce"]) {
735
+ [readingBuilder setNonce:json[@"nonce"]];
736
+ }
737
+
738
+ if (json[@"documentType"]) {
739
+ UQDocumentConfig *documentObject = [[UQDocumentConfig alloc] initWithDocumentTypeName:json[@"documentType"]];
740
+ [readingBuilder setDocumentType:documentObject.documentType];
741
+ }
742
+
743
+ if (json[@"documentNumber"]) {
744
+ [readingBuilder setDocumentNumber:json[@"documentNumber"]];
745
+ }
746
+
747
+ if (json[@"dateOfBirth"]) {
748
+ [readingBuilder setDateOfBirth:json[@"dateOfBirth"]];
749
+ }
750
+
751
+ if (json[@"dateOfExpiry"]) {
752
+ [readingBuilder setDateOfExpiry:json[@"dateOfExpiry"]];
753
+ }
754
+
755
+ if (json[@"mrz"]) {
756
+ readingBuilder.mrz = json[@"mrz"];
757
+ }
758
+
759
+ if (json[@"isReturnDataForIncompleteSession"] && [json[@"isReturnDataForIncompleteSession"] boolValue]) {
760
+ [readingBuilder returnDataForIncompleteSession];
761
+ }
762
+
763
+ if (json[@"isSecuredWindowsDisabled"] && [json[@"isSecuredWindowsDisabled"] boolValue]) {
764
+ [readingBuilder disableSecureWindow];
765
+ }
766
+
767
+ if (json[@"facialRecognitionSpecification"]) {
768
+ NSDictionary *frConfig = json[@"facialRecognitionSpecification"];
769
+ UQFacialRecognitionConfig *config = [[UQFacialRecognitionConfig alloc] init];
770
+ config.enableFacialRecognition = YES;
771
+
772
+ if (frConfig[@"enrollFace"] && [frConfig[@"enrollFace"] boolValue]) {
773
+ config.enrollFace = YES;
774
+ }
775
+
776
+ if (frConfig[@"scanMinimumMatchLevel"]) {
777
+ config.scanMinimumMatchLevel = [frConfig[@"scanMinimumMatchLevel"] intValue];
778
+ }
779
+
780
+ if (frConfig[@"readMinimumMatchLevel"]) {
781
+ config.readMinimumMatchLevel = [frConfig[@"readMinimumMatchLevel"] intValue];
782
+ }
783
+
784
+ if (frConfig[@"lookupMinimumMatchLevel"]) {
785
+ config.minimumMatchLevel = [frConfig[@"lookupMinimumMatchLevel"] intValue];
786
+ }
787
+
788
+ if (frConfig[@"maxAttempts"]) {
789
+ int maxAttempts = [frConfig[@"maxAttempts"] intValue];
790
+ if (maxAttempts > 0) {
791
+ config.maxAttempts = maxAttempts;
792
+ }
793
+ }
794
+
795
+ if (frConfig[@"allowClosedEyes"] && [frConfig[@"allowClosedEyes"] boolValue]) {
796
+ config.allowClosedEyes = YES;
797
+ }
798
+
799
+ if (frConfig[@"obfuscationType"]) {
800
+ if ([frConfig[@"obfuscationType"] isEqualToString:@"BLURRED"]) {
801
+ config.obfuscationType = BLURRED;
802
+ } else if ([frConfig[@"obfuscationType"] isEqualToString:@"FILLED"]) {
803
+ config.obfuscationType = FILLED;
804
+ } else if ([frConfig[@"obfuscationType"] isEqualToString:@"FILLED_WHITE"]) {
805
+ config.obfuscationType = FILLED_WHITE;
806
+ }
807
+ }
808
+
809
+ if (frConfig[@"isOneToNVerificationEnabled"] && [frConfig[@"isOneToNVerificationEnabled"] boolValue]) {
810
+ config.enableOneToNVerification = YES;
811
+ }
812
+
813
+ if (frConfig[@"enableActiveLiveness"] && [frConfig[@"enableActiveLiveness"] boolValue]) {
814
+ config.enableActiveLiveness = YES;
815
+ }
816
+
817
+ if (frConfig[@"disableLivenessGesture"]) {
818
+ NSString *gesture = frConfig[@"disableLivenessGesture"];
819
+ if ([gesture isEqualToString:@"FACE_MOVE"]) {
820
+ config.disableLivenessGesture = FACE_MOVE;
821
+ } else if ([gesture isEqualToString:@"FACE_TILT"]) {
822
+ config.disableLivenessGesture = FACE_TILT;
823
+ } else if ([gesture isEqualToString:@"FACE_TURN"]) {
824
+ config.disableLivenessGesture = FACE_TURN;
825
+ }
826
+ }
827
+
828
+ [readingBuilder enableFacialRecognition:config];
829
+ }
830
+
831
+ if (json[@"backgroundCheckConfiguration"]) {
832
+ NSDictionary *bgConfig = json[@"backgroundCheckConfiguration"];
833
+
834
+ BOOL isDisableConsent = bgConfig[@"disableConsent"] && [bgConfig[@"disableConsent"] boolValue];
835
+ BOOL isMonitoringEnabled = bgConfig[@"monitoringEnabled"] && [bgConfig[@"monitoringEnabled"] boolValue];
836
+ BOOL isSkipView = bgConfig[@"skipView"] && [bgConfig[@"skipView"] boolValue];
837
+
838
+ BackgroundCheckType type = RDC;
839
+ if (bgConfig[@"backgroundCheckType"]) {
840
+ if ([bgConfig[@"backgroundCheckType"] isEqualToString:@"DOW_JONES"]) {
841
+ type = DOW_JONES;
842
+ }
843
+ }
844
+
845
+ [readingBuilder enableBackgroundCheck:isDisableConsent type:type monitoring:isMonitoringEnabled skipView:isSkipView];
846
+ }
847
+
848
+ if (json[@"isLookupEnabled"] && [json[@"isLookupEnabled"] boolValue]) {
849
+ [readingBuilder enableLookup];
850
+ }
851
+
852
+ builderController.delegate = self;
853
+ [builderController setReading:readingBuilder];
854
+
855
+ UIViewController *rootViewController = UIApplication.sharedApplication.keyWindow.rootViewController;
856
+ builderController.appViewController = rootViewController;
857
+
858
+ NSInteger appearanceMode = SYSTEM;
859
+ if (json[@"appearanceMode"]) {
860
+ if ([json[@"appearanceMode"] isEqualToString:@"LIGHT"]) {
861
+ appearanceMode = LIGHT;
862
+ } else if ([json[@"appearanceMode"] isEqualToString:@"DARK"]) {
863
+ appearanceMode = DARK;
864
+ }
865
+ }
866
+ [builderController setAppearanceMode:appearanceMode];
867
+ });
868
+ [builderController performReading];
869
+ } else {
870
+ UQSessionStatus *status = [[UQSessionStatus alloc] init];
871
+ status.statusCode = UNEXPECTED_ERROR;
872
+ status.message = @"Expected reading object as argument.";
873
+ status.statusTask = -1;
874
+ [self sendPluginError:status];
875
+ }
876
+ }
877
+ @catch (NSException *exception) {
878
+ NSLog(@"%@", exception.callStackSymbols);
879
+ UQSessionStatus *status = [[UQSessionStatus alloc] init];
880
+ status.statusCode = UNEXPECTED_ERROR;
881
+ status.message = exception.reason;
882
+ status.statusTask = -1;
883
+ [self sendPluginError:status];
884
+ }
885
+ }
886
+
887
+ - (void)didReadingCompleteWithInfo:(nonnull NSString *)jwsString {
888
+ NSMutableDictionary *jsonResults = [[NSMutableDictionary alloc]init];
889
+ [jsonResults setValue:jwsString forKey:@"result"];
890
+ self.promiseResolve(jsonResults);
891
+ }
892
+
893
+ - (void)didReadingIncompleteWithStatus:(UQSessionStatus *)status {
894
+ [self sendPluginError:status];
895
+ }
896
+
660
897
  - (void)sendPluginError:(UQSessionStatus *)status {
661
898
  NSString *code = nil;
662
899
  switch (status.statusCode) {
@@ -690,6 +927,9 @@ RCT_EXPORT_METHOD(isLookupFacialRecognitionSupported:(NSString *)documentType re
690
927
  case SESSION_INVALIDATED_CAMERA_PERMISSION_NOT_GRANTED:
691
928
  code = @"SESSION_INVALIDATED_CAMERA_PERMISSION_NOT_GRANTED";
692
929
  break;
930
+ case SESSION_INVALIDATED_READING_AUTHENTICATION_FAILED:
931
+ code = @"SESSION_INVALIDATED_READING_AUTHENTICATION_FAILED";
932
+ break;
693
933
  }
694
934
  NSString *task = nil;
695
935
  switch (status.statusTask) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "uqudosdk-react-native",
3
3
  "title": "React Native UqudoId",
4
- "version": "3.4.2",
4
+ "version": "3.5.0",
5
5
  "description": "Uqudo SDK react native module",
6
6
  "main": "index.js",
7
7
  "author": {
@@ -52,6 +52,11 @@ export class UqudoIdSDK {
52
52
  return await NativeModules.UqudoId.isEnrollmentSupported(documentType);
53
53
  }
54
54
 
55
+ async reading(readingConfiguration) {
56
+ var result = await NativeModules.UqudoId.reading(JSON.stringify(readingConfiguration));
57
+ return result;
58
+ }
59
+
55
60
  }
56
61
 
57
62
  export const DocumentType = Object.freeze(
@@ -113,6 +118,9 @@ export const DocumentType = Object.freeze(
113
118
  LBN_DL: 'LBN_DL',
114
119
  MRZ: 'MRZ',
115
120
  IRQ_ID: 'IRQ_ID',
121
+ IDN_ID: 'IDN_ID',
122
+ IRQ_ID_NATIONAL: 'IRQ_ID_NATIONAL',
123
+ IRQ_ID_RESIDENT: 'IRQ_ID_RESIDENT',
116
124
  UAE_ID_DIGITAL: 'UAE_ID_DIGITAL',
117
125
  QAT_VL:'QAT_VL',
118
126
  UAE_PASSPORT_DIGITAL: 'UAE_PASSPORT_DIGITAL',
@@ -144,6 +152,14 @@ export const AppearanceMode = Object.freeze(
144
152
  }
145
153
  );
146
154
 
155
+ export const LivenessGesture = Object.freeze(
156
+ {
157
+ FACE_MOVE: 'FACE_MOVE',
158
+ FACE_TILT: 'FACE_TILT',
159
+ FACE_TURN: 'FACE_TURN'
160
+ }
161
+ );
162
+
147
163
  export const ObfuscationType = Object.freeze(
148
164
  {
149
165
  FILLED: 'FILLED',
@@ -311,8 +327,16 @@ export class FacialRecognitionConfigurationBuilder {
311
327
  return this;
312
328
  },
313
329
 
330
+ enableActiveLiveness: function (gesture) {
331
+ this.enableActiveLiveness = true;
332
+ if (gesture) {
333
+ this.disableLivenessGesture = gesture;
334
+ }
335
+ return this;
336
+ },
337
+
314
338
  build: function () {
315
- return new FacialRecognitionConfiguration(this.enrollFace, this.scanMinimumMatchLevel, this.readMinimumMatchLevel, this.lookupMinimumMatchLevel, this.maxAttempts,this.isAllowClosedEyes,this.obfuscationType,this.isOneToNVerificationEnabled);
339
+ return new FacialRecognitionConfiguration(this.enrollFace, this.scanMinimumMatchLevel, this.readMinimumMatchLevel, this.lookupMinimumMatchLevel, this.maxAttempts,this.isAllowClosedEyes,this.obfuscationType,this.isOneToNVerificationEnabled,this.enableActiveLiveness,this.disableLivenessGesture);
316
340
  }
317
341
  };
318
342
  }
@@ -320,7 +344,7 @@ export class FacialRecognitionConfigurationBuilder {
320
344
 
321
345
 
322
346
  export class FacialRecognitionConfiguration {
323
- constructor(enrollFace, scanMinimumMatchLevel, readMinimumMatchLevel, lookupMinimumMatchLevel, maxAttempts,isAllowClosedEyes,obfuscationType,isOneToNVerificationEnabled) {
347
+ constructor(enrollFace, scanMinimumMatchLevel, readMinimumMatchLevel, lookupMinimumMatchLevel, maxAttempts,isAllowClosedEyes,obfuscationType,isOneToNVerificationEnabled,enableActiveLiveness,disableLivenessGesture) {
324
348
  this.enrollFace = enrollFace;
325
349
  this.scanMinimumMatchLevel = scanMinimumMatchLevel;
326
350
  this.readMinimumMatchLevel = readMinimumMatchLevel;
@@ -329,6 +353,8 @@ export class FacialRecognitionConfiguration {
329
353
  this.allowClosedEyes = isAllowClosedEyes;
330
354
  this.obfuscationType = obfuscationType;
331
355
  this.isOneToNVerificationEnabled = isOneToNVerificationEnabled;
356
+ this.enableActiveLiveness = enableActiveLiveness;
357
+ this.disableLivenessGesture = disableLivenessGesture;
332
358
  }
333
359
  }
334
360
 
@@ -688,16 +714,23 @@ export class FaceSessionBuilder {
688
714
  return this;
689
715
  },
690
716
 
717
+ enableActiveLiveness: function (gesture) {
718
+ this.enableActiveLiveness = true;
719
+ if (gesture) {
720
+ this.disableLivenessGesture = gesture;
721
+ }
722
+ return this;
723
+ },
691
724
 
692
725
  build: function () {
693
- return new FaceSessionConfiguration(this.authorizationToken, this.sessionId, this.nonce, this.userIdentifier, this.isRootedDeviceAllowed, this.isSecuredWindowsDisabled, this.minimumMatchLevel, this.maxAttempts, this.isReturnDataForIncompleteSession, this.appearanceMode,this.isAllowClosedEyes,this.obfuscationType);
726
+ return new FaceSessionConfiguration(this.authorizationToken, this.sessionId, this.nonce, this.userIdentifier, this.isRootedDeviceAllowed, this.isSecuredWindowsDisabled, this.minimumMatchLevel, this.maxAttempts, this.isReturnDataForIncompleteSession, this.appearanceMode,this.isAllowClosedEyes,this.obfuscationType,this.enableActiveLiveness,this.disableLivenessGesture);
694
727
  }
695
728
  }
696
729
  }
697
730
  }
698
731
 
699
732
  export class FaceSessionConfiguration {
700
- constructor(token, sessionId, nonce, userIdentifier, isRootedDeviceAllowed, isSecuredWindowsDisabled, minimumMatchLevel,maxAttempts,isReturnDataForIncompleteSession,appearanceMode,isAllowClosedEyes,obfuscationType) {
733
+ constructor(token, sessionId, nonce, userIdentifier, isRootedDeviceAllowed, isSecuredWindowsDisabled, minimumMatchLevel,maxAttempts,isReturnDataForIncompleteSession,appearanceMode,isAllowClosedEyes,obfuscationType,enableActiveLiveness,disableLivenessGesture) {
701
734
  this.token = token;
702
735
  this.sessionId = sessionId;
703
736
  this.nonce = nonce;
@@ -710,6 +743,8 @@ export class FaceSessionConfiguration {
710
743
  this.appearanceMode = appearanceMode;
711
744
  this.allowClosedEyes = isAllowClosedEyes;
712
745
  this.obfuscationType = obfuscationType;
746
+ this.enableActiveLiveness = enableActiveLiveness;
747
+ this.disableLivenessGesture = disableLivenessGesture;
713
748
  }
714
749
  }
715
750
 
@@ -730,6 +765,122 @@ export class Lookup {
730
765
  }
731
766
  }
732
767
 
768
+ export class Reading {
769
+ constructor(authorizationToken, sessionId, userIdentifier, nonce, documentType,
770
+ documentNumber, dateOfBirth, dateOfExpiry, mrz, isReturnDataForIncompleteSession,
771
+ isSecuredWindowsDisabled, facialRecognitionSpecification, backgroundCheckConfiguration,
772
+ isLookupEnabled, appearanceMode) {
773
+ this.authorizationToken = authorizationToken;
774
+ this.sessionId = sessionId;
775
+ this.userIdentifier = userIdentifier;
776
+ this.nonce = nonce;
777
+ this.documentType = documentType;
778
+ this.documentNumber = documentNumber;
779
+ this.dateOfBirth = dateOfBirth;
780
+ this.dateOfExpiry = dateOfExpiry;
781
+ this.mrz = mrz;
782
+ this.isReturnDataForIncompleteSession = isReturnDataForIncompleteSession;
783
+ this.isSecuredWindowsDisabled = isSecuredWindowsDisabled;
784
+ this.facialRecognitionSpecification = facialRecognitionSpecification;
785
+ this.backgroundCheckConfiguration = backgroundCheckConfiguration;
786
+ this.isLookupEnabled = isLookupEnabled;
787
+ this.appearanceMode = appearanceMode;
788
+ }
789
+ }
790
+
791
+ export class ReadingBuilder {
792
+ setToken(token) {
793
+ this.authorizationToken = token;
794
+ return this;
795
+ }
796
+
797
+ setSessionId(sessionId) {
798
+ this.sessionId = sessionId;
799
+ return this;
800
+ }
801
+
802
+ setUserIdentifier(userIdentifier) {
803
+ this.userIdentifier = userIdentifier;
804
+ return this;
805
+ }
806
+
807
+ setNonce(nonce) {
808
+ this.nonce = nonce;
809
+ return this;
810
+ }
811
+
812
+ setDocumentType(documentType) {
813
+ this.documentType = documentType;
814
+ return this;
815
+ }
816
+
817
+ setDocumentNumber(documentNumber) {
818
+ this.documentNumber = documentNumber;
819
+ return this;
820
+ }
821
+
822
+ setDateOfBirth(dateOfBirth) {
823
+ this.dateOfBirth = dateOfBirth;
824
+ return this;
825
+ }
826
+
827
+ setDateOfExpiry(dateOfExpiry) {
828
+ this.dateOfExpiry = dateOfExpiry;
829
+ return this;
830
+ }
831
+
832
+ setMrz(mrz) {
833
+ this.mrz = mrz;
834
+ return this;
835
+ }
836
+
837
+ returnDataForIncompleteSession() {
838
+ this.isReturnDataForIncompleteSession = true;
839
+ return this;
840
+ }
841
+
842
+ disableSecureWindow() {
843
+ this.isSecuredWindowsDisabled = true;
844
+ return this;
845
+ }
846
+
847
+ enableFacialRecognition() {
848
+ if (arguments.length === 0) {
849
+ this.facialRecognitionSpecification = new FacialRecognitionConfigurationBuilder().build();
850
+ } else {
851
+ this.facialRecognitionSpecification = arguments[0];
852
+ }
853
+ return this;
854
+ }
855
+
856
+ enableBackgroundCheck() {
857
+ if (arguments.length === 0) {
858
+ this.backgroundCheckConfiguration = new BackgroundCheckConfigurationBuilder().build();
859
+ } else {
860
+ this.backgroundCheckConfiguration = arguments[0];
861
+ }
862
+ return this;
863
+ }
864
+
865
+ enableLookup() {
866
+ this.isLookupEnabled = true;
867
+ return this;
868
+ }
869
+
870
+ setAppearanceMode(appearanceMode) {
871
+ this.appearanceMode = appearanceMode;
872
+ return this;
873
+ }
874
+
875
+ build() {
876
+ return new Reading(this.authorizationToken, this.sessionId, this.userIdentifier, this.nonce,
877
+ this.documentType, this.documentNumber, this.dateOfBirth, this.dateOfExpiry, this.mrz,
878
+ this.isReturnDataForIncompleteSession, this.isSecuredWindowsDisabled,
879
+ this.facialRecognitionSpecification, this.backgroundCheckConfiguration,
880
+ this.isLookupEnabled, this.appearanceMode);
881
+ }
882
+ }
883
+
733
884
  export class LookupBuilder {
734
885
  setToken(token) {
735
886
  this.authorizationToken = token;
@@ -13,5 +13,5 @@ Pod::Spec.new do |s|
13
13
  s.source = { :http => 'https://uqudo.com' }
14
14
  s.header_dir = 'UqudoSDK'
15
15
  s.dependency 'React'
16
- s.dependency 'UqudoSDK', '3.4.2'
16
+ s.dependency 'UqudoSDK', '3.5.1'
17
17
  end