@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.
Files changed (35) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +252 -0
  3. package/android/build.gradle +53 -0
  4. package/android/libs/FaceSDKLib-release.aar +0 -0
  5. package/android/proguard-rules.pro +3 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/java/com/faceaisdk/reactnative/FaceRNModule.kt +383 -0
  8. package/android/src/main/java/com/faceaisdk/reactnative/FaceRNPackage.kt +16 -0
  9. package/ios/FaceAISDK/CustomToastView.swift +34 -0
  10. package/ios/FaceAISDK/FaceAINaviView.swift +212 -0
  11. package/ios/FaceAISDK/FaceSDKCameraView.swift +40 -0
  12. package/ios/FaceAISDK/FaceSDKLocalizer.swift +21 -0
  13. package/ios/FaceAISDK/LivenessDetectView.swift +317 -0
  14. package/ios/FaceAISDK/ScreenBrightnessHelper.swift +100 -0
  15. package/ios/FaceAISDK/TTSPlayer.swift +357 -0
  16. package/ios/FaceAISDK/VerifyFaceView.swift +284 -0
  17. package/ios/FaceAISDK/addFace/AddFaceByCamera.swift +207 -0
  18. package/ios/FaceAISDK/addFace/AddFaceByImage.swift +174 -0
  19. package/ios/FaceAISDK/addFace/ImagePicker.swift +52 -0
  20. package/ios/FaceAISDK/addFace/VerifyTwoFaceSimiView.swift +210 -0
  21. package/ios/FaceColorExtensions.swift +10 -0
  22. package/ios/FaceRNModule.h +9 -0
  23. package/ios/FaceRNModule.m +197 -0
  24. package/ios/FaceSDKSwiftManager.swift +277 -0
  25. package/ios/Resources/en.lproj/Localizable.strings +51 -0
  26. package/ios/Resources/light_too_high.png +0 -0
  27. package/ios/Resources/zh-Hans.lproj/Localizable.strings +51 -0
  28. package/lib/index.d.ts +22 -0
  29. package/lib/index.js +112 -0
  30. package/lib/types.d.ts +39 -0
  31. package/lib/types.js +2 -0
  32. package/package.json +88 -0
  33. package/react-native-face-sdk.podspec +28 -0
  34. package/src/index.ts +184 -0
  35. package/src/types.ts +90 -0
package/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Email:FaceAISDK.Service@gmail.com
package/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # @faceaisdk/react-native-face-sdk
2
+
3
+ FaceAISDK 人脸识别、活体检测 React Native 原生插件仓库,支持 iOS 和 Android 双端,所有功能无需后台 API 服务即可离线运行。
4
+
5
+ 当前仓库已调整为更接近标准 RN 库仓的结构:
6
+
7
+ - **根目录**:可发布插件 `@faceaisdk/react-native-face-sdk`
8
+ - **`example/`**:示例 App / 真机联调工程
9
+
10
+ > **说明**:人脸识别、活体检测等功能需要摄像头,必须使用真机,不能在模拟器中验证。
11
+
12
+ ## 安装
13
+
14
+ ```sh
15
+ npm install @faceaisdk/react-native-face-sdk
16
+ ```
17
+
18
+ ### iOS
19
+
20
+ 在您的 iOS 工程目录下运行:
21
+
22
+ ```sh
23
+ cd ios
24
+ pod install
25
+ ```
26
+
27
+ > **注意**:由于使用了人脸识别 SDK,您需要在 `Info.plist` 中添加相机权限描述:
28
+ > ```xml
29
+ > <key>NSCameraUsageDescription</key>
30
+ > <string>我们需要访问您的相机进行人脸识别</string>
31
+ > ```
32
+
33
+ ### Android
34
+
35
+ 1. 确保您的项目 `minSdkVersion` 至少为 24。
36
+ 2. Android 端会自动完成 Autolinking。
37
+
38
+ > **注意**:由于使用了人脸识别 SDK,您需要在 `AndroidManifest.xml` 中确保有以下权限:
39
+ > ```xml
40
+ > <uses-permission android:name="android.permission.CAMERA" />
41
+ > ```
42
+
43
+ ---
44
+
45
+ ## 功能列表
46
+
47
+ | 功能 | iOS | Android |
48
+ |------|-----|---------|
49
+ | SDK相机录入人脸信息 | ✅ | ✅ |
50
+ | 1:1人脸识别+活体检测 | ✅ | ✅ |
51
+ | 活体检测(动作/炫彩/静默) | ✅ | ✅ |
52
+ | 查询人脸特征信息 | ✅ | ✅ |
53
+ | 同步人脸特征信息 | ✅ | ✅ |
54
+ | 图片录入人脸信息 | ✅ | ✅ |
55
+ | 删除人脸特征信息 | ✅ | ✅ |
56
+
57
+ ## 仓库结构
58
+
59
+ ```text
60
+ FaceAISDK_RN/
61
+ ├── src/ # 插件 TypeScript 对外 API
62
+ ├── android/ # 插件 Android Library 工程
63
+ ├── ios/ # 插件 iOS 原生源码与资源
64
+ ├── @faceaisdk/react-native-face-sdk.podspec # iOS Podspec
65
+ ├── example/ # 示例 App(真机调试、联调、回归)
66
+ │ ├── App.tsx
67
+ │ ├── android/
68
+ │ ├── ios/
69
+ │ └── auto_run.sh
70
+ ├── __tests__/ # 插件单元测试
71
+ ├── README.md
72
+ └── 插件封装与npm发布指南.md
73
+ ```
74
+
75
+ ## JS API
76
+
77
+ 根目录导出 Promise 风格接口:
78
+
79
+ ```ts
80
+ import {
81
+ addFaceBySDKCamera,
82
+ faceVerify,
83
+ livenessVerify,
84
+ getFaceFeature,
85
+ insertFaceFeature,
86
+ addFaceByImage,
87
+ deleteFaceFeature,
88
+ } from '@faceaisdk/react-native-face-sdk';
89
+ ```
90
+
91
+ ### 核心方法说明
92
+
93
+ #### 1. SDK 相机录入人脸
94
+ `addFaceBySDKCamera(faceID, options)`
95
+ - `faceID`: 用户唯一标识
96
+ - `options`: `{ mode?: number, showConfirm?: boolean }`
97
+
98
+ #### 2. 人脸比对 + 活体检测
99
+ `faceVerify(faceID, options)`
100
+ - `faceID`: 待验证的用户标识
101
+ - `options`: 包含阈值、活体类型、动作序列、超时时间等配置
102
+
103
+ #### 3. 纯活体检测
104
+ `livenessVerify(options)`
105
+ - 仅检测镜头前是否为活人,不进行 1:1 比对
106
+
107
+ ## 统一返回结构
108
+
109
+ ```ts
110
+ export interface FaceResult {
111
+ code: number;
112
+ msg: string;
113
+ faceID: string;
114
+ similarity: number;
115
+ liveness: number;
116
+ faceFeature: string;
117
+ faceBase64: string;
118
+ }
119
+ ```
120
+
121
+ ## 状态码说明
122
+
123
+ | Code | 含义 |
124
+ |------|------|
125
+ | 0 | 初始化状态/用户取消 |
126
+ | 1 | 人脸识别对比成功(大于设置的 threshold) |
127
+ | 2 | 人脸识别对比失败(小于设置的 threshold) |
128
+ | 3 | 动作活体检测成功 |
129
+ | 4 | 动作活体超时 |
130
+ | 5 | 多次没有检测到人脸 |
131
+ | 6 | 没有对应的人脸特征值 |
132
+ | 7 | 炫彩活体成功 |
133
+ | 8 | 炫彩活体失败 |
134
+ | 9 | 炫彩活体失败(光线亮度过高) |
135
+ | 10 | 所有活体检测完成 |
136
+ | 11 | 静默活体检测失败 |
137
+ | 12 | 没有录入人脸信息 |
138
+ | 13 | 多人脸出现在镜头 |
139
+
140
+ ## 根目录:作为库开发/发布
141
+
142
+ ### 构建与测试
143
+
144
+ ```sh
145
+ npm run typecheck
146
+ npm run build
147
+ npm test
148
+ npm run pack
149
+ ```
150
+
151
+ ### 发布前检查
152
+
153
+ ```sh
154
+ npm pack .
155
+ ```
156
+
157
+ 生成产物中应至少包含:
158
+
159
+ - `src/` / `lib/`
160
+ - `android/`
161
+ - `ios/`
162
+ - `@faceaisdk/react-native-face-sdk.podspec`
163
+
164
+ ## `example/`:作为示例 App 运行
165
+
166
+ > 请确保已完成 [React Native 环境配置](https://reactnative.dev/docs/set-up-your-environment)。
167
+
168
+ ### 方式一:使用仓库根命令
169
+
170
+ ```sh
171
+ npm run start
172
+ npm run android
173
+ npm run ios
174
+ ```
175
+
176
+ 这些命令会自动代理到 `example/` 工程。
177
+
178
+ ### 方式二:直接进入 `example/`
179
+
180
+ ```sh
181
+ cd example
182
+ node ../node_modules/react-native/cli.js start --config metro.config.js
183
+ ```
184
+
185
+ #### Android
186
+
187
+ ```sh
188
+ cd example
189
+ node ../node_modules/react-native/cli.js run-android --no-packager
190
+ ```
191
+
192
+ #### iOS
193
+
194
+ ```sh
195
+ cd example
196
+ ./pod-install.sh
197
+ node ../node_modules/react-native/cli.js run-ios --device "您的手机名称"
198
+ ```
199
+
200
+ 如果您希望在仓库根目录执行,也可以直接运行:
201
+
202
+ ```sh
203
+ npm run pods:install
204
+ ```
205
+
206
+ `pod-install.sh` 会自动:
207
+
208
+ - 使用 `example/vendor/bundle` 安装 Ruby gems
209
+ - 注入 Ruby 4 所需的 `kconv` 兼容层
210
+ - 对 `RCTSwiftUI` / `TensorFlowLiteSwift` 注入 `-no-verify-emitted-module-interface` 兼容参数(用于 Xcode 15.x)
211
+ - 执行 `bundle exec pod install`
212
+
213
+ ### 真机自动运行脚本
214
+
215
+ 根目录保留了快捷入口,仍可直接执行:
216
+
217
+ ```sh
218
+ ./auto_run.sh
219
+ ```
220
+
221
+ 实际会转发到:
222
+
223
+ ```sh
224
+ ./example/auto_run.sh
225
+ ```
226
+
227
+ ## 示例工程如何消费本地库
228
+
229
+ `example/App.tsx` 使用包名方式调用本地根库:
230
+
231
+ ```ts
232
+ import {faceVerify} from '@faceaisdk/react-native-face-sdk';
233
+ ```
234
+
235
+ 并通过 `example/metro.config.js` 将该包名解析到仓库根目录源码,便于在本地开发时即时调试。
236
+
237
+ ## 常见问题 (Troubleshooting)
238
+
239
+ ### 1. 权限问题
240
+ 本插件需要相机权限。
241
+ - **Android**: 插件会自动处理运行时权限请求,但您仍需确保 `AndroidManifest.xml` 中声明了权限。
242
+ - **iOS**: 请务必在 `Info.plist` 中配置 `NSCameraUsageDescription`,否则 App 会在调用相机时崩溃。
243
+
244
+ ### 2. 只有真机可用
245
+ 人脸识别和活体检测依赖底层硬件和原生 SDK,**模拟器无法运行**,请使用真机测试。
246
+
247
+ ### 3. 编译错误 (Xcode 15+)
248
+ 如果遇到 Swift 相关的编译错误,请参考 `example/pod-install.sh` 中的处理方式,确保开启了 `-no-verify-emitted-module-interface`。
249
+
250
+ ## 许可证 (License)
251
+
252
+ MIT
@@ -0,0 +1,53 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'org.jetbrains.kotlin.android'
3
+
4
+ android {
5
+ namespace 'com.faceaisdk.reactnative'
6
+ compileSdkVersion rootProject.ext.has('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
7
+
8
+ defaultConfig {
9
+ minSdkVersion rootProject.ext.has('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
10
+ targetSdkVersion rootProject.ext.has('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
11
+ consumerProguardFiles 'proguard-rules.pro'
12
+ }
13
+
14
+ compileOptions {
15
+ sourceCompatibility JavaVersion.VERSION_17
16
+ targetCompatibility JavaVersion.VERSION_17
17
+ }
18
+
19
+ //SDK依赖Java11 就够了
20
+ kotlinOptions {
21
+ jvmTarget = '17'
22
+ }
23
+
24
+ sourceSets {
25
+ main {
26
+ manifest.srcFile 'src/main/AndroidManifest.xml'
27
+ java.srcDirs = ['src/main/java']
28
+ res.srcDirs = ['src/main/res']
29
+ jniLibs.srcDirs = ['libs']
30
+ }
31
+ }
32
+ }
33
+
34
+ repositories {
35
+ google()
36
+ mavenCentral()
37
+ maven { url 'https://jitpack.io' }
38
+ }
39
+
40
+ dependencies {
41
+ implementation 'com.facebook.react:react-android'
42
+ implementation fileTree(dir: 'libs', include: ['*.aar'])
43
+
44
+ implementation 'io.github.faceaisdk:Android:2026.06.21'
45
+ implementation 'com.tencent:mmkv:1.3.14'
46
+ implementation 'com.airbnb.android:lottie:6.5.2'
47
+ implementation 'com.github.bumptech.glide:glide:4.16.0'
48
+ implementation 'androidx.appcompat:appcompat:1.6.0'
49
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
50
+ implementation 'androidx.recyclerview:recyclerview:1.3.2'
51
+ implementation 'pub.devrel:easypermissions:3.0.0'
52
+ }
53
+
@@ -0,0 +1,3 @@
1
+ # Keep FaceAISDK React Native bridge classes.
2
+ -keep class com.faceaisdk.reactnative.** { *; }
3
+
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.faceaisdk.reactnative" />
3
+
@@ -0,0 +1,383 @@
1
+ package com.faceaisdk.reactnative
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.pm.PackageManager
7
+ import android.Manifest
8
+ import androidx.core.app.ActivityCompat
9
+ import androidx.core.content.ContextCompat
10
+ import com.facebook.react.bridge.*
11
+ import com.facebook.react.modules.core.DeviceEventManagerModule
12
+ import com.facebook.react.modules.core.PermissionAwareActivity
13
+ import com.facebook.react.modules.core.PermissionListener
14
+ import com.faceAI.demo.FaceSDKConfig
15
+ import com.faceAI.demo.SysCamera.addFace.AddFaceFeatureActivity
16
+ import com.faceAI.demo.SysCamera.verify.FaceVerificationActivity
17
+ import com.faceAI.demo.SysCamera.verify.LivenessDetectActivity
18
+ import com.faceAI.demo.base.utils.BitmapUtils
19
+ import com.ai.face.faceSearch.search.Image2FaceFeature
20
+ import android.graphics.Bitmap
21
+ import android.text.TextUtils
22
+ import com.tencent.mmkv.MMKV
23
+
24
+ class FaceRNModule(reactContext: ReactApplicationContext) :
25
+ ReactContextBaseJavaModule(reactContext), ActivityEventListener {
26
+
27
+ companion object {
28
+ const val NAME = "FaceRNModule"
29
+ private const val REQ_CODE_ADD_FACE = 10086
30
+ private const val REQ_CODE_VERIFY = 10087
31
+ private const val REQ_CODE_LIVENESS = 10088
32
+ private const val PERMISSION_REQUEST_CODE = 10010
33
+ }
34
+
35
+ private var mCallback: Callback? = null
36
+ private var mCurrentFaceID: String = ""
37
+ private var mPendingAction: (() -> Unit)? = null
38
+
39
+ init {
40
+ reactContext.addActivityEventListener(this)
41
+ }
42
+
43
+ override fun getName(): String = NAME
44
+
45
+ /**
46
+ * 检查并请求相机权限
47
+ */
48
+ private fun checkCameraPermission(action: () -> Unit) {
49
+ val activity = reactApplicationContext.currentActivity ?: return
50
+ if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
51
+ == PackageManager.PERMISSION_GRANTED
52
+ ) {
53
+ action()
54
+ } else {
55
+ mPendingAction = action
56
+ val permissionAwareActivity = activity as? PermissionAwareActivity
57
+ permissionAwareActivity?.requestPermissions(
58
+ arrayOf(Manifest.permission.CAMERA),
59
+ PERMISSION_REQUEST_CODE,
60
+ object : PermissionListener {
61
+ override fun onRequestPermissionsResult(
62
+ requestCode: Int,
63
+ permissions: Array<String>,
64
+ grantResults: IntArray
65
+ ): Boolean {
66
+ if (requestCode == PERMISSION_REQUEST_CODE) {
67
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
68
+ mPendingAction?.invoke()
69
+ } else {
70
+ mCallback?.invoke(Arguments.createMap().apply {
71
+ putInt("code", -1)
72
+ putString("msg", "相机权限被拒绝,请在设置中开启")
73
+ putString("faceID", mCurrentFaceID)
74
+ })
75
+ mCallback = null
76
+ }
77
+ mPendingAction = null
78
+ return true
79
+ }
80
+ return false
81
+ }
82
+ }
83
+ )
84
+ }
85
+ }
86
+
87
+ /**
88
+ * 1. SDK相机录入人脸信息
89
+ */
90
+ @ReactMethod
91
+ fun addFaceBySDKCamera(
92
+ faceID: String,
93
+ addFacePerformanceMode: Int,
94
+ needShowConfirmDialog: Boolean,
95
+ callback: Callback
96
+ ) {
97
+ val activity = reactApplicationContext.currentActivity ?: return
98
+ mCallback = callback
99
+ mCurrentFaceID = faceID
100
+
101
+ checkCameraPermission {
102
+ FaceSDKConfig.init(activity)
103
+ val intent = Intent()
104
+ intent.setClassName(
105
+ activity,
106
+ "com.faceAI.demo.SysCamera.addFace.AddFaceFeatureActivity"
107
+ )
108
+ intent.putExtra("ADD_FACE_IMAGE_TYPE_KEY", "FACE_VERIFY")
109
+ intent.putExtra("USER_FACE_ID_KEY", faceID)
110
+ intent.putExtra("NEED_CONFIRM_ADD_FACE", needShowConfirmDialog)
111
+ intent.putExtra("ADD_FACE_PERFORMANCE_MODE", addFacePerformanceMode)
112
+ activity.startActivityForResult(intent, REQ_CODE_ADD_FACE)
113
+ }
114
+ }
115
+
116
+ /**
117
+ * 2. 人脸识别+活体检测
118
+ */
119
+ @ReactMethod
120
+ fun faceVerify(
121
+ faceID: String,
122
+ threshold: Double,
123
+ faceLivenessType: Int,
124
+ motionLivenessTypes: String,
125
+ motionLivenessTimeOut: Int,
126
+ motionLivenessSteps: Int,
127
+ allowMultiFaces: Boolean,
128
+ callback: Callback
129
+ ) {
130
+ val activity = reactApplicationContext.currentActivity ?: return
131
+ mCallback = callback
132
+ mCurrentFaceID = faceID
133
+
134
+ checkCameraPermission {
135
+ FaceSDKConfig.init(activity)
136
+ val intent = Intent()
137
+ intent.setClassName(
138
+ activity,
139
+ "com.faceAI.demo.SysCamera.verify.FaceVerificationActivity"
140
+ )
141
+ intent.putExtra(FaceVerificationActivity.USER_FACE_ID_KEY, faceID)
142
+ intent.putExtra(FaceVerificationActivity.THRESHOLD_KEY, threshold.toFloat())
143
+ intent.putExtra(FaceVerificationActivity.FACE_LIVENESS_TYPE, faceLivenessType)
144
+ intent.putExtra(FaceVerificationActivity.MOTION_LIVENESS_TYPES, motionLivenessTypes)
145
+ intent.putExtra(FaceVerificationActivity.MOTION_TIMEOUT, motionLivenessTimeOut)
146
+ intent.putExtra(FaceVerificationActivity.MOTION_STEP_SIZE, motionLivenessSteps)
147
+ intent.putExtra(FaceVerificationActivity.ALLOW_MULTI_FACES, allowMultiFaces)
148
+ activity.startActivityForResult(intent, REQ_CODE_VERIFY)
149
+ }
150
+ }
151
+
152
+ /**
153
+ * 3. 活体检测
154
+ */
155
+ @ReactMethod
156
+ fun livenessVerify(
157
+ faceLivenessType: Int,
158
+ motionLivenessTypes: String,
159
+ motionLivenessTimeOut: Int,
160
+ motionLivenessSteps: Int,
161
+ allowMultiFaces: Boolean,
162
+ showResultTips: Boolean,
163
+ callback: Callback
164
+ ) {
165
+ val activity = reactApplicationContext.currentActivity ?: return
166
+ mCallback = callback
167
+ mCurrentFaceID = ""
168
+
169
+ checkCameraPermission {
170
+ FaceSDKConfig.init(activity)
171
+ val intent = Intent()
172
+ intent.setClassName(
173
+ activity,
174
+ "com.faceAI.demo.SysCamera.verify.LivenessDetectActivity"
175
+ )
176
+ intent.putExtra(LivenessDetectActivity.FACE_LIVENESS_TYPE, faceLivenessType)
177
+ intent.putExtra(LivenessDetectActivity.MOTION_LIVENESS_TYPES, motionLivenessTypes)
178
+ intent.putExtra(LivenessDetectActivity.MOTION_TIMEOUT, motionLivenessTimeOut)
179
+ intent.putExtra(LivenessDetectActivity.MOTION_STEP_SIZE, motionLivenessSteps)
180
+ intent.putExtra(LivenessDetectActivity.ALLOW_MULTI_FACES, allowMultiFaces)
181
+ intent.putExtra(LivenessDetectActivity.SHOW_RESULT_TIPS, showResultTips) //是否提示活体检测结果还是调用方待后续动作处理完毕后自行处理
182
+ activity.startActivityForResult(intent, REQ_CODE_LIVENESS)
183
+ }
184
+ }
185
+
186
+ /**
187
+ * 4. 查询人脸特征信息
188
+ */
189
+ @ReactMethod
190
+ fun getFaceFeature(faceID: String, callback: Callback) {
191
+ val context = reactApplicationContext.applicationContext
192
+ FaceSDKConfig.init(context)
193
+
194
+ val faceFeature = MMKV.defaultMMKV().decodeString(faceID)
195
+ val result = Arguments.createMap()
196
+
197
+ if (faceFeature.isNullOrEmpty()) {
198
+ result.putInt("code", 0)
199
+ result.putString("msg", "Face Feature not exist")
200
+ result.putString("faceFeature", "")
201
+ } else if (faceFeature.length != 1024) {
202
+ result.putInt("code", 0)
203
+ result.putString("msg", "Face Feature length should be 1024")
204
+ result.putString("faceFeature", "")
205
+ } else {
206
+ result.putInt("code", 1)
207
+ result.putString("msg", "Face Feature exist")
208
+ result.putString("faceFeature", faceFeature)
209
+ }
210
+
211
+ result.putString("faceID", faceID)
212
+ result.putDouble("similarity", 0.0)
213
+ result.putDouble("liveness", 0.0)
214
+ result.putString("faceBase64", "")
215
+ callback.invoke(result)
216
+ }
217
+
218
+ /**
219
+ * 5. 同步人脸特征信息
220
+ */
221
+ @ReactMethod
222
+ fun insertFaceFeature(faceID: String, faceFeature: String, callback: Callback) {
223
+ val context = reactApplicationContext.applicationContext
224
+ FaceSDKConfig.init(context)
225
+
226
+ val result = Arguments.createMap()
227
+
228
+ if (TextUtils.isEmpty(faceFeature)) {
229
+ result.putInt("code", 0)
230
+ result.putString("msg", "Face Feature not exist")
231
+ } else if (faceFeature.length != 1024) {
232
+ result.putInt("code", 0)
233
+ result.putString("msg", "Face Feature length should be 1024")
234
+ } else {
235
+ MMKV.defaultMMKV().encode(faceID, faceFeature)
236
+ result.putInt("code", 1)
237
+ result.putString("msg", "insert Face success")
238
+ }
239
+
240
+ result.putString("faceID", faceID)
241
+ result.putDouble("similarity", 0.0)
242
+ result.putDouble("liveness", 0.0)
243
+ result.putString("faceFeature", "")
244
+ result.putString("faceBase64", "")
245
+ callback.invoke(result)
246
+ }
247
+
248
+ /**
249
+ * 6. 通过图片录入人脸信息
250
+ */
251
+ @ReactMethod
252
+ fun addFaceBySDKImage(faceID: String, base64FaceImage: String, callback: Callback) {
253
+ val activity = reactApplicationContext.currentActivity ?: return
254
+ FaceSDKConfig.init(activity)
255
+
256
+ Image2FaceFeature.getInstance(activity)
257
+ .getFaceFeatureByBase64(base64FaceImage, faceID, object : Image2FaceFeature.Callback {
258
+ override fun onFailed(msg: String) {
259
+ val result = Arguments.createMap()
260
+ result.putInt("code", 0)
261
+ result.putString("msg", msg)
262
+ result.putString("faceID", faceID)
263
+ result.putDouble("similarity", 0.0)
264
+ result.putDouble("liveness", 0.0)
265
+ result.putString("faceFeature", "")
266
+ result.putString("faceBase64", "")
267
+ callback.invoke(result)
268
+ }
269
+
270
+ override fun onSuccess(bitmap: Bitmap, returnFaceID: String, faceFeature: String) {
271
+ com.ai.face.core.engine.FaceAISDKEngine.getInstance(activity)
272
+ .saveCroppedFaceImage(bitmap, FaceSDKConfig.CACHE_BASE_FACE_DIR, faceID)
273
+ MMKV.defaultMMKV().encode(faceID, faceFeature)
274
+
275
+ val result = Arguments.createMap()
276
+ result.putInt("code", 1)
277
+ result.putString("msg", "getFaceFeature Success")
278
+ result.putString("faceID", faceID)
279
+ result.putDouble("similarity", 0.0)
280
+ result.putDouble("liveness", 0.0)
281
+ result.putString("faceFeature", faceFeature)
282
+ result.putString("faceBase64", "")
283
+ callback.invoke(result)
284
+ }
285
+ })
286
+ }
287
+
288
+ /**
289
+ * 7. 删除人脸特征信息
290
+ */
291
+ @ReactMethod
292
+ fun deleteFaceFeature(faceID: String, callback: Callback) {
293
+ val context = reactApplicationContext.applicationContext
294
+ FaceSDKConfig.init(context)
295
+
296
+ MMKV.defaultMMKV().removeValueForKey(faceID)
297
+ Image2FaceFeature.getInstance(context)
298
+ .deleteFaceImage(FaceSDKConfig.CACHE_BASE_FACE_DIR + faceID)
299
+
300
+ val result = Arguments.createMap()
301
+ result.putInt("code", 1)
302
+ result.putString("msg", "Delete Success")
303
+ result.putString("faceID", faceID)
304
+ result.putDouble("similarity", 0.0)
305
+ result.putDouble("liveness", 0.0)
306
+ result.putString("faceFeature", "")
307
+ result.putString("faceBase64", "")
308
+ callback.invoke(result)
309
+ }
310
+
311
+ override fun onActivityResult(
312
+ activity: Activity,
313
+ requestCode: Int,
314
+ resultCode: Int,
315
+ data: Intent?
316
+ ) {
317
+ if (mCallback == null) return
318
+ if (requestCode != REQ_CODE_ADD_FACE && requestCode != REQ_CODE_VERIFY && requestCode != REQ_CODE_LIVENESS) {
319
+ return
320
+ }
321
+
322
+ val result = Arguments.createMap()
323
+ result.putString("faceID", mCurrentFaceID)
324
+ result.putDouble("similarity", 0.0)
325
+ result.putDouble("liveness", 0.0)
326
+ result.putString("faceFeature", "")
327
+ result.putString("faceBase64", "")
328
+
329
+ if (data != null) {
330
+ result.putInt("code", data.getIntExtra("code", 0))
331
+ result.putString("msg", data.getStringExtra("msg") ?: "操作完成")
332
+
333
+ when (requestCode) {
334
+ REQ_CODE_ADD_FACE -> {
335
+ result.putString("faceFeature", data.getStringExtra("faceFeature") ?: "")
336
+ if (data.getIntExtra("code", 0) != 0) {
337
+ val base64 = BitmapUtils.bitmapToBase64(
338
+ FaceSDKConfig.CACHE_BASE_FACE_DIR + mCurrentFaceID
339
+ )
340
+ result.putString("faceBase64", base64 ?: "")
341
+ }
342
+ }
343
+ REQ_CODE_VERIFY -> {
344
+ result.putDouble(
345
+ "similarity",
346
+ data.getFloatExtra("similarity", 0f).toDouble()
347
+ )
348
+ result.putDouble(
349
+ "liveness",
350
+ data.getFloatExtra("livenessValue", 0f).toDouble()
351
+ )
352
+ if (data.getIntExtra("code", 0) == 1) {
353
+ val base64 = BitmapUtils.bitmapToBase64(
354
+ FaceSDKConfig.CACHE_FACE_LOG_DIR + "verifyBitmap"
355
+ )
356
+ result.putString("faceBase64", base64 ?: "")
357
+ }
358
+ }
359
+ REQ_CODE_LIVENESS -> {
360
+ result.putDouble(
361
+ "liveness",
362
+ data.getFloatExtra("livenessValue", 0f).toDouble()
363
+ )
364
+ if (data.getIntExtra("code", 0) == 10) {
365
+ val base64 = BitmapUtils.bitmapToBase64(
366
+ FaceSDKConfig.CACHE_FACE_LOG_DIR + "liveBitmap"
367
+ )
368
+ result.putString("faceBase64", base64 ?: "")
369
+ }
370
+ }
371
+ }
372
+ } else {
373
+ result.putInt("code", 0)
374
+ result.putString("msg", "用户取消/中断操作")
375
+ }
376
+
377
+ mCallback?.invoke(result)
378
+ mCallback = null
379
+ mCurrentFaceID = ""
380
+ }
381
+
382
+ override fun onNewIntent(intent: Intent) {}
383
+ }