├── .github └── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── config.yml │ └── feature-request.md ├── README.md ├── RNFaceApi.podspec ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── reactlibrary │ ├── JSONConstructor.java │ ├── RNFaceApiModule.java │ └── RNFaceApiPackage.java ├── example ├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.js ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── regula │ │ │ │ └── face │ │ │ │ └── api │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── regula │ │ │ │ └── face │ │ │ │ └── api │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── images │ └── portrait.png ├── index.js ├── ios │ ├── FaceApi.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── FaceApi-tvOS.xcscheme │ │ │ └── FaceApi.xcscheme │ ├── FaceApi.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── FaceApi │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── Podfile ├── metro.config.js └── package.json ├── index.d.ts ├── index.js ├── ios ├── RFSWJSONConstructor.h ├── RFSWJSONConstructor.m ├── RNFaceApi.h ├── RNFaceApi.m ├── RNFaceApi.xcodeproj │ └── project.pbxproj └── RNFaceApi.xcworkspace │ └── contents.xcworkspacedata └── package.json /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | title: "[BR] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Before Submitting, be sure to** 11 | - [ ] Update to the latest stable version. 12 | - [ ] Read and follow the guides described in the [documentation](https://docs.regulaforensics.com?utm_source=github). 13 | - [ ] Try to reproduce in our demo project. 14 | - [ ] Search for your issue in the existing GitHub issues. 15 | 16 | **Bug Description** 17 | 18 | 19 | **Steps To Reproduce** 20 | 26 | 27 | **Expected behavior** 28 | 29 | 30 | **Screenshots** 31 | 32 | 33 | **Environment:** 34 | - Device: 35 | - OS: 36 | - OS version: 37 | 38 | **Additional context** 39 | 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Regula Help Center 4 | url: https://support.regulaforensics.com/hc/requests/new?utm_source=github 5 | about: Please submit any requests here 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this product 4 | title: "[FR] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | 13 | **Describe the solution you'd like** 14 | 15 | 16 | **Describe alternatives you've considered** 17 | 18 | 19 | **Additional context** 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Regula Face API (React Native version) 2 | Face API is a framework that is used for face matching, recognition and liveness detection. 3 | 4 | # Contents 5 | * [How to build the demo application](#how-to-build-the-demo-application) 6 | * [Documentation](#documentation) 7 | * [Additional information](#additional-information) 8 | 9 | ## How to build the demo application 10 | 1. Download or the clone current repository . 11 | 2. Run the following commands within the root directory: 12 | ```bash 13 | $ cd example 14 | $ npm install 15 | $ cd ios 16 | $ pod install 17 | ``` 18 | 19 | **Note**: make sure that Metro Bundler is running when you run your app. Otherwise, run `npx react-native start` command. If it fails to start, run `git init` from Project root, then `npx react-native start`. 20 | 21 | 3. Android: 22 | * Run `npx react-native run-android` inside `example` folder - this is just one way to run the app. You can also run it directly from within Android Studio. 23 | 24 | **Note**: if the running failed with the following error `Error: spawn ./gradlew EACCES`, try to run the following command `chmod +x gradlew` within the `example/android` directory. 25 | 26 | 4. iOS: 27 | * Run `npx react-native run-ios` inside `example` folder - this is just one way to run the app. You can also run it directly from within Xcode. 28 | 29 | ## Documentation 30 | You can find documentation on API [here](https://docs.regulaforensics.com/develop/face-sdk/mobile). 31 | 32 | ## Additional information 33 | If you have any technical questions, feel free to [contact](mailto:support@regulaforensics.com) us or create issues [here]. 34 | -------------------------------------------------------------------------------- /RNFaceApi.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | source = File.join(__dir__, 'ios') 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'RNFaceApi' 8 | s.version = package['version'] 9 | s.summary = package['description'] 10 | s.license = package['license'] 11 | 12 | s.authors = { 'RegulaForensics' => 'support@regulaforensics.com' } 13 | s.homepage = 'https://regulaforensics.com' 14 | 15 | s.source = { http: "file:#{source}" } 16 | s.ios.deployment_target = '11.0' 17 | s.source_files = 'ios/**/*.{h,m}' 18 | s.dependency 'FaceSDK', '5.1.1482' 19 | s.dependency 'React' 20 | end 21 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 33 5 | 6 | defaultConfig { 7 | minSdkVersion 21 8 | targetSdkVersion 33 9 | versionCode 1 10 | versionName "1.0" 11 | } 12 | } 13 | 14 | rootProject.allprojects { 15 | repositories { 16 | maven { 17 | url "https://maven.regulaforensics.com/RegulaDocumentReader" 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | //noinspection GradleDynamicVersion 24 | implementation 'com.facebook.react:react-native:+' 25 | //noinspection GradleDependency 26 | implementation('com.regula.face:api:5.1.2371'){ 27 | transitive = true 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNFaceApiModule.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import static com.regula.facesdk.FaceSDK.Instance; 4 | 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.res.Configuration; 8 | import android.content.res.Resources; 9 | 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.bridge.ReactContext; 12 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 13 | import com.facebook.react.bridge.ReactMethod; 14 | import com.facebook.react.bridge.ReadableArray; 15 | import com.facebook.react.modules.core.DeviceEventManagerModule; 16 | import com.regula.facesdk.configuration.FaceCaptureConfiguration; 17 | import com.regula.facesdk.configuration.LivenessConfiguration; 18 | import com.regula.facesdk.configuration.MatchFaceConfiguration; 19 | import com.regula.facesdk.exception.InitException; 20 | import com.regula.facesdk.model.results.matchfaces.MatchFacesComparedFacesPair; 21 | import com.regula.facesdk.model.results.matchfaces.MatchFacesSimilarityThresholdSplit; 22 | 23 | import org.json.JSONArray; 24 | import org.json.JSONException; 25 | import org.json.JSONObject; 26 | 27 | import java.util.Iterator; 28 | import java.util.List; 29 | import java.util.Locale; 30 | 31 | @SuppressWarnings({"unused", "RedundantSuppression", "ConstantConditions", "SameParameterValue"}) 32 | public class RNFaceApiModule extends ReactContextBaseJavaModule { 33 | private final static String videoEncoderCompletionEvent = "videoEncoderCompletionEvent"; 34 | 35 | JSONArray data; 36 | private final ReactContext reactContext; 37 | 38 | public RNFaceApiModule(ReactApplicationContext reactContext) { 39 | super(reactContext); 40 | this.reactContext = reactContext; 41 | } 42 | 43 | @Override 44 | @SuppressWarnings("NullableProblems") 45 | public String getName() { 46 | return "RNFaceApi"; 47 | } 48 | 49 | private Context getContext() { 50 | return reactContext.getCurrentActivity(); 51 | } 52 | 53 | private Activity getActivity() { 54 | return getCurrentActivity(); 55 | } 56 | 57 | @SuppressWarnings({"WrapperTypeMayBePrimitive", "unchecked"}) 58 | private T args(int index) throws JSONException { 59 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 | // Rewrite it according to react native documentation!!! 61 | // the is no int or double in js so all ints are sent as double by default 62 | Object value = data.get(index); 63 | if (value instanceof Double) 64 | if ((Double) value % 1 == 0) { 65 | Integer intValue = ((Double) value).intValue(); 66 | return (T) intValue; 67 | } 68 | //noinspection unchecked 69 | return (T) data.get(index); 70 | } 71 | 72 | private void send(String event, String data) { 73 | reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(event, data); 74 | } 75 | 76 | private void sendVideoEncoderCompletion(String transactionId, boolean success) { 77 | send(videoEncoderCompletionEvent, JSONConstructor.generateVideoEncoderCompletion(transactionId, success).toString()); 78 | } 79 | 80 | private interface Callback { 81 | void success(Object o); 82 | 83 | void error(String s); 84 | 85 | default void success() { 86 | success(""); 87 | } 88 | } 89 | 90 | @ReactMethod 91 | public void exec(String moduleName, String action, ReadableArray args, com.facebook.react.bridge.Callback successCallback, com.facebook.react.bridge.Callback errorCallback) { 92 | data = new JSONArray(args.toArrayList()); 93 | Callback callback = new Callback() { 94 | @Override 95 | public void success(Object o) { 96 | if (o instanceof Integer) 97 | successCallback.invoke(o); 98 | else if (o instanceof Boolean) 99 | successCallback.invoke((boolean) o ? "true" : ""); 100 | else 101 | successCallback.invoke(o); 102 | } 103 | 104 | @Override 105 | public void error(String s) { 106 | errorCallback.invoke(s); 107 | } 108 | }; 109 | 110 | try { 111 | switch (action) { 112 | case "getServiceUrl": 113 | getServiceUrl(callback); 114 | break; 115 | case "startLiveness": 116 | startLiveness(callback); 117 | break; 118 | case "getFaceSdkVersion": 119 | getFaceSdkVersion(callback); 120 | break; 121 | case "presentFaceCaptureActivity": 122 | presentFaceCaptureActivity(callback); 123 | break; 124 | case "stopFaceCaptureActivity": 125 | stopFaceCaptureActivity(callback); 126 | break; 127 | case "init": 128 | init(callback); 129 | break; 130 | case "deinit": 131 | deinit(callback); 132 | break; 133 | case "isInitialized": 134 | isInitialized(callback); 135 | break; 136 | case "stopLivenessProcessing": 137 | stopLivenessProcessing(callback); 138 | break; 139 | case "setRequestHeaders": 140 | setRequestHeaders(callback, args(0)); 141 | break; 142 | case "presentFaceCaptureActivityWithConfig": 143 | presentFaceCaptureActivityWithConfig(callback, args(0)); 144 | break; 145 | case "startLivenessWithConfig": 146 | startLivenessWithConfig(callback, args(0)); 147 | break; 148 | case "setServiceUrl": 149 | setServiceUrl(callback, args(0)); 150 | break; 151 | case "matchFaces": 152 | matchFaces(callback, args(0)); 153 | break; 154 | case "detectFaces": 155 | detectFaces(callback, args(0)); 156 | break; 157 | case "matchFacesWithConfig": 158 | matchFacesWithConfig(callback, args(0), args(1)); 159 | break; 160 | case "setLanguage": 161 | setLanguage(callback, args(0)); 162 | break; 163 | case "matchFacesSimilarityThresholdSplit": 164 | matchFacesSimilarityThresholdSplit(callback, args(0), args(1)); 165 | break; 166 | } 167 | } catch (Exception e) { 168 | e.printStackTrace(); 169 | } 170 | } 171 | 172 | private void getServiceUrl(Callback callback) { 173 | callback.success(Instance().getServiceUrl()); 174 | } 175 | 176 | private void setRequestHeaders(Callback callback, JSONObject headers) { 177 | Instance().setNetworkInterceptorListener(requestBuilder -> { 178 | try { 179 | Iterator keys = headers.keys(); 180 | while (keys.hasNext()) { 181 | String key = keys.next(); 182 | String value = (String) headers.get(key); 183 | requestBuilder.header(key, value); 184 | } 185 | } catch (JSONException e) { 186 | e.printStackTrace(); 187 | } 188 | }); 189 | callback.success(); 190 | } 191 | 192 | private void startLiveness(Callback callback) { 193 | Instance().startLiveness(getContext(), (response) -> callback.success(JSONConstructor.generateLivenessResponse(response).toString())); 194 | } 195 | 196 | private void detectFaces(Callback callback, String request) throws JSONException { 197 | Instance().detectFaces(JSONConstructor.DetectFacesRequestFromJSON(new JSONObject(request)), (response) -> callback.success(JSONConstructor.generateDetectFacesResponse(response).toString())); 198 | } 199 | 200 | private void getFaceSdkVersion(Callback callback) { 201 | callback.success(Instance().getFaceSdkVersion()); 202 | } 203 | 204 | private void presentFaceCaptureActivity(Callback callback) { 205 | Instance().presentFaceCaptureActivity(getContext(), (response) -> callback.success(JSONConstructor.generateFaceCaptureResponse(response).toString())); 206 | } 207 | 208 | private void stopFaceCaptureActivity(Callback callback) { 209 | Instance().stopFaceCaptureActivity(getContext()); 210 | callback.success(); 211 | } 212 | 213 | private void stopLivenessProcessing(Callback callback) { 214 | Instance().stopLivenessProcessing(getContext()); 215 | callback.success(); 216 | } 217 | 218 | private void presentFaceCaptureActivityWithConfig(Callback callback, JSONObject config) throws JSONException { 219 | FaceCaptureConfiguration.Builder builder = new FaceCaptureConfiguration.Builder(); 220 | if (config.has("copyright")) 221 | builder.setCopyright(config.getBoolean("copyright")); 222 | if (config.has("cameraId")) 223 | builder.setCameraId(config.getInt("cameraId")); 224 | if (config.has("cameraSwitchEnabled")) 225 | builder.setCameraSwitchEnabled(config.getBoolean("cameraSwitchEnabled")); 226 | if (config.has("showHelpTextAnimation")) 227 | builder.setShowHelpTextAnimation(config.getBoolean("showHelpTextAnimation")); 228 | if (config.has("closeButtonEnabled")) 229 | builder.setCloseButtonEnabled(config.getBoolean("closeButtonEnabled")); 230 | if (config.has("torchButtonEnabled")) 231 | builder.setTorchButtonEnabled(config.getBoolean("torchButtonEnabled")); 232 | if (config.has("timeout")) 233 | builder.setTimeout(config.getInt("timeout")); 234 | Instance().presentFaceCaptureActivity(getContext(), builder.build(), (response) -> callback.success(JSONConstructor.generateFaceCaptureResponse(response).toString())); 235 | } 236 | 237 | private void startLivenessWithConfig(Callback callback, JSONObject config) throws JSONException { 238 | LivenessConfiguration.Builder builder = new LivenessConfiguration.Builder(); 239 | if (config.has("copyright")) 240 | builder.setCopyright(config.getBoolean("copyright")); 241 | if (config.has("attemptsCount")) 242 | builder.setAttemptsCount(config.getInt("attemptsCount")); 243 | if (config.has("sessionId")) 244 | builder.setSessionId(config.getString("sessionId")); 245 | if (config.has("skipStep")) 246 | builder.setSkipStep(JSONConstructor.LivenessSkipStepArrayFromJSON(config.getInt("skipStep"))); 247 | if (config.has("showHelpTextAnimation")) 248 | builder.setShowHelpTextAnimation(config.getBoolean("showHelpTextAnimation")); 249 | if (config.has("locationTrackingEnabled")) 250 | builder.setLocationTrackingEnabled(config.getBoolean("locationTrackingEnabled")); 251 | if (config.has("closeButtonEnabled")) 252 | builder.setCloseButtonEnabled(config.getBoolean("closeButtonEnabled")); 253 | if (config.has("recordingProcess")) 254 | builder.setRecordingProcess(config.getBoolean("recordingProcess")); 255 | Instance().startLiveness(getContext(), builder.build(), (response) -> callback.success(JSONConstructor.generateLivenessResponse(response).toString())); 256 | } 257 | 258 | private void setServiceUrl(Callback callback, String url) { 259 | Instance().setServiceUrl(url); 260 | callback.success(); 261 | } 262 | 263 | private void init(Callback callback) { 264 | Instance().init(getContext(), (boolean success, InitException error) -> { 265 | if (success) 266 | Instance().setVideoEncoderCompletion(this::sendVideoEncoderCompletion); 267 | callback.success(JSONConstructor.generateInitCompletion(success, error).toString()); 268 | }); 269 | } 270 | 271 | private void deinit(Callback callback) { 272 | Instance().deinit(); 273 | callback.success(); 274 | } 275 | 276 | private void isInitialized(Callback callback) { 277 | callback.success(Instance().isInitialized()); 278 | } 279 | 280 | private void matchFaces(Callback callback, String request) throws JSONException { 281 | Instance().matchFaces(JSONConstructor.MatchFacesRequestFromJSON(new JSONObject(request)), (response) -> callback.success(JSONConstructor.generateMatchFacesResponse(response).toString())); 282 | } 283 | 284 | private void matchFacesWithConfig(Callback callback, String request, @SuppressWarnings("unused") JSONObject config) throws JSONException { 285 | MatchFaceConfiguration.Builder builder = new MatchFaceConfiguration.Builder(); 286 | Instance().matchFaces(JSONConstructor.MatchFacesRequestFromJSON(new JSONObject(request)), builder.build(), (response) -> callback.success(JSONConstructor.generateMatchFacesResponse(response).toString())); 287 | } 288 | 289 | private void matchFacesSimilarityThresholdSplit(Callback callback, String array, Double similarity) throws JSONException { 290 | List faces = JSONConstructor.listFromJSON(new JSONArray(array), JSONConstructor::MatchFacesComparedFacesPairFromJSON); 291 | MatchFacesSimilarityThresholdSplit split = new MatchFacesSimilarityThresholdSplit(faces, similarity); 292 | callback.success(JSONConstructor.generateMatchFacesSimilarityThresholdSplit(split).toString()); 293 | } 294 | 295 | private void setLanguage(Callback callback, String language) { 296 | Locale locale = new Locale(language); 297 | Locale.setDefault(locale); 298 | Resources resources = getContext().getResources(); 299 | Configuration config = resources.getConfiguration(); 300 | config.setLocale(locale); 301 | resources.updateConfiguration(config, resources.getDisplayMetrics()); 302 | callback.success(); 303 | } 304 | } -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNFaceApiPackage.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.react.bridge.NativeModule; 11 | import com.facebook.react.bridge.ReactApplicationContext; 12 | import com.facebook.react.uimanager.ViewManager; 13 | import com.facebook.react.bridge.JavaScriptModule; 14 | @SuppressWarnings({"rawtypes", "unused", "RedundantSuppression"}) 15 | public class RNFaceApiPackage implements ReactPackage { 16 | @NonNull 17 | @Override 18 | public List createNativeModules(@NonNull ReactApplicationContext reactContext) { 19 | return Collections.singletonList(new RNFaceApiModule(reactContext)); 20 | } 21 | 22 | // Deprecated from RN 0.47 23 | public List> createJSModules() { 24 | return Collections.emptyList(); 25 | } 26 | 27 | @NonNull 28 | @Override 29 | public List createViewManagers(@NonNull ReactApplicationContext reactContext) { 30 | return Collections.emptyList(); 31 | } 32 | } -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; These should not be required directly 12 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 13 | node_modules/warning/.* 14 | 15 | ; Flow doesn't support platforms 16 | .*/Libraries/Utilities/LoadingView.js 17 | 18 | [untyped] 19 | .*/node_modules/@react-native-community/cli/.*/.* 20 | 21 | [include] 22 | 23 | [libs] 24 | node_modules/react-native/interface.js 25 | node_modules/react-native/flow/ 26 | 27 | [options] 28 | emoji=true 29 | 30 | esproposal.optional_chaining=enable 31 | esproposal.nullish_coalescing=enable 32 | 33 | module.file_ext=.js 34 | module.file_ext=.json 35 | module.file_ext=.ios.js 36 | 37 | munge_underscores=true 38 | 39 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 40 | module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 41 | 42 | suppress_type=$FlowIssue 43 | suppress_type=$FlowFixMe 44 | suppress_type=$FlowFixMeProps 45 | suppress_type=$FlowFixMeState 46 | 47 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 50 | 51 | [lints] 52 | sketchy-null-number=warn 53 | sketchy-null-mixed=warn 54 | sketchy-number=warn 55 | untyped-type-import=warn 56 | nonstrict-import=warn 57 | deprecated-type=warn 58 | unsafe-getters-setters=warn 59 | inexact-spread=warn 60 | unnecessary-invariant=warn 61 | signature-verification-failure=warn 62 | deprecated-utility=error 63 | 64 | [strict] 65 | deprecated-type 66 | nonstrict-import 67 | sketchy-null 68 | unclear-type 69 | unsafe-getters-setters 70 | untyped-import 71 | untyped-type-import 72 | 73 | [version] 74 | ^0.113.0 75 | -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .gradle 28 | local.properties 29 | *.iml 30 | 31 | # node.js 32 | # 33 | node_modules/ 34 | npm-debug.log 35 | yarn-error.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | *.keystore 41 | !debug.keystore 42 | 43 | # fastlane 44 | # 45 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 46 | # screenshots whenever they are needed. 47 | # For more information about the recommended setup visit: 48 | # https://docs.fastlane.tools/best-practices/source-control/ 49 | 50 | */fastlane/report.xml 51 | */fastlane/Preview.html 52 | */fastlane/screenshots 53 | 54 | # Bundle artifact 55 | *.jsbundle 56 | 57 | # CocoaPods 58 | /ios/Pods/ 59 | 60 | 61 | .idea/ 62 | -------------------------------------------------------------------------------- /example/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { StyleSheet, View, Button, Text, Image, TouchableHighlight, Alert, LogBox, NativeEventEmitter } from 'react-native' 3 | import { launchImageLibrary } from 'react-native-image-picker'; 4 | import FaceSDK, { Enum, FaceCaptureResponse, LivenessResponse, MatchFacesResponse, MatchFacesRequest, MatchFacesImage, MatchFacesSimilarityThresholdSplit, RNFaceApi } from '@regulaforensics/react-native-face-api' 5 | 6 | LogBox.ignoreLogs(['new NativeEventEmitter']); 7 | const eventManager = new NativeEventEmitter(RNFaceApi) 8 | 9 | var image1 = new MatchFacesImage() 10 | var image2 = new MatchFacesImage() 11 | 12 | export default class App extends Component { 13 | constructor(props) { 14 | super(props) 15 | 16 | eventManager.addListener('videoEncoderCompletionEvent', json => { 17 | response = JSON.parse(json) 18 | transactionId = response["transactionId"]; 19 | success = response["success"]; 20 | console.log("video_encoder_completion:"); 21 | console.log(" success: " + success); 22 | console.log(" transactionId: " + transactionId); 23 | }) 24 | 25 | FaceSDK.init(json => { 26 | response = JSON.parse(json) 27 | if (!response["success"]) { 28 | console.log("Init failed: "); 29 | console.log(json); 30 | } 31 | }, e => { }) 32 | 33 | this.state = { 34 | img1: require('./images/portrait.png'), 35 | img2: require('./images/portrait.png'), 36 | similarity: "nil", 37 | liveness: "nil" 38 | } 39 | } 40 | 41 | pickImage(first) { 42 | Alert.alert("Select option", "", [ 43 | { 44 | text: "Use gallery", 45 | onPress: () => launchImageLibrary({ includeBase64: true }, response => { 46 | if (response.assets == undefined) return 47 | this.setImage(first, response.assets[0].base64, Enum.ImageType.PRINTED) 48 | }) 49 | }, 50 | { 51 | text: "Use camera", 52 | onPress: () => FaceSDK.presentFaceCaptureActivity(result => { 53 | this.setImage(first, FaceCaptureResponse.fromJson(JSON.parse(result)).image.bitmap, Enum.ImageType.LIVE) 54 | }, e => { }) 55 | }], { cancelable: true }) 56 | } 57 | 58 | setImage(first, base64, type) { 59 | if (base64 == null) return 60 | this.setState({ similarity: "nil" }) 61 | if (first) { 62 | image1.bitmap = base64 63 | image1.imageType = type 64 | this.setState({ img1: { uri: "data:image/png;base64," + base64 } }) 65 | this.setState({ liveness: "nil" }) 66 | } else { 67 | image2.bitmap = base64 68 | image2.imageType = type 69 | this.setState({ img2: { uri: "data:image/png;base64," + base64 } }) 70 | } 71 | } 72 | 73 | clearResults() { 74 | this.setState({ 75 | img1: require('./images/portrait.png'), 76 | img2: require('./images/portrait.png'), 77 | similarity: "nil", 78 | liveness: "nil" 79 | }) 80 | image1 = new MatchFacesImage() 81 | image2 = new MatchFacesImage() 82 | } 83 | 84 | matchFaces() { 85 | if (image1 == null || image1.bitmap == null || image1.bitmap == "" || image2 == null || image2.bitmap == null || image2.bitmap == "") 86 | return 87 | this.setState({ similarity: "Processing..." }) 88 | request = new MatchFacesRequest() 89 | request.images = [image1, image2] 90 | FaceSDK.matchFaces(JSON.stringify(request), response => { 91 | response = MatchFacesResponse.fromJson(JSON.parse(response)) 92 | FaceSDK.matchFacesSimilarityThresholdSplit(JSON.stringify(response.results), 0.75, str => { 93 | var split = MatchFacesSimilarityThresholdSplit.fromJson(JSON.parse(str)) 94 | this.setState({ similarity: split.matchedFaces.length > 0 ? ((split.matchedFaces[0].similarity * 100).toFixed(2) + "%") : "error" }) 95 | }, e => { this.setState({ similarity: e }) }) 96 | }, e => { this.setState({ similarity: e }) }) 97 | } 98 | 99 | liveness() { 100 | FaceSDK.startLiveness(result => { 101 | result = LivenessResponse.fromJson(JSON.parse(result)) 102 | 103 | this.setImage(true, result.bitmap, Enum.ImageType.LIVE) 104 | if (result.bitmap != null) 105 | this.setState({ liveness: result["liveness"] == Enum.LivenessStatus.PASSED ? "passed" : "unknown" }) 106 | }, e => { }) 107 | } 108 | 109 | render() { 110 | return ( 111 | 112 | 113 | 114 | 115 | this.pickImage(true)}> 116 | 123 | 124 | 125 | 126 | this.pickImage(false)}> 127 | 134 | 135 | 136 | 137 | 138 | 139 | 140 |