@soyio/soyio-rn-sdk 4.1.13 → 4.1.14

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.
@@ -1,44 +1,75 @@
1
1
  package com.soyio.soyiorndk
2
2
 
3
+ import android.app.Activity
4
+ import android.app.Application
5
+ import android.os.Bundle
3
6
  import android.os.Handler
4
7
  import android.os.Looper
5
8
  import com.facebook.react.bridge.Arguments
6
9
  import com.facebook.react.bridge.Promise
7
- import java.util.concurrent.atomic.AtomicBoolean
10
+ import com.facetec.sdk.FaceTecSessionActivity
8
11
 
9
12
  abstract class BaseFaceTecProcessor(
10
13
  private val promise: Promise,
11
14
  private val errorCode: String,
15
+ activity: Activity,
12
16
  ) {
13
17
  private val mainHandler = Handler(Looper.getMainLooper())
14
- private val promiseCompleted = AtomicBoolean(false)
18
+ private val application = activity.application
19
+ private var promiseResolved = false
15
20
  protected val defaultError = "unknown_error"
16
21
  protected val flowCancelledError = "FLOW_CANCELLED"
17
22
 
18
- protected fun resolveSuccess() {
19
- if (promiseCompleted.compareAndSet(false, true)) {
20
- mainHandler.post {
21
- val result = Arguments.createMap().apply { putBoolean("success", true) }
22
- promise.resolve(result)
23
+ @Volatile private var isSuccess = false
24
+ @Volatile private var failureMessage: String? = null
25
+
26
+ private val lifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
27
+ override fun onActivityDestroyed(a: Activity) {
28
+ if (a is FaceTecSessionActivity) {
29
+ resolveFromTrackedState()
30
+ application.unregisterActivityLifecycleCallbacks(this)
23
31
  }
24
32
  }
33
+ override fun onActivityCreated(a: Activity, b: Bundle?) {}
34
+ override fun onActivityStarted(a: Activity) {}
35
+ override fun onActivityResumed(a: Activity) {}
36
+ override fun onActivityPaused(a: Activity) {}
37
+ override fun onActivityStopped(a: Activity) {}
38
+ override fun onActivitySaveInstanceState(a: Activity, b: Bundle) {}
39
+ }
40
+
41
+ init {
42
+ application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
43
+ }
44
+
45
+ protected fun markSuccess() {
46
+ isSuccess = true
47
+ failureMessage = null
48
+ }
49
+
50
+ protected fun markFailure(message: String = defaultError) {
51
+ isSuccess = false
52
+ failureMessage = message
25
53
  }
26
54
 
27
- protected fun resolveFailure(message: String = defaultError) {
28
- if (promiseCompleted.compareAndSet(false, true)) {
29
- mainHandler.post {
30
- val result = Arguments.createMap().apply {
31
- putBoolean("success", false)
32
- putString("error", message)
33
- }
34
- promise.resolve(result)
55
+ @Synchronized
56
+ private fun resolveFromTrackedState() {
57
+ if (promiseResolved) return
58
+ promiseResolved = true
59
+ mainHandler.post {
60
+ val result = Arguments.createMap().apply {
61
+ putBoolean("success", isSuccess)
62
+ if (!isSuccess) putString("error", failureMessage ?: defaultError)
35
63
  }
64
+ promise.resolve(result)
36
65
  }
37
66
  }
38
67
 
68
+ @Synchronized
39
69
  protected fun reject(message: String) {
40
- if (promiseCompleted.compareAndSet(false, true)) {
41
- mainHandler.post { promise.reject(errorCode, message) }
42
- }
70
+ if (promiseResolved) return
71
+ promiseResolved = true
72
+ application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
73
+ mainHandler.post { promise.reject(errorCode, message) }
43
74
  }
44
75
  }
@@ -17,7 +17,7 @@ class SoyioIdOnlyProcessor(
17
17
  requestableToken: String,
18
18
  authToken: String,
19
19
  promise: Promise,
20
- ) : BaseFaceTecProcessor(promise, FACETEC_ID_ERROR), FaceTecIDScanProcessor {
20
+ ) : BaseFaceTecProcessor(promise, FACETEC_ID_ERROR, activity), FaceTecIDScanProcessor {
21
21
 
22
22
  private val requestService = FaceTecRequestService(
23
23
  baseUrl = baseUrl,
@@ -36,7 +36,7 @@ class SoyioIdOnlyProcessor(
36
36
  ) {
37
37
  if (idScanResult.status != FaceTecIDScanStatus.SUCCESS) {
38
38
  idScanResultCallback.cancel()
39
- resolveFailure(flowCancelledError)
39
+ markFailure(flowCancelledError)
40
40
  return
41
41
  }
42
42
 
@@ -61,16 +61,16 @@ class SoyioIdOnlyProcessor(
61
61
 
62
62
  if (error || !wasProcessed || scanResultBlob.isNullOrBlank()) {
63
63
  idScanResultCallback.cancel()
64
- resolveFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
64
+ markFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
65
65
  return@post
66
66
  }
67
67
 
68
68
  idScanResultCallback.proceedToNextStep(scanResultBlob)
69
- resolveSuccess()
69
+ markSuccess()
70
70
  },
71
71
  onFailure = {
72
72
  idScanResultCallback.cancel()
73
- resolveFailure(it.ifBlank { defaultError })
73
+ markFailure(it.ifBlank { defaultError })
74
74
  },
75
75
  )
76
76
  }
@@ -22,7 +22,7 @@ class SoyioValidationProcessor(
22
22
  authToken: String,
23
23
  promise: Promise,
24
24
  private val onLivenessSuccess: (() -> Unit)? = null,
25
- ) : BaseFaceTecProcessor(promise, FACETEC_VALIDATION_ERROR), FaceTecFaceScanProcessor, FaceTecIDScanProcessor {
25
+ ) : BaseFaceTecProcessor(promise, FACETEC_VALIDATION_ERROR, activity), FaceTecFaceScanProcessor, FaceTecIDScanProcessor {
26
26
 
27
27
  private val requestService = FaceTecRequestService(
28
28
  baseUrl = baseUrl,
@@ -46,7 +46,7 @@ class SoyioValidationProcessor(
46
46
  ) {
47
47
  if (sessionResult.status != FaceTecSessionStatus.SESSION_COMPLETED_SUCCESSFULLY) {
48
48
  faceScanResultCallback.cancel()
49
- resolveFailure(flowCancelledError)
49
+ markFailure(flowCancelledError)
50
50
  return
51
51
  }
52
52
 
@@ -70,7 +70,7 @@ class SoyioValidationProcessor(
70
70
 
71
71
  if (error || !wasProcessed || scanResultBlob.isNullOrBlank()) {
72
72
  faceScanResultCallback.cancel()
73
- resolveFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
73
+ markFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
74
74
  return@post
75
75
  }
76
76
 
@@ -79,7 +79,7 @@ class SoyioValidationProcessor(
79
79
  },
80
80
  onFailure = {
81
81
  faceScanResultCallback.cancel()
82
- resolveFailure(it.ifBlank { defaultError })
82
+ markFailure(it.ifBlank { defaultError })
83
83
  },
84
84
  )
85
85
  }
@@ -90,7 +90,7 @@ class SoyioValidationProcessor(
90
90
  ) {
91
91
  if (idScanResult.status != FaceTecIDScanStatus.SUCCESS) {
92
92
  idScanResultCallback.cancel()
93
- resolveFailure(flowCancelledError)
93
+ markFailure(flowCancelledError)
94
94
  return
95
95
  }
96
96
 
@@ -114,16 +114,16 @@ class SoyioValidationProcessor(
114
114
 
115
115
  if (error || !wasProcessed || scanResultBlob.isNullOrBlank()) {
116
116
  idScanResultCallback.cancel()
117
- resolveFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
117
+ markFailure(errorMessage.takeIf { it.isNotBlank() } ?: defaultError)
118
118
  return@post
119
119
  }
120
120
 
121
121
  idScanResultCallback.proceedToNextStep(scanResultBlob)
122
- resolveSuccess()
122
+ markSuccess()
123
123
  },
124
124
  onFailure = {
125
125
  idScanResultCallback.cancel()
126
- resolveFailure(it.ifBlank { defaultError })
126
+ markFailure(it.ifBlank { defaultError })
127
127
  },
128
128
  )
129
129
  }
@@ -152,12 +152,14 @@ class SoyioIDOnlyProcessor: NSObject, Processor, FaceTecIDScanProcessorDelegate,
152
152
  func onFaceTecSDKCompletelyDone() {
153
153
  // Dismiss the view controller to return to the main UI
154
154
  fromViewController.dismiss(animated: true, completion: {
155
- // Notify completion
156
- if self.success {
155
+ // Notify completion — check apiErrorMessage first, since a previous step
156
+ // may have set self.success = true before a later step (e.g. NFC) failed.
157
+ if let errorMessage = self.apiErrorMessage {
158
+ self.completionHandler?(false, errorMessage)
159
+ } else if self.success {
157
160
  self.completionHandler?(true, nil)
158
161
  } else {
159
- let errorMessage = self.apiErrorMessage ?? self.unknownErrorMessage
160
- self.completionHandler?(false, errorMessage)
162
+ self.completionHandler?(false, self.unknownErrorMessage)
161
163
  }
162
164
  })
163
165
  }
@@ -246,12 +246,14 @@ class SoyioPhotoIDMatchProcessor: NSObject, Processor, FaceTecFaceScanProcessorD
246
246
  func onFaceTecSDKCompletelyDone() {
247
247
  // Dismiss the view controller to return to the main UI
248
248
  fromViewController.dismiss(animated: true, completion: {
249
- // Notify completion
250
- if self.success {
249
+ // Notify completion — check apiErrorMessage first, since a previous step
250
+ // may have set self.success = true before a later step (e.g. NFC) failed.
251
+ if let errorMessage = self.apiErrorMessage {
252
+ self.completionHandler?(false, errorMessage)
253
+ } else if self.success {
251
254
  self.completionHandler?(true, nil)
252
255
  } else {
253
- let errorMessage = self.apiErrorMessage ?? self.unknownErrorMessage
254
- self.completionHandler?(false, errorMessage)
256
+ self.completionHandler?(false, self.unknownErrorMessage)
255
257
  }
256
258
  })
257
259
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soyio/soyio-rn-sdk",
3
- "version": "4.1.13",
3
+ "version": "4.1.14",
4
4
  "license": "MIT",
5
5
  "author": "Ignacio Méndez",
6
6
  "main": "./package/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soyio/soyio-rn-sdk",
3
- "version": "4.1.13",
3
+ "version": "4.1.14",
4
4
  "license": "MIT",
5
5
  "author": "Ignacio Méndez",
6
6
  "main": "./package/index.js",