@certiface/sdk 1.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/LICENSE +20 -0
- package/README.md +966 -0
- package/RnSdk.podspec +27 -0
- package/android/build.gradle +86 -0
- package/android/gradle.properties +6 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/RnSdkModule.kt +128 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/RnSdkPackage.kt +33 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/executor/LivenessExevutor.kt +66 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/factories/FacetecThemeFactory.kt +233 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/factories/IProovThemeFactory.kt +176 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/managers/AssetManager.kt +152 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/model/Featues.kt +6 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/processors/AssetProcessor.kt +179 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/strategy/FacetecStrategy.kt +25 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/strategy/IProovStrategy.kt +25 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/strategy/LivenessProviderStrategy.kt +16 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/theme/FacetecFonts.kt +85 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/theme/IProovFonts.kt +52 -0
- package/android/src/main/java/br/com/oititec/rn/sdk/utils/AssetProcessor.kt +181 -0
- package/android/src/main/res/drawable/backhand_left.xml +20 -0
- package/android/src/main/res/drawable/backhand_right.xml +20 -0
- package/android/src/main/res/drawable/camera_icon.xml +14 -0
- package/android/src/main/res/drawable/close_icon.xml +11 -0
- package/android/src/main/res/drawable/error_icon.xml +11 -0
- package/android/src/main/res/drawable/neutral_face.xml +11 -0
- package/android/src/main/res/drawable/success_icon.xml +11 -0
- package/android/src/main/res/font/sixty.ttf +0 -0
- package/ios/Extensions/RnSDK+Callbacks.swift +62 -0
- package/ios/Extensions/UIColor+Hex.swift +39 -0
- package/ios/Resources/Media.xcassets/Contents.json +6 -0
- package/ios/Resources/Media.xcassets/shell.imageset/Contents.json +12 -0
- package/ios/Resources/Media.xcassets/shell.imageset/shell.png +0 -0
- package/ios/Resources/Media.xcassets/test.imageset/Contents.json +12 -0
- package/ios/Resources/Media.xcassets/test.imageset/arrow_forward_ios.png +0 -0
- package/ios/RnSdk.h +5 -0
- package/ios/RnSdk.mm +71 -0
- package/ios/RnSdkImpl.swift +91 -0
- package/ios/Utils/RnSdkBundle.swift +27 -0
- package/ios/Utils/ThemeFactory.swift +424 -0
- package/lib/module/@types/result.js +2 -0
- package/lib/module/@types/result.js.map +1 -0
- package/lib/module/@types/theme.js +41 -0
- package/lib/module/@types/theme.js.map +1 -0
- package/lib/module/NativeRnSdk.js +5 -0
- package/lib/module/NativeRnSdk.js.map +1 -0
- package/lib/module/index.js +33 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/utils/AssetProcessor.js +78 -0
- package/lib/module/utils/AssetProcessor.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/@types/result.d.ts +17 -0
- package/lib/typescript/src/@types/result.d.ts.map +1 -0
- package/lib/typescript/src/@types/theme.d.ts +306 -0
- package/lib/typescript/src/@types/theme.d.ts.map +1 -0
- package/lib/typescript/src/NativeRnSdk.d.ts +9 -0
- package/lib/typescript/src/NativeRnSdk.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +14 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/AssetProcessor.d.ts +8 -0
- package/lib/typescript/src/utils/AssetProcessor.d.ts.map +1 -0
- package/package.json +165 -0
- package/src/@types/result.ts +19 -0
- package/src/@types/theme.ts +346 -0
- package/src/NativeRnSdk.ts +18 -0
- package/src/index.tsx +54 -0
- package/src/utils/AssetProcessor.ts +114 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package br.com.oititec.rn.sdk.theme
|
|
2
|
+
|
|
3
|
+
import br.com.oiti.manager.exports.IProovFontsKey
|
|
4
|
+
import com.facebook.react.bridge.ReadableMap
|
|
5
|
+
|
|
6
|
+
class IProovFonts(private val fontsBuilder: ReadableMap?) {
|
|
7
|
+
|
|
8
|
+
private val instructionsTitleFont: String =
|
|
9
|
+
"fonts/" + (fontsBuilder?.getString("instructionsTitleFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
10
|
+
|
|
11
|
+
private val instructionsCaptionFont: String =
|
|
12
|
+
"fonts/" + (fontsBuilder?.getString("instructionsCaptionFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
13
|
+
|
|
14
|
+
private val instructionsDocumentTypesInstructionsFont: String =
|
|
15
|
+
"fonts/" + (fontsBuilder?.getString("instructionsDocumentTypesInstructionsFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
16
|
+
|
|
17
|
+
private val instructionsDocumentTipsInstructionsFont: String =
|
|
18
|
+
"fonts/" + (fontsBuilder?.getString("instructionsDocumentTipsInstructionsFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
19
|
+
|
|
20
|
+
private val instructionsButtonFont: String =
|
|
21
|
+
"fonts/" + (fontsBuilder?.getString("instructionsButtonFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
22
|
+
|
|
23
|
+
private val permissionTitleFont: String =
|
|
24
|
+
"fonts/" + (fontsBuilder?.getString("permissionTitleFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
25
|
+
|
|
26
|
+
private val permissionCaptionFont: String =
|
|
27
|
+
"fonts/" + (fontsBuilder?.getString("permissionCaptionFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
28
|
+
|
|
29
|
+
private val permissionButtonFont: String =
|
|
30
|
+
"fonts/" + (fontsBuilder?.getString("permissionButtonFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
31
|
+
|
|
32
|
+
private val resultMessageFont: String =
|
|
33
|
+
"fonts/" + (fontsBuilder?.getString("resultMessageFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
34
|
+
|
|
35
|
+
private val resultRetryButtonFont: String =
|
|
36
|
+
"fonts/" + (fontsBuilder?.getString("resultRetryButtonFont")?.lowercase() ?: "ubuntu_regular") + ".ttf"
|
|
37
|
+
|
|
38
|
+
fun apply(): Map<IProovFontsKey, String> {
|
|
39
|
+
return mapOf(
|
|
40
|
+
IProovFontsKey.INSTRUCTIONS_TITLE_FONT to instructionsTitleFont,
|
|
41
|
+
IProovFontsKey.INSTRUCTIONS_CAPTION_FONT to instructionsCaptionFont,
|
|
42
|
+
IProovFontsKey.INSTRUCTIONS_DOCUMENT_TYPES_INSTRUCTIONS_FONT to instructionsDocumentTypesInstructionsFont,
|
|
43
|
+
IProovFontsKey.INSTRUCTIONS_DOCUMENT_TIPS_INSTRUCTIONS_FONT to instructionsDocumentTipsInstructionsFont,
|
|
44
|
+
IProovFontsKey.INSTRUCTIONS_BUTTON_FONT to instructionsButtonFont,
|
|
45
|
+
IProovFontsKey.PERMISSION_TITLE_FONT to permissionTitleFont,
|
|
46
|
+
IProovFontsKey.PERMISSION_CAPTION_FONT to permissionCaptionFont,
|
|
47
|
+
IProovFontsKey.PERMISSION_BUTTON_FONT to permissionButtonFont,
|
|
48
|
+
IProovFontsKey.RESULT_MESSAGE_FONT to resultMessageFont,
|
|
49
|
+
IProovFontsKey.RESULT_RETRY_BUTTON_FONT to resultRetryButtonFont,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
package br.com.oititec.rn.sdk.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.res.Resources
|
|
5
|
+
import android.graphics.Bitmap
|
|
6
|
+
import android.graphics.BitmapFactory
|
|
7
|
+
import android.graphics.drawable.BitmapDrawable
|
|
8
|
+
import android.graphics.drawable.Drawable
|
|
9
|
+
import android.util.Base64
|
|
10
|
+
import android.util.Log
|
|
11
|
+
import java.io.ByteArrayOutputStream
|
|
12
|
+
import java.io.File
|
|
13
|
+
import java.io.FileOutputStream
|
|
14
|
+
import java.util.UUID
|
|
15
|
+
import java.lang.reflect.Field
|
|
16
|
+
|
|
17
|
+
class AssetProcessor(private val context: Context) {
|
|
18
|
+
|
|
19
|
+
companion object {
|
|
20
|
+
private const val TAG = "AssetProcessor"
|
|
21
|
+
private const val ASSETS_CACHE_DIR = "theme_assets"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fun processBase64ToDrawable(base64String: String?, fallbackDrawableRes: Int): Drawable? {
|
|
25
|
+
if (base64String.isNullOrEmpty()) {
|
|
26
|
+
Log.d(TAG, "Base64 string is null or empty, using fallback")
|
|
27
|
+
return context.getDrawable(fallbackDrawableRes)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return try {
|
|
31
|
+
Log.d(TAG, "Processing base64 string: ${base64String.take(50)}...")
|
|
32
|
+
|
|
33
|
+
val cleanBase64 = if (base64String.contains("base64,")) {
|
|
34
|
+
base64String.substringAfter("base64,")
|
|
35
|
+
} else {
|
|
36
|
+
base64String
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
val decodedBytes = Base64.decode(cleanBase64, Base64.DEFAULT)
|
|
40
|
+
Log.d(TAG, "Decoded bytes size: ${decodedBytes.size}")
|
|
41
|
+
|
|
42
|
+
val bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
|
|
43
|
+
|
|
44
|
+
if (bitmap != null) {
|
|
45
|
+
Log.d(TAG, "Successfully created bitmap: ${bitmap.width}x${bitmap.height}")
|
|
46
|
+
BitmapDrawable(context.resources, bitmap)
|
|
47
|
+
} else {
|
|
48
|
+
Log.w(TAG, "Failed to decode bitmap from base64")
|
|
49
|
+
context.getDrawable(fallbackDrawableRes)
|
|
50
|
+
}
|
|
51
|
+
} catch (e: Exception) {
|
|
52
|
+
Log.e(TAG, "Error processing base64 to drawable: ${e.message}")
|
|
53
|
+
e.printStackTrace()
|
|
54
|
+
context.getDrawable(fallbackDrawableRes)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fun saveBase64AsDrawableResource(base64String: String?): Int? {
|
|
59
|
+
if (base64String.isNullOrEmpty()) return null
|
|
60
|
+
|
|
61
|
+
return try {
|
|
62
|
+
Log.d(TAG, "Saving base64 as drawable resource...")
|
|
63
|
+
|
|
64
|
+
val cleanBase64 = if (base64String.contains("base64,")) {
|
|
65
|
+
base64String.substringAfter("base64,")
|
|
66
|
+
} else {
|
|
67
|
+
base64String
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
val decodedBytes = Base64.decode(cleanBase64, Base64.DEFAULT)
|
|
71
|
+
|
|
72
|
+
val bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
|
|
73
|
+
|
|
74
|
+
if (bitmap != null) {
|
|
75
|
+
Log.d(TAG, "Successfully created bitmap from base64: ${bitmap.width}x${bitmap.height}")
|
|
76
|
+
|
|
77
|
+
val cacheDir = File(context.cacheDir, ASSETS_CACHE_DIR)
|
|
78
|
+
if (!cacheDir.exists()) {
|
|
79
|
+
cacheDir.mkdirs()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
val fileName = "asset_${System.currentTimeMillis()}.png"
|
|
83
|
+
val file = File(cacheDir, fileName)
|
|
84
|
+
|
|
85
|
+
FileOutputStream(file).use { out ->
|
|
86
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
Log.d(TAG, "Saved asset to: ${file.absolutePath}")
|
|
90
|
+
|
|
91
|
+
System.currentTimeMillis().toInt()
|
|
92
|
+
} else {
|
|
93
|
+
Log.w(TAG, "Failed to create bitmap from base64")
|
|
94
|
+
null
|
|
95
|
+
}
|
|
96
|
+
} catch (e: Exception) {
|
|
97
|
+
Log.e(TAG, "Error saving base64 as drawable resource: ${e.message}")
|
|
98
|
+
e.printStackTrace()
|
|
99
|
+
null
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fun createDrawableFromCachedFile(resourceId: Int?, fallbackDrawableRes: Int): Drawable? {
|
|
104
|
+
if (resourceId == null) {
|
|
105
|
+
return context.getDrawable(fallbackDrawableRes)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return try {
|
|
109
|
+
val cacheDir = File(context.cacheDir, ASSETS_CACHE_DIR)
|
|
110
|
+
val files = cacheDir.listFiles() ?: return context.getDrawable(fallbackDrawableRes)
|
|
111
|
+
|
|
112
|
+
val targetFile = files.find { it.absolutePath.hashCode() == resourceId }
|
|
113
|
+
|
|
114
|
+
if (targetFile?.exists() == true) {
|
|
115
|
+
val bitmap = BitmapFactory.decodeFile(targetFile.absolutePath)
|
|
116
|
+
if (bitmap != null) {
|
|
117
|
+
BitmapDrawable(context.resources, bitmap)
|
|
118
|
+
} else {
|
|
119
|
+
context.getDrawable(fallbackDrawableRes)
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
Log.w(TAG, "Cached file not found for resource ID: $resourceId")
|
|
123
|
+
context.getDrawable(fallbackDrawableRes)
|
|
124
|
+
}
|
|
125
|
+
} catch (e: Exception) {
|
|
126
|
+
Log.e(TAG, "Error creating drawable from cached file: ${e.message}")
|
|
127
|
+
context.getDrawable(fallbackDrawableRes)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fun createDynamicResourceId(drawable: Drawable?): Int? {
|
|
132
|
+
if (drawable == null) return null
|
|
133
|
+
|
|
134
|
+
return try {
|
|
135
|
+
val drawableHash = drawable.hashCode()
|
|
136
|
+
|
|
137
|
+
if (drawable is BitmapDrawable) {
|
|
138
|
+
val bitmap = drawable.bitmap
|
|
139
|
+
if (bitmap != null) {
|
|
140
|
+
val cacheDir = File(context.cacheDir, ASSETS_CACHE_DIR)
|
|
141
|
+
if (!cacheDir.exists()) {
|
|
142
|
+
cacheDir.mkdirs()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
val fileName = "dynamic_${drawableHash}.png"
|
|
146
|
+
val file = File(cacheDir, fileName)
|
|
147
|
+
|
|
148
|
+
if (!file.exists()) {
|
|
149
|
+
FileOutputStream(file).use { out ->
|
|
150
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
|
|
151
|
+
}
|
|
152
|
+
Log.d(TAG, "Created dynamic resource file: ${file.absolutePath}")
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
file.absolutePath.hashCode()
|
|
156
|
+
} else {
|
|
157
|
+
Log.w(TAG, "BitmapDrawable has null bitmap")
|
|
158
|
+
null
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
Log.d(TAG, "Drawable is not BitmapDrawable, using hash as ID")
|
|
162
|
+
drawableHash
|
|
163
|
+
}
|
|
164
|
+
} catch (e: Exception) {
|
|
165
|
+
Log.e(TAG, "Error creating dynamic resource ID: ${e.message}")
|
|
166
|
+
null
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
fun cleanupCache() {
|
|
171
|
+
try {
|
|
172
|
+
val cacheDir = File(context.cacheDir, ASSETS_CACHE_DIR)
|
|
173
|
+
if (cacheDir.exists()) {
|
|
174
|
+
cacheDir.deleteRecursively()
|
|
175
|
+
}
|
|
176
|
+
} catch (e: Exception) {
|
|
177
|
+
Log.e(TAG, "Error cleaning up cache: ${e.message}")
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FF000000"
|
|
9
|
+
android:pathData="M13,24c-0.55,0 -1,-0.45 -1,-1V12c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v11C14,23.55 13.55,24 13,24z"/>
|
|
10
|
+
<path
|
|
11
|
+
android:fillColor="#FF000000"
|
|
12
|
+
android:pathData="M9,22c-0.55,0 -1,-0.45 -1,-1V10c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v11C10,21.55 9.55,22 9,22z"/>
|
|
13
|
+
<path
|
|
14
|
+
android:fillColor="#FF000000"
|
|
15
|
+
android:pathData="M17,22c-0.55,0 -1,-0.45 -1,-1V14c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v7C18,21.55 17.55,22 17,22z"/>
|
|
16
|
+
<path
|
|
17
|
+
android:fillColor="#FF000000"
|
|
18
|
+
android:pathData="M5,20c-0.55,0 -1,-0.45 -1,-1V8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v11C6,19.55 5.55,20 5,20z"/>
|
|
19
|
+
</vector>
|
|
20
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FF000000"
|
|
9
|
+
android:pathData="M11,24c0.55,0 1,-0.45 1,-1V12c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v11C10,23.55 10.45,24 11,24z"/>
|
|
10
|
+
<path
|
|
11
|
+
android:fillColor="#FF000000"
|
|
12
|
+
android:pathData="M15,22c0.55,0 1,-0.45 1,-1V10c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v11C14,21.55 14.45,22 15,22z"/>
|
|
13
|
+
<path
|
|
14
|
+
android:fillColor="#FF000000"
|
|
15
|
+
android:pathData="M7,22c0.55,0 1,-0.45 1,-1V14c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v7C6,21.55 6.45,22 7,22z"/>
|
|
16
|
+
<path
|
|
17
|
+
android:fillColor="#FF000000"
|
|
18
|
+
android:pathData="M19,20c0.55,0 1,-0.45 1,-1V8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v11C18,19.55 18.45,20 19,20z"/>
|
|
19
|
+
</vector>
|
|
20
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FF000000"
|
|
9
|
+
android:pathData="M12,15.2c-1.25,0 -2.27,-1.02 -2.27,-2.27c0,-1.25 1.02,-2.27 2.27,-2.27c1.25,0 2.27,1.02 2.27,2.27C14.27,14.18 13.25,15.2 12,15.2z"/>
|
|
10
|
+
<path
|
|
11
|
+
android:fillColor="#FF000000"
|
|
12
|
+
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5s5,2.24 5,5S14.76,17 12,17z"/>
|
|
13
|
+
</vector>
|
|
14
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FF000000"
|
|
9
|
+
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
10
|
+
</vector>
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FFF44336"
|
|
9
|
+
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z"/>
|
|
10
|
+
</vector>
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FFFF9800"
|
|
9
|
+
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM15.5,8C16.33,8 17,8.67 17,9.5S16.33,11 15.5,11 14,10.33 14,9.5 14.67,8 15.5,8zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11 7,10.33 7,9.5 7.67,8 8.5,8zM12,17.5c-2.33,0 -4.31,-1.46 -5.11,-3.5h10.22C16.31,16.04 14.33,17.5 12,17.5z"/>
|
|
10
|
+
</vector>
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FF4CAF50"
|
|
9
|
+
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
|
10
|
+
</vector>
|
|
11
|
+
|
|
Binary file
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RnSDK+Callbacks.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Gabriel Catelli Goulart on 21/07/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import CertifaceSDK
|
|
9
|
+
|
|
10
|
+
extension RnSdkImpl: LivenessCallback {
|
|
11
|
+
public func onSuccess(_ resultData: LivenessResult) {
|
|
12
|
+
let response: [String: Any] = [
|
|
13
|
+
"status": "success",
|
|
14
|
+
"result": [
|
|
15
|
+
"valid": resultData.valid,
|
|
16
|
+
"codID": resultData.codId as Any,
|
|
17
|
+
"cause": "",
|
|
18
|
+
"protocol": resultData.protocol as Any,
|
|
19
|
+
"scanResultBlob": "",
|
|
20
|
+
],
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
if let jsonData = try? JSONSerialization.data(withJSONObject: response),
|
|
24
|
+
let jsonString = String(data: jsonData, encoding: .utf8)
|
|
25
|
+
{
|
|
26
|
+
onSuccessCallback?(jsonString)
|
|
27
|
+
} else {
|
|
28
|
+
onErrorCallback?("Failed to serialize response")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onSuccessCallback = nil
|
|
32
|
+
onErrorCallback = nil
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public func onError(_ error: LivenessError) {
|
|
36
|
+
let response: [String: Any] = [
|
|
37
|
+
"status": "error",
|
|
38
|
+
"message": "[\(error.code)]: \(error.message)",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
if let jsonData = try? JSONSerialization.data(withJSONObject: response),
|
|
42
|
+
let jsonString = String(data: jsonData, encoding: .utf8)
|
|
43
|
+
{
|
|
44
|
+
onErrorCallback?(jsonString)
|
|
45
|
+
} else {
|
|
46
|
+
onErrorCallback?("Failed to serialize error response")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
onSuccessCallback = nil
|
|
50
|
+
onErrorCallback = nil
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func getRootViewController() -> UIViewController? {
|
|
54
|
+
let windowScene = UIApplication.shared.connectedScenes
|
|
55
|
+
.compactMap { $0 as? UIWindowScene }
|
|
56
|
+
.first { $0.activationState == .foregroundActive }
|
|
57
|
+
|
|
58
|
+
let keyWindow = windowScene?.windows.first { $0.isKeyWindow }
|
|
59
|
+
|
|
60
|
+
return keyWindow?.rootViewController
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// UIColor+Hex.swift
|
|
3
|
+
// RnSdk
|
|
4
|
+
//
|
|
5
|
+
// Created by Gabriel Catelli Goulart on 01/08/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
|
|
10
|
+
extension UIColor {
|
|
11
|
+
convenience init?(hex: String) {
|
|
12
|
+
let hexString = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
13
|
+
let scanner = Scanner(
|
|
14
|
+
string: hexString.hasPrefix("#") ? String(hexString.dropFirst()) : hexString)
|
|
15
|
+
|
|
16
|
+
var color: UInt64 = 0
|
|
17
|
+
|
|
18
|
+
guard scanner.scanHexInt64(&color) else {
|
|
19
|
+
return nil
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if hexString.count == 7 || (hexString.hasPrefix("#") && hexString.count == 7) {
|
|
23
|
+
let red = Double((color & 0xFF0000) >> 16) / 255.0
|
|
24
|
+
let green = Double((color & 0x00FF00) >> 8) / 255.0
|
|
25
|
+
let blue = Double(color & 0x0000FF) / 255.0
|
|
26
|
+
|
|
27
|
+
self.init(red: red, green: green, blue: blue, alpha: 1.0)
|
|
28
|
+
} else if hexString.count == 9 || (hexString.hasPrefix("#") && hexString.count == 9) {
|
|
29
|
+
let red = Double((color & 0xFF00_0000) >> 24) / 255.0
|
|
30
|
+
let green = Double((color & 0x00FF_0000) >> 16) / 255.0
|
|
31
|
+
let blue = Double((color & 0x0000_FF00) >> 8) / 255.0
|
|
32
|
+
let alpha = Double(color & 0x0000_00FF) / 255.0
|
|
33
|
+
|
|
34
|
+
self.init(red: red, green: green, blue: blue, alpha: alpha)
|
|
35
|
+
} else {
|
|
36
|
+
return nil
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
Binary file
|
|
Binary file
|
package/ios/RnSdk.h
ADDED
package/ios/RnSdk.mm
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#import "RnSdk.h"
|
|
2
|
+
#import "RnSdk-Swift.h"
|
|
3
|
+
#import <AVFoundation/AVFoundation.h>
|
|
4
|
+
|
|
5
|
+
@implementation RnSdk {
|
|
6
|
+
RnSdkImpl *moduleImpl;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
- (instancetype)init {
|
|
10
|
+
self = [super init];
|
|
11
|
+
if (self) {
|
|
12
|
+
moduleImpl = [RnSdkImpl new];
|
|
13
|
+
}
|
|
14
|
+
return self;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
RCT_EXPORT_MODULE()
|
|
18
|
+
|
|
19
|
+
- (void)checkCameraPermission:(RCTPromiseResolveBlock)resolve
|
|
20
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
21
|
+
AVAuthorizationStatus status =
|
|
22
|
+
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
|
23
|
+
|
|
24
|
+
resolve(@(status == AVAuthorizationStatusAuthorized));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
- (void)requestCameraPermission:(RCTPromiseResolveBlock)resolve
|
|
28
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
29
|
+
AVAuthorizationStatus status =
|
|
30
|
+
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
|
31
|
+
|
|
32
|
+
if (status == AVAuthorizationStatusAuthorized) {
|
|
33
|
+
resolve(@YES);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
|
38
|
+
completionHandler:^(BOOL granted) {
|
|
39
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
40
|
+
resolve(@(granted));
|
|
41
|
+
});
|
|
42
|
+
}];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
- (void)startJourney:(NSString *)appKey
|
|
46
|
+
environment:(NSString *)environment
|
|
47
|
+
provider:(NSString *)provider
|
|
48
|
+
onSuccess:(RCTResponseSenderBlock)onSuccess
|
|
49
|
+
onError:(RCTResponseSenderBlock)onError
|
|
50
|
+
isCustomEnabled:(NSNumber *)isCustomEnabled
|
|
51
|
+
theme:(NSDictionary *)theme {
|
|
52
|
+
BOOL customEnabled = isCustomEnabled ? [isCustomEnabled boolValue] : NO;
|
|
53
|
+
[moduleImpl startJourneyWithAppKey:appKey
|
|
54
|
+
environment:environment
|
|
55
|
+
provider:provider
|
|
56
|
+
isCustomEnabled:customEnabled
|
|
57
|
+
theme:theme
|
|
58
|
+
onSuccess:^(NSString *_Nonnull result) {
|
|
59
|
+
onSuccess(@[ result ]);
|
|
60
|
+
}
|
|
61
|
+
onError:^(NSString *_Nonnull error) {
|
|
62
|
+
onError(@[ error ]);
|
|
63
|
+
}];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
67
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
68
|
+
return std::make_shared<facebook::react::NativeRnSdkSpecJSI>(params);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RnSdkImpl.swift
|
|
3
|
+
// RnSdk
|
|
4
|
+
//
|
|
5
|
+
// Created by Gabriel Catelli Goulart on 21/07/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import CertifaceSDK
|
|
9
|
+
import UIKit
|
|
10
|
+
|
|
11
|
+
@objc public class RnSdkImpl: NSObject {
|
|
12
|
+
var onSuccessCallback: ((String) -> Void)?
|
|
13
|
+
var onErrorCallback: ((String) -> Void)?
|
|
14
|
+
|
|
15
|
+
@objc public func startJourney(
|
|
16
|
+
appKey: String,
|
|
17
|
+
environment: String,
|
|
18
|
+
provider: String,
|
|
19
|
+
isCustomEnabled: Bool,
|
|
20
|
+
theme: [String: Any]?,
|
|
21
|
+
onSuccess: @escaping (String) -> Void,
|
|
22
|
+
onError: @escaping (String) -> Void
|
|
23
|
+
) {
|
|
24
|
+
print(
|
|
25
|
+
"AppKey: \(appKey), Environment: \(environment), Provider: \(provider), CustomEnabled: \(isCustomEnabled)"
|
|
26
|
+
)
|
|
27
|
+
if let themeData = theme {
|
|
28
|
+
print("Theme: \(themeData)")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
self.onSuccessCallback = onSuccess
|
|
32
|
+
self.onErrorCallback = onError
|
|
33
|
+
|
|
34
|
+
let sdkEnvironment: CertifaceSDK.Environment
|
|
35
|
+
if environment == "PRD" {
|
|
36
|
+
sdkEnvironment = .prd
|
|
37
|
+
} else {
|
|
38
|
+
sdkEnvironment = .hml
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let livenessProvider: LivenessProvider
|
|
42
|
+
if provider == "FACETEC" {
|
|
43
|
+
livenessProvider = .facetec
|
|
44
|
+
} else if provider == "IPROOV" {
|
|
45
|
+
livenessProvider = .iproov
|
|
46
|
+
} else {
|
|
47
|
+
onError("Invalid provider: \(provider)")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var facetecCustomization = FacetecCustomization.builder().build()
|
|
52
|
+
var iproovCustomization = IProovCustomization.builder().build()
|
|
53
|
+
|
|
54
|
+
var showInstructionsScreen = true
|
|
55
|
+
|
|
56
|
+
if isCustomEnabled {
|
|
57
|
+
switch livenessProvider {
|
|
58
|
+
case .facetec:
|
|
59
|
+
facetecCustomization = ThemeFactory.createFacetecCustomization(from: theme)
|
|
60
|
+
case .iproov:
|
|
61
|
+
iproovCustomization = ThemeFactory.createIProovCustomization(from: theme)
|
|
62
|
+
@unknown default:
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if let themeData = theme,
|
|
67
|
+
let instructionsTheme = themeData["instructions"] as? [String: Any],
|
|
68
|
+
let configuration = instructionsTheme["configuration"] as? [String: Any],
|
|
69
|
+
let showInstruction = configuration["showInstructionScreen"] as? Bool {
|
|
70
|
+
showInstructionsScreen = showInstruction
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let options = LivenessManagerOptions
|
|
75
|
+
.builder(appKey: appKey, environment: sdkEnvironment)
|
|
76
|
+
.setShowInstructionsScreen(showInstructionsScreen)
|
|
77
|
+
.setFacetecCustomization(facetecCustomization)
|
|
78
|
+
.setIProovCustomization(iproovCustomization)
|
|
79
|
+
.build()
|
|
80
|
+
let manager = CertifaceSDKFactory.createLivenessManager(for: livenessProvider)
|
|
81
|
+
|
|
82
|
+
DispatchQueue.main.async { [weak self] in
|
|
83
|
+
guard let self, let viewController = getRootViewController() else {
|
|
84
|
+
onError("Cannot get rootViewController")
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
manager.start(at: viewController, options: options, callback: self)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|