@faceaisdk/react-native-face-sdk 0.1.1
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 +1 -0
- package/README.md +252 -0
- package/android/build.gradle +53 -0
- package/android/libs/FaceSDKLib-release.aar +0 -0
- package/android/proguard-rules.pro +3 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/faceaisdk/reactnative/FaceRNModule.kt +383 -0
- package/android/src/main/java/com/faceaisdk/reactnative/FaceRNPackage.kt +16 -0
- package/ios/FaceAISDK/CustomToastView.swift +34 -0
- package/ios/FaceAISDK/FaceAINaviView.swift +212 -0
- package/ios/FaceAISDK/FaceSDKCameraView.swift +40 -0
- package/ios/FaceAISDK/FaceSDKLocalizer.swift +21 -0
- package/ios/FaceAISDK/LivenessDetectView.swift +317 -0
- package/ios/FaceAISDK/ScreenBrightnessHelper.swift +100 -0
- package/ios/FaceAISDK/TTSPlayer.swift +357 -0
- package/ios/FaceAISDK/VerifyFaceView.swift +284 -0
- package/ios/FaceAISDK/addFace/AddFaceByCamera.swift +207 -0
- package/ios/FaceAISDK/addFace/AddFaceByImage.swift +174 -0
- package/ios/FaceAISDK/addFace/ImagePicker.swift +52 -0
- package/ios/FaceAISDK/addFace/VerifyTwoFaceSimiView.swift +210 -0
- package/ios/FaceColorExtensions.swift +10 -0
- package/ios/FaceRNModule.h +9 -0
- package/ios/FaceRNModule.m +197 -0
- package/ios/FaceSDKSwiftManager.swift +277 -0
- package/ios/Resources/en.lproj/Localizable.strings +51 -0
- package/ios/Resources/light_too_high.png +0 -0
- package/ios/Resources/zh-Hans.lproj/Localizable.strings +51 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.js +112 -0
- package/lib/types.d.ts +39 -0
- package/lib/types.js +2 -0
- package/package.json +88 -0
- package/react-native-face-sdk.podspec +28 -0
- package/src/index.ts +184 -0
- package/src/types.ts +90 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import PhotosUI
|
|
3
|
+
|
|
4
|
+
// Select image from album
|
|
5
|
+
struct ImagePicker: UIViewControllerRepresentable {
|
|
6
|
+
@Binding var selectedImage: UIImage?
|
|
7
|
+
@Environment(\.dismiss) private var dismiss
|
|
8
|
+
|
|
9
|
+
var onImagePicked: ((UIImage) -> Void)?
|
|
10
|
+
|
|
11
|
+
func makeUIViewController(context: Context) -> PHPickerViewController {
|
|
12
|
+
var config = PHPickerConfiguration()
|
|
13
|
+
config.filter = .images
|
|
14
|
+
config.selectionLimit = 1
|
|
15
|
+
|
|
16
|
+
let picker = PHPickerViewController(configuration: config)
|
|
17
|
+
picker.delegate = context.coordinator
|
|
18
|
+
return picker
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {}
|
|
22
|
+
|
|
23
|
+
func makeCoordinator() -> Coordinator {
|
|
24
|
+
Coordinator(self)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class Coordinator: NSObject, PHPickerViewControllerDelegate {
|
|
28
|
+
let parent: ImagePicker
|
|
29
|
+
|
|
30
|
+
init(_ parent: ImagePicker) {
|
|
31
|
+
self.parent = parent
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
|
35
|
+
parent.dismiss()
|
|
36
|
+
|
|
37
|
+
guard let provider = results.first?.itemProvider,
|
|
38
|
+
provider.canLoadObject(ofClass: UIImage.self) else {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
provider.loadObject(ofClass: UIImage.self) { image, error in
|
|
43
|
+
if let uiImage = image as? UIImage {
|
|
44
|
+
DispatchQueue.main.async {
|
|
45
|
+
self.parent.selectedImage = uiImage
|
|
46
|
+
self.parent.onImagePicked?(uiImage)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import PhotosUI
|
|
3
|
+
import FaceAISDK_Core
|
|
4
|
+
|
|
5
|
+
// 定义单侧人脸的数据模型
|
|
6
|
+
struct FaceSlot {
|
|
7
|
+
var originalImage: UIImage?
|
|
8
|
+
var croppedImage: UIImage?
|
|
9
|
+
var feature: String?
|
|
10
|
+
var isLoading: Bool = false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//SDK API viewModel.evaluateSimilarity(f1: f1, f2: f2)
|
|
14
|
+
public struct VerifyTwoFaceSimiView: View {
|
|
15
|
+
// 恢复 dismiss 以支持自定义导航栏返回
|
|
16
|
+
@Environment(\.dismiss) private var dismiss
|
|
17
|
+
|
|
18
|
+
@State private var leftSlot = FaceSlot()
|
|
19
|
+
@State private var rightSlot = FaceSlot()
|
|
20
|
+
|
|
21
|
+
@StateObject private var viewModel = VerifyTwoFaceSimiModel()
|
|
22
|
+
@State private var similarityResult: String = ""
|
|
23
|
+
@State private var activePicker: PickerType?
|
|
24
|
+
|
|
25
|
+
// CustomToastView 相关状态
|
|
26
|
+
@State private var showToast = false
|
|
27
|
+
@State private var toastMessage = ""
|
|
28
|
+
@State private var toastStyle: ToastStyle = .success
|
|
29
|
+
|
|
30
|
+
enum PickerType: Identifiable {
|
|
31
|
+
case left, right
|
|
32
|
+
var id: Int { hashValue }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 干净的初始化方法
|
|
36
|
+
public init() {}
|
|
37
|
+
|
|
38
|
+
public var body: some View {
|
|
39
|
+
ZStack {
|
|
40
|
+
VStack(spacing: 0) {
|
|
41
|
+
HStack {
|
|
42
|
+
Button(action: {
|
|
43
|
+
dismiss()
|
|
44
|
+
}) {
|
|
45
|
+
Image(systemName: "chevron.left")
|
|
46
|
+
.font(.system(size: 16, weight: .semibold))
|
|
47
|
+
.foregroundColor(.black)
|
|
48
|
+
.padding(10)
|
|
49
|
+
.background(Color.gray.opacity(0.1))
|
|
50
|
+
.clipShape(Circle())
|
|
51
|
+
}
|
|
52
|
+
Text("Verify Two Face Similarity")
|
|
53
|
+
.font(.headline)
|
|
54
|
+
Spacer()
|
|
55
|
+
}
|
|
56
|
+
.padding(.horizontal, 20)
|
|
57
|
+
.padding(.top, 10)
|
|
58
|
+
.padding(.bottom, 20)
|
|
59
|
+
|
|
60
|
+
ScrollView {
|
|
61
|
+
VStack(spacing: 30) {
|
|
62
|
+
HStack(spacing: 20) {
|
|
63
|
+
faceBox(slot: leftSlot) { activePicker = .left }
|
|
64
|
+
faceBox(slot: rightSlot) { activePicker = .right }
|
|
65
|
+
}
|
|
66
|
+
.padding(.horizontal, 20)
|
|
67
|
+
.padding(.top, 25)
|
|
68
|
+
|
|
69
|
+
if !similarityResult.isEmpty {
|
|
70
|
+
VStack(spacing: 8) {
|
|
71
|
+
Text(similarityResult)
|
|
72
|
+
.font(.system(size: 28, weight: .heavy))
|
|
73
|
+
.foregroundColor(.blue)
|
|
74
|
+
}
|
|
75
|
+
.frame(maxWidth: .infinity)
|
|
76
|
+
.padding(.vertical, 12)
|
|
77
|
+
.padding(.horizontal, 22)
|
|
78
|
+
.background(Color.blue.opacity(0.1))
|
|
79
|
+
.cornerRadius(16)
|
|
80
|
+
.padding(.horizontal, 33)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// MARK: - 4. 操作按钮
|
|
84
|
+
Button(action: runComparison) {
|
|
85
|
+
Text("Verify Two Face Similarity")
|
|
86
|
+
.font(.headline).foregroundColor(.white)
|
|
87
|
+
.frame(maxWidth: .infinity).frame(height: 55)
|
|
88
|
+
.background(canCompare ? Color.blue : Color.gray)
|
|
89
|
+
.cornerRadius(12)
|
|
90
|
+
}
|
|
91
|
+
.disabled(!canCompare)
|
|
92
|
+
.padding(.horizontal, 33)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
97
|
+
.background(Color.white.ignoresSafeArea())
|
|
98
|
+
.navigationBarBackButtonHidden(true)
|
|
99
|
+
.navigationBarHidden(true)
|
|
100
|
+
|
|
101
|
+
if showToast {
|
|
102
|
+
VStack {
|
|
103
|
+
Spacer()
|
|
104
|
+
CustomToastView(
|
|
105
|
+
message: toastMessage,
|
|
106
|
+
style: toastStyle
|
|
107
|
+
)
|
|
108
|
+
.padding(.bottom, 77)
|
|
109
|
+
}
|
|
110
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
111
|
+
.transition(.move(edge: .bottom).combined(with: .opacity))
|
|
112
|
+
.zIndex(1)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
.sheet(item: $activePicker) { type in
|
|
116
|
+
ImagePicker(selectedImage: .constant(nil)) { uiImage in
|
|
117
|
+
handleImageSelected(uiImage, for: type)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// 监听 Model 提示状态改变,弹出 Toast
|
|
121
|
+
.onChange(of: viewModel.sdkInterfaceTips.code) { code in
|
|
122
|
+
if code != 0 {
|
|
123
|
+
let msg = NSLocalizedString("Face_Tips_Code_\(code)", comment: "")
|
|
124
|
+
toastMessage = msg
|
|
125
|
+
|
|
126
|
+
// 简单约定:如果检测到人脸(Code为确认录入等)视为 success,否则视为 failure
|
|
127
|
+
toastStyle = (code == FaceTipsCode.CONFIRM_ADD_FACE) ? .success : .failure
|
|
128
|
+
|
|
129
|
+
withAnimation {
|
|
130
|
+
showToast = true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 2秒后自动隐藏 Toast
|
|
134
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
135
|
+
withAnimation {
|
|
136
|
+
showToast = false
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
.animation(.easeInOut(duration: 0.3), value: showToast)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private var canCompare: Bool {
|
|
145
|
+
leftSlot.feature != nil && rightSlot.feature != nil
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 处理图片选择后的初始化与直接回调闭包
|
|
149
|
+
private func handleImageSelected(_ image: UIImage, for type: PickerType) {
|
|
150
|
+
// 选择图片后,先重置当前 Slot 的状态
|
|
151
|
+
if type == .left {
|
|
152
|
+
leftSlot.originalImage = image
|
|
153
|
+
leftSlot.isLoading = true
|
|
154
|
+
leftSlot.feature = nil
|
|
155
|
+
} else {
|
|
156
|
+
rightSlot.originalImage = image
|
|
157
|
+
rightSlot.isLoading = true
|
|
158
|
+
rightSlot.feature = nil
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 调用 Model 闭包处理人脸
|
|
162
|
+
viewModel.processImage(image) { croppedImage, feature in
|
|
163
|
+
// 无论成功还是失败,都会走到这里,从而安全地关闭 Loading 状态
|
|
164
|
+
if type == .left {
|
|
165
|
+
leftSlot.isLoading = false
|
|
166
|
+
leftSlot.croppedImage = croppedImage
|
|
167
|
+
leftSlot.feature = feature
|
|
168
|
+
} else {
|
|
169
|
+
rightSlot.isLoading = false
|
|
170
|
+
rightSlot.croppedImage = croppedImage
|
|
171
|
+
rightSlot.feature = feature
|
|
172
|
+
}
|
|
173
|
+
similarityResult = "" //清空之前的结果
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private func runComparison() {
|
|
178
|
+
guard let f1 = leftSlot.feature, let f2 = rightSlot.feature else { return }
|
|
179
|
+
let score = viewModel.evaluateSimilarity(f1: f1, f2: f2)
|
|
180
|
+
similarityResult = String(format: "%.2f%%", score * 100)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 复用 UI 组件
|
|
184
|
+
@ViewBuilder
|
|
185
|
+
private func faceBox(slot: FaceSlot, action: @escaping () -> Void) -> some View {
|
|
186
|
+
Button(action: action) {
|
|
187
|
+
ZStack {
|
|
188
|
+
if let displayImg = slot.croppedImage ?? slot.originalImage {
|
|
189
|
+
Image(uiImage: displayImg).resizable().scaledToFill()
|
|
190
|
+
} else {
|
|
191
|
+
VStack {
|
|
192
|
+
Image(systemName: "person.crop.rectangle.badge.plus")
|
|
193
|
+
.font(.largeTitle)
|
|
194
|
+
}.foregroundColor(.gray)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if slot.isLoading {
|
|
198
|
+
ZStack {
|
|
199
|
+
Color.black.opacity(0.3)
|
|
200
|
+
ProgressView().tint(.white)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
.frame(width: 150, height: 150)
|
|
205
|
+
.background(Color.gray.opacity(0.1))
|
|
206
|
+
.cornerRadius(16)
|
|
207
|
+
.clipped()
|
|
208
|
+
}.buttonStyle(PlainButtonStyle())
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FaceRNModule.m
|
|
3
|
+
// FaceRN
|
|
4
|
+
//
|
|
5
|
+
// This file is a duplicate. See FaceRN/FaceRNModule.m for the actual implementation.
|
|
6
|
+
// 统一 iOS/Android 桥接 API,参考 FaceAISDK_uniapp_UTS
|
|
7
|
+
|
|
8
|
+
#import "FaceRNModule.h"
|
|
9
|
+
#import <UIKit/UIKit.h>
|
|
10
|
+
|
|
11
|
+
#import "FaceAISDKReactNative-Swift.h"
|
|
12
|
+
|
|
13
|
+
@implementation FaceRNModule
|
|
14
|
+
|
|
15
|
+
RCT_EXPORT_MODULE();
|
|
16
|
+
|
|
17
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
18
|
+
return YES;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (dispatch_queue_t)methodQueue {
|
|
22
|
+
return dispatch_get_main_queue();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//结果Code 对应含义message 返回给插件调用方
|
|
26
|
+
- (NSString *)getMsgByCode:(NSInteger)code {
|
|
27
|
+
switch (code) {
|
|
28
|
+
case 0: return @"User canceled/interrupted";
|
|
29
|
+
case 1: return @"Operation succeeded";
|
|
30
|
+
case 2: return @"Low face similarity (verification failed)";
|
|
31
|
+
case 3: return @"Motion liveness passed";
|
|
32
|
+
case 4: return @"Motion liveness timeout";
|
|
33
|
+
case 5: return @"No face detected repeatedly";
|
|
34
|
+
case 6: return @"No local face feature found";
|
|
35
|
+
case 7: return @"Color liveness passed";
|
|
36
|
+
case 8: return @"Color liveness failed";
|
|
37
|
+
case 9: return @"Ambient light too strong (color failed)";
|
|
38
|
+
case 10: return @"All liveness checks passed";
|
|
39
|
+
case 11: return @"Silent liveness failed";
|
|
40
|
+
case 12: return @"No enrolled face information";
|
|
41
|
+
case 13: return @"Multiple faces detected";
|
|
42
|
+
default: return @"Unknown status code";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
RCT_EXPORT_METHOD(addFaceBySDKCamera:(NSString *)faceID
|
|
47
|
+
addFacePerformanceMode:(nonnull NSNumber *)performanceMode
|
|
48
|
+
needShowConfirmDialog:(BOOL)needConfirm
|
|
49
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
50
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
51
|
+
[FaceSDKSwiftManager showAddFaceByCamera:faceID :performanceMode :needConfirm :^(NSNumber * _Nonnull resultCode, NSString * _Nonnull feature) {
|
|
52
|
+
NSString *msg = [resultCode integerValue] == 1
|
|
53
|
+
? @"Face enrollment succeeded"
|
|
54
|
+
: @"User canceled enrollment";
|
|
55
|
+
NSString *base64Str = @"";
|
|
56
|
+
if ([resultCode integerValue] == 1) {
|
|
57
|
+
base64Str = [FaceSDKSwiftManager getFaceImageBase64:faceID] ?: @"";
|
|
58
|
+
}
|
|
59
|
+
NSString *faceFeature = feature.length > 0 ? feature : ([FaceSDKSwiftManager getiOSFaceFeature:faceID] ?: @"");
|
|
60
|
+
NSDictionary *result = @{
|
|
61
|
+
@"code": resultCode,
|
|
62
|
+
@"msg": msg,
|
|
63
|
+
@"faceID": faceID ?: @"",
|
|
64
|
+
@"similarity": @(0),
|
|
65
|
+
@"liveness": @(0),
|
|
66
|
+
@"faceFeature": faceFeature,
|
|
67
|
+
@"faceBase64": base64Str
|
|
68
|
+
};
|
|
69
|
+
callback(@[result]);
|
|
70
|
+
}];
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
RCT_EXPORT_METHOD(faceVerify:(NSString *)faceID
|
|
75
|
+
threshold:(nonnull NSNumber *)threshold
|
|
76
|
+
faceLivenessType:(nonnull NSNumber *)faceLivenessType
|
|
77
|
+
motionLivenessTypes:(NSString *)motionLivenessTypes
|
|
78
|
+
motionLivenessTimeOut:(nonnull NSNumber *)motionLivenessTimeOut
|
|
79
|
+
motionLivenessSteps:(nonnull NSNumber *)motionLivenessSteps
|
|
80
|
+
allowMultiFaces:(BOOL)allowMultiFaces
|
|
81
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
82
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
83
|
+
[FaceSDKSwiftManager showFaceVerify:faceID :threshold :faceLivenessType :motionLivenessTypes :motionLivenessTimeOut :motionLivenessSteps :^(NSNumber * _Nonnull resultCode, NSNumber * _Nonnull similarity, NSNumber * _Nonnull liveness) {
|
|
84
|
+
NSString *base64Str = @"";
|
|
85
|
+
NSInteger code = [resultCode integerValue];
|
|
86
|
+
if (code == 1 || code == 10) {
|
|
87
|
+
base64Str = [FaceSDKSwiftManager getFaceImageBase64:faceID] ?: @"";
|
|
88
|
+
}
|
|
89
|
+
NSDictionary *result = @{
|
|
90
|
+
@"code": resultCode,
|
|
91
|
+
@"msg": [self getMsgByCode:code],
|
|
92
|
+
@"faceID": faceID ?: @"",
|
|
93
|
+
@"similarity": similarity,
|
|
94
|
+
@"liveness": liveness,
|
|
95
|
+
@"faceFeature": @"",
|
|
96
|
+
@"faceBase64": base64Str
|
|
97
|
+
};
|
|
98
|
+
callback(@[result]);
|
|
99
|
+
}];
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
RCT_EXPORT_METHOD(livenessVerify:(nonnull NSNumber *)faceLivenessType
|
|
104
|
+
motionLivenessTypes:(NSString *)motionLivenessTypes
|
|
105
|
+
motionLivenessTimeOut:(nonnull NSNumber *)motionLivenessTimeOut
|
|
106
|
+
motionLivenessSteps:(nonnull NSNumber *)motionLivenessSteps
|
|
107
|
+
allowMultiFaces:(BOOL)allowMultiFaces
|
|
108
|
+
showResultTips:(BOOL)showResultTips
|
|
109
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
110
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
111
|
+
[FaceSDKSwiftManager showLivenessVerify:faceLivenessType :motionLivenessTypes :motionLivenessTimeOut :motionLivenessSteps :showResultTips :^(NSNumber * _Nonnull resultCode, NSNumber * _Nonnull liveness) {
|
|
112
|
+
NSString *base64Str = @"";
|
|
113
|
+
NSInteger code = [resultCode integerValue];
|
|
114
|
+
if (code == 1 || code == 10) {
|
|
115
|
+
base64Str = [FaceSDKSwiftManager getFaceImageBase64:@"Liveness"] ?: @"";
|
|
116
|
+
}
|
|
117
|
+
NSDictionary *result = @{
|
|
118
|
+
@"code": resultCode,
|
|
119
|
+
@"msg": [self getMsgByCode:code],
|
|
120
|
+
@"faceID": @"",
|
|
121
|
+
@"similarity": @(0),
|
|
122
|
+
@"liveness": liveness,
|
|
123
|
+
@"faceFeature": @"",
|
|
124
|
+
@"faceBase64": base64Str
|
|
125
|
+
};
|
|
126
|
+
callback(@[result]);
|
|
127
|
+
}];
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
RCT_EXPORT_METHOD(getFaceFeature:(NSString *)faceID
|
|
132
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
133
|
+
NSString *faceFeature = [FaceSDKSwiftManager getiOSFaceFeature:faceID] ?: @"";
|
|
134
|
+
[FaceSDKSwiftManager isFaceFeatureExist:faceID :^(NSNumber * _Nonnull resultCode, NSString * _Nonnull msg) {
|
|
135
|
+
NSDictionary *result = @{
|
|
136
|
+
@"code": resultCode,
|
|
137
|
+
@"msg": msg,
|
|
138
|
+
@"faceID": faceID ?: @"",
|
|
139
|
+
@"similarity": @(0),
|
|
140
|
+
@"liveness": @(0),
|
|
141
|
+
@"faceFeature": faceFeature,
|
|
142
|
+
@"faceBase64": @""
|
|
143
|
+
};
|
|
144
|
+
callback(@[result]);
|
|
145
|
+
}];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
RCT_EXPORT_METHOD(insertFaceFeature:(NSString *)faceID
|
|
149
|
+
faceFeature:(NSString *)faceFeature
|
|
150
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
151
|
+
[FaceSDKSwiftManager insertFaceFeature:faceID :faceFeature :^(NSNumber * _Nonnull resultCode, NSString * _Nonnull msg) {
|
|
152
|
+
NSDictionary *result = @{
|
|
153
|
+
@"code": resultCode,
|
|
154
|
+
@"msg": msg,
|
|
155
|
+
@"faceID": faceID ?: @"",
|
|
156
|
+
@"similarity": @(0),
|
|
157
|
+
@"liveness": @(0),
|
|
158
|
+
@"faceFeature": @"",
|
|
159
|
+
@"faceBase64": @""
|
|
160
|
+
};
|
|
161
|
+
callback(@[result]);
|
|
162
|
+
}];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
RCT_EXPORT_METHOD(addFaceBySDKImage:(NSString *)faceID
|
|
166
|
+
base64FaceImage:(NSString *)base64FaceImage
|
|
167
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
168
|
+
[FaceSDKSwiftManager addFaceByBase64:faceID :base64FaceImage :^(NSNumber * _Nonnull resultCode, NSString * _Nonnull feature, NSString * _Nonnull msg) {
|
|
169
|
+
NSDictionary *result = @{
|
|
170
|
+
@"code": resultCode,
|
|
171
|
+
@"msg": msg,
|
|
172
|
+
@"faceID": faceID ?: @"",
|
|
173
|
+
@"similarity": @(0),
|
|
174
|
+
@"liveness": @(0),
|
|
175
|
+
@"faceFeature": feature ?: @"",
|
|
176
|
+
@"faceBase64": @""
|
|
177
|
+
};
|
|
178
|
+
callback(@[result]);
|
|
179
|
+
}];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
RCT_EXPORT_METHOD(deleteFaceFeature:(NSString *)faceID
|
|
183
|
+
callback:(RCTResponseSenderBlock)callback) {
|
|
184
|
+
[FaceSDKSwiftManager deleteFaceFeature:faceID];
|
|
185
|
+
NSDictionary *result = @{
|
|
186
|
+
@"code": @(1),
|
|
187
|
+
@"msg": @"Delete Success",
|
|
188
|
+
@"faceID": faceID ?: @"",
|
|
189
|
+
@"similarity": @(0),
|
|
190
|
+
@"liveness": @(0),
|
|
191
|
+
@"faceFeature": @"",
|
|
192
|
+
@"faceBase64": @""
|
|
193
|
+
};
|
|
194
|
+
callback(@[result]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@end
|