├── .nvmrc
├── .gitattributes
├── .tool-versions
├── .yarnrc
├── SampleApp
├── .gitattributes
├── app.json
├── version.json
├── android
│ ├── app
│ │ ├── debug.keystore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── 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
│ │ │ │ │ └── xml
│ │ │ │ │ │ └── network_security_config.xml
│ │ │ │ ├── java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── sampleapp
│ │ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ │ └── MainApplication.java
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── sampleapp
│ │ │ │ └── DetoxTest.java
│ │ ├── proguard-rules.pro
│ │ ├── BUCK
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── settings.gradle
│ ├── gradle.properties
│ ├── build.gradle
│ ├── gradlew.bat
│ └── gradlew
├── TestUtils
│ ├── testProperties.js
│ └── waitForElement.js
├── jest.setup.js
├── ios
│ ├── SampleApp
│ │ ├── Images.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── SampleApp.entitlements
│ │ ├── AppDelegate.h
│ │ ├── main.m
│ │ ├── AppDelegate.m
│ │ ├── Info.plist
│ │ └── Base.lproj
│ │ │ └── LaunchScreen.xib
│ ├── SampleSwift.swift
│ ├── SampleApp.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── .xcode.env
│ ├── SampleAppTests
│ │ ├── Info.plist
│ │ └── SampleAppTests.m
│ ├── SampleApp-tvOSTests
│ │ └── Info.plist
│ ├── PrivacyInfo.xcprivacy
│ ├── SampleApp-tvOS
│ │ └── Info.plist
│ ├── Podfile
│ └── SampleApp.xcodeproj
│ │ └── xcshareddata
│ │ └── xcschemes
│ │ ├── SampleApp.xcscheme
│ │ └── SampleApp-tvOS.xcscheme
├── .eslintrc.js
├── .prettierrc.js
├── Gemfile
├── yalc.lock
├── e2eAndroid
│ ├── config.json
│ ├── init.js
│ └── sampleAppFlow.spec.js
├── babel.config.js
├── index.js
├── metro.config.js
├── jest.config.js
├── __tests__
│ └── App-test.js
├── colors.json
├── .gitignore
├── Router.js
├── Finish.js
├── Start.js
├── Gemfile.lock
├── package.json
├── App.js
├── README.md
├── backend-server-example.js
└── scripts
│ └── examples_postinstall.js
├── ios
├── .xcode.env
├── OnfidoSdkTests
│ ├── .swiftlint.yml
│ ├── colors.json
│ ├── Info.plist
│ └── ResponseTests.swift
├── OnfidoSdk.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── OnfidoSdk-Bridging-Header.h
├── PluginMetadata.h
├── PluginMetadata.m
├── OnfidoConfigParser.swift
├── OnfidoSdk.m
├── BridgeUtils.swift
├── OnfidoFlowBuilder.swift
├── EncryptedBiometricTokenHandlerReceiver.swift
├── CallbackReceiver.swift
├── OnfidoPluginConfig.swift
├── Podfile
├── OnfidoSdk.xcodeproj
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── OnfidoSdk.xcscheme
│ │ └── OnfidoSdkTests.xcscheme
├── OnfidoResponse.swift
└── OnfidoSdk.swift
├── .editorconfig
├── android
├── proguard-rules.pro
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── onfido
│ │ │ └── reactnative
│ │ │ └── sdk
│ │ │ ├── Pair.java
│ │ │ ├── OnfidoSdkPackage.java
│ │ │ ├── AnalyticsCallbackBridge.java
│ │ │ ├── BiometricTokenCallbackBridge.java
│ │ │ ├── Response.java
│ │ │ ├── ReactNativeBridgeUtils.java
│ │ │ └── OnfidoSdkActivityEventListener.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── onfido
│ │ └── reactnative
│ │ └── sdk
│ │ ├── ResponseTest.java
│ │ ├── ReactNativeBridgeUtilesTest.java
│ │ └── WritableMapImpl.java
├── publish.gradle
├── README.md
└── gradlew.bat
├── index.ts
├── find-tokens.sh
├── .npmignore
├── babel.config.js
├── scripts
├── update-integration-versions.sh
├── android_add_maven_link.js
├── android_enable_multi_dex.js
└── update_colors.js
├── onfido-react-native-sdk.podspec
├── tsconfig.json
├── LICENSE
├── package.json
├── .gitignore
├── MIGRATION.md
└── ONFIDO_STUDIO.md
/.nvmrc:
--------------------------------------------------------------------------------
1 | v21.1.0
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs 21.1.0
2 | ruby 3.2.4
3 |
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
1 | registry "https://registry.npmjs.org"
--------------------------------------------------------------------------------
/SampleApp/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | export NODE_BINARY=$(command -v node)
2 |
--------------------------------------------------------------------------------
/ios/OnfidoSdkTests/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - force_cast
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_size = 2
3 |
4 | [*.java]
5 | indent_size = 4
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.onfido.reactnative.sdk.** { *; }
2 |
--------------------------------------------------------------------------------
/SampleApp/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SampleApp",
3 | "displayName": "SampleApp"
4 | }
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 | org.gradle.jvmargs=-Xmx3076M
3 |
--------------------------------------------------------------------------------
/SampleApp/version.json:
--------------------------------------------------------------------------------
1 | {"commit": "6b48da2c4df8181c047c5a3155d3c146a81b3f4b", "version": "10.0.0"}
2 |
--------------------------------------------------------------------------------
/SampleApp/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/debug.keystore
--------------------------------------------------------------------------------
/SampleApp/TestUtils/testProperties.js:
--------------------------------------------------------------------------------
1 | export const textProps = {
2 | firstName: 'First Name',
3 | lastName: 'Last Name',
4 | };
5 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SampleApp
3 |
4 |
--------------------------------------------------------------------------------
/SampleApp/jest.setup.js:
--------------------------------------------------------------------------------
1 | import {jest} from '@jest/globals';
2 | jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter');
3 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import Onfido from "./js/Onfido";
2 | export * from './js/config_constants';
3 |
4 | export { Onfido };
5 | export default Onfido;
6 |
--------------------------------------------------------------------------------
/SampleApp/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native',
4 | plugins: ['detox'],
5 | rules: {
6 | 'prettier/prettier': 0,
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | };
8 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SampleApp/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby '>= 3.2.4'
5 |
6 | gem 'cocoapods', '1.16.1'
7 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onfido/react-native-sdk/HEAD/SampleApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SampleApp/yalc.lock:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v1",
3 | "packages": {
4 | "@onfido/react-native-sdk": {
5 | "signature": "30d477b143c4377a4f13eddbe92ff157",
6 | "file": true
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/SampleApp/e2eAndroid/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "setupFilesAfterEnv": ["./init.js"],
3 | "testEnvironment": "node",
4 | "reporters": ["detox/runners/jest/streamlineReporter"],
5 | "verbose": true
6 | }
7 |
--------------------------------------------------------------------------------
/find-tokens.sh:
--------------------------------------------------------------------------------
1 | if git grep -e api_sandbox --or -e api_live --or -e sdk_sandbox --or -e sdk_live -- ':!find-tokens.sh'
2 | then
3 | echo "ERROR: Found a token in your code. Please remove it before commiting."
4 | exit 1
5 | fi
--------------------------------------------------------------------------------
/SampleApp/ios/SampleSwift.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SampleSwift.swift
3 | // SampleApp
4 | //
5 | // Created by Santana, Luis on 3/10/20.
6 | // Copyright © 2020 Facebook. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | TestApp
2 | SampleApp
3 | .gitlab
4 | testutils
5 |
6 | .gitlab-ci.yml
7 | bitrise.yml
8 | .huskyrc
9 | .gitattributes
10 |
11 | # Tests
12 | #
13 | js/__tests__
14 | android/src/test
15 | ios/OnfidoSdkTests
16 |
17 | CONTRIBUTING.md
--------------------------------------------------------------------------------
/SampleApp/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@babel/preset-env',
4 | 'module:metro-react-native-babel-preset',
5 | 'module:react-native-dotenv',
6 | ],
7 | targets: {
8 | node: 'current'
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/SampleApp/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import {AppRegistry} from 'react-native';
6 | import Router from './Router';
7 | import {name as appName} from './app.json';
8 |
9 | AppRegistry.registerComponent(appName, () => Router);
10 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | '@babel/preset-env',
5 | {
6 | targets: {
7 | node: 'current',
8 | },
9 | },
10 | ],
11 | 'module:metro-react-native-babel-preset'
12 | ],
13 | };
14 |
--------------------------------------------------------------------------------
/SampleApp/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'SampleApp'
2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 | include ':app'
4 | includeBuild('../node_modules/@react-native/gradle-plugin')
--------------------------------------------------------------------------------
/SampleApp/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jul 30 16:08:19 CEST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 10.0.2.2
5 | localhost
6 |
7 |
--------------------------------------------------------------------------------
/SampleApp/metro.config.js:
--------------------------------------------------------------------------------
1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
2 | /**
3 | * Metro configuration
4 | * https://facebook.github.io/metro/docs/configuration
5 | *
6 | * @type {import('metro-config').MetroConfig}
7 | */
8 | const config = {};
9 | module.exports = mergeConfig(getDefaultConfig(__dirname), config);
10 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/SampleApp.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.nfc.readersession.formats
6 |
7 | TAG
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoSdk-Bridging-Header.h
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 | //
7 | // Use this file to import your target's public headers that you would like to expose to Swift.
8 | //
9 |
10 | #import
11 | #import
12 | #import "PluginMetadata.h"
13 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | @interface AppDelegate : RCTAppDelegate
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ios/PluginMetadata.h:
--------------------------------------------------------------------------------
1 | //
2 | // PluginMetadata.h
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | #import
8 |
9 | NS_ASSUME_NONNULL_BEGIN
10 |
11 | @interface PluginMetadata : NSObject
12 | @property (nonatomic, readonly) NSString* pluginPlatform;
13 | @property (nonatomic, readonly) NSString* pluginVersion;
14 | @end
15 |
16 | NS_ASSUME_NONNULL_END
17 |
--------------------------------------------------------------------------------
/ios/PluginMetadata.m:
--------------------------------------------------------------------------------
1 | //
2 | // PluginMetadata.m
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | #import "PluginMetadata.h"
8 |
9 | @implementation PluginMetadata
10 |
11 | - (instancetype)init
12 | {
13 | self = [super init];
14 | if (self) {
15 | _pluginPlatform = @"react-native";
16 | _pluginVersion = @"15.3.0";
17 | }
18 | return self;
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/java/com/sampleapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.sampleapp;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript. This is used to schedule
9 | * rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "SampleApp";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/android/src/main/java/com/onfido/reactnative/sdk/Pair.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | /*
4 | Good guy Java doesn't have either .withIndex() , or the (Kotlin) Pair, so here is a dedicated class
5 | to be used for mapping, to simulate the Kotlin Pair
6 | */
7 | public class Pair {
8 | int index;
9 | byte[] data;
10 |
11 | public Pair(int index, byte[] data) {
12 | this.index = index;
13 | this.data = data;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 |
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SampleApp/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'react-native',
3 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
4 | transformIgnorePatterns: [
5 | 'node_modules/(?!(' +
6 | '@react-native|react-native' +
7 | '|@onfido/react-native-sdk' +
8 | '|react-router-native' +
9 | '|invariant' +
10 | ')/)',
11 | ],
12 | testMatch: ['**/*+(__tests__/**-test.js)'],
13 | testEnvironment: 'node',
14 | setupFiles: ['/jest.setup.js'],
15 | };
16 |
--------------------------------------------------------------------------------
/SampleApp/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 | # NODE_BINARY variable contains the PATH to the node executable.
6 | #
7 | # Customize the NODE_BINARY variable here.
8 | # For example, to use nvm with brew, add the following line
9 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
10 | export NODE_BINARY=$(command -v node)
--------------------------------------------------------------------------------
/scripts/update-integration-versions.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | PROJ_DIR=.
4 | MANIFEST_FILE=${PROJ_DIR}/android/src/main/AndroidManifest.xml
5 | IOS_PLUGIN_FILE=${PROJ_DIR}/ios/PluginMetadata.m
6 |
7 | update_manifest()
8 | {
9 | sed -i -e "s/android:value=\"[0-9]*\.[0-9]*\.[0-9]*\"/android:value=\"$2\"/g" $1
10 | }
11 |
12 | update_plugin_file()
13 | {
14 | sed -i -e "s/_pluginVersion = @\"[0-9]*\.[0-9]*\.[0-9]*\"/_pluginVersion = @\"$2\"/g" $1
15 | }
16 |
17 | update_manifest ${MANIFEST_FILE} $PACKAGE_VERSION
18 | update_plugin_file ${IOS_PLUGIN_FILE} $PACKAGE_VERSION
19 |
--------------------------------------------------------------------------------
/ios/OnfidoSdkTests/colors.json:
--------------------------------------------------------------------------------
1 | {
2 | "onfidoPrimaryColor": "#FF0000",
3 | "onfidoPrimaryButtonTextColor": "#00FF00",
4 | "onfidoPrimaryButtonColorPressed": "#0000FF",
5 | "onfidoIosSupportDarkMode": true,
6 | "secondaryTitleColor": "#FF0000",
7 | "secondaryBackgroundPressedColor": "#FF0000",
8 | "bubbleErrorBackgroundColor": "#F53636",
9 | "buttonCornerRadius": 12,
10 | "fontFamilyBody": "",
11 | "fontFamilyTitle": "",
12 | "captureSuccessColors": {
13 | "borderColor": "#51D17B",
14 | "tickViewImageTintColor": "#058731",
15 | "tickViewBackgroundColor": "#CBF8DA"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SampleApp/__tests__/App-test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | jest.mock('@onfido/react-native-sdk', () => {
13 | return {
14 | Onfido: {
15 | OnfidoSdk: {
16 | start: jest.fn().mockReturnValue(Promise.resolve()),
17 | },
18 | },
19 | };
20 | });
21 |
22 | jest.mock("../backend-server-example.js");
23 |
24 |
25 | it('renders correctly', () => {
26 | renderer.create();
27 | });
28 |
--------------------------------------------------------------------------------
/ios/OnfidoConfigParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoConfigParser.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Foundation
8 |
9 | struct OnfidoConfigParser {
10 | func parse(_ config: NSDictionary) throws -> OnfidoPluginConfig {
11 | try decodeConfig(from: config)
12 | }
13 |
14 | private func decodeConfig(from dictionary: NSDictionary) throws -> T {
15 | let jsonData = try JSONSerialization.data(withJSONObject: dictionary, options: [])
16 | let decoder = JSONDecoder()
17 | let config = try decoder.decode(T.self, from: jsonData)
18 | return config
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/SampleApp/colors.json:
--------------------------------------------------------------------------------
1 | {
2 | "onfidoPrimaryColor": "#FF0000",
3 | "onfidoPrimaryButtonTextColor": "#FFFFFF",
4 | "onfidoPrimaryButtonColorPressed": "#FFA500",
5 | "interfaceStyle": "system",
6 | "secondaryTitleColor": "#FF0000",
7 | "secondaryBackgroundPressedColor": "#FF0000",
8 | "bubbleErrorBackgroundColor": "#F53636",
9 | "buttonCornerRadius": 12,
10 | "fontFamilyBody": "",
11 | "fontFamilyTitle": "",
12 | "captureSuccessColors": {
13 | "borderColor": "#51D17B",
14 | "tickViewImageTintColor": "#058731",
15 | "tickViewBackgroundColor": "#CBF8DA"
16 | },
17 | "backgroundColor": {
18 | "light": "#FCFCFD",
19 | "dark": "#000000"
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk.m:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoSdk.m
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | #import
8 | #import
9 | #import
10 | @interface RCT_EXTERN_MODULE(OnfidoSdk, RCTEventEmitter)
11 |
12 | RCT_EXTERN_METHOD(
13 | start:(NSDictionary *)config
14 | resolver:(RCTPromiseResolveBlock)resolve
15 | rejecter:(RCTPromiseRejectBlock)reject
16 | )
17 | RCT_EXTERN_METHOD(supportedEvents)
18 | RCT_EXTERN_METHOD(withAnalyticsCallback)
19 | RCT_EXTERN_METHOD(withMediaCallbacksEnabled)
20 | RCT_EXTERN_METHOD(withBiometricTokenCallback)
21 | RCT_EXTERN_METHOD(provideBiometricToken:(NSString *)biometricToken)
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/SampleApp/TestUtils/waitForElement.js:
--------------------------------------------------------------------------------
1 | import {element, by, waitFor, expect} from 'detox';
2 |
3 | export const waitForElementByType = async type => {
4 | await waitFor(element(by.type(`${type}`)).atIndex(0))
5 | .toBeVisible()
6 | .withTimeout(9000);
7 | return expect(element(by.type(`${type}`)).atIndex(0)).toBeVisible();
8 | };
9 |
10 | export const waitForElementByLabel = async label => {
11 | await waitFor(element(by.label(`${label}`)))
12 | .toBeVisible()
13 | .withTimeout(9000);
14 | return expect(element(by.label(`${label}`))).toBeVisible();
15 | };
16 |
17 | export const waitForElementByText = async text => {
18 | await waitFor(element(by.text(`${text}`)))
19 | .toBeVisible()
20 | .withTimeout(9000);
21 | return expect(element(by.text(`${text}`))).toBeVisible();
22 | };
23 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/ios/OnfidoSdkTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SampleApp/e2eAndroid/init.js:
--------------------------------------------------------------------------------
1 | /* eslint-env detox/detox, jest, jasmine */
2 |
3 | const detox = require('detox');
4 | const config = require('../package.json').detox;
5 | const adapter = require('detox/runners/jest/adapter');
6 | const specReporter = require('detox/runners/jest/specReporter');
7 |
8 | // Set the default timeout
9 | jest.setTimeout(1200000);
10 |
11 | jasmine.getEnv().addReporter(adapter);
12 |
13 | // This takes care of generating status logs on a per-spec basis. By default, jest only reports at file-level.
14 | // This is strictly optional.
15 | jasmine.getEnv().addReporter(specReporter);
16 |
17 | beforeAll(async () => {
18 | await detox.init(config);
19 | });
20 |
21 | beforeEach(async () => {
22 | await adapter.beforeEach();
23 | });
24 |
25 | afterAll(async () => {
26 | await adapter.afterAll();
27 | await detox.cleanup();
28 | });
29 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleAppTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/BridgeUtils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BridgeUtils.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | /*
8 | NOTE: These are used in junction with RN + Android, to communicate the
9 | information received to the MediaCallback added in TestApp/App.js
10 | */
11 |
12 | import Foundation
13 |
14 | enum Keys {
15 | enum MediaCallback {
16 | static let fileData = "fileData"
17 | static let fileName = "fileName"
18 | static let fileType = "fileType"
19 | static let documentSide = "side"
20 | static let documentType = "type"
21 | static let documentIssuingCountry = "issuingCountry"
22 | static let captureType = "captureType"
23 | }
24 |
25 | enum CaptureType {
26 | static let document = "DOCUMENT"
27 | static let face = "FACE"
28 | static let video = "VIDEO"
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/onfido-react-native-sdk.podspec:
--------------------------------------------------------------------------------
1 | require "json"
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "onfido-react-native-sdk"
7 | s.version = package["version"]
8 | s.summary = package["description"]
9 | s.description = <<-DESC
10 | onfido-react-native-sdk
11 | DESC
12 | s.homepage = "https://github.com/onfido/react-native-sdk"
13 | s.license = "MIT"
14 | s.authors = { "Onfido" => "engineering@onfido.com" }
15 | s.platforms = { :ios => "13.0" }
16 | s.source = { :git => "https://github.com/onfido/react-native-sdk.git", :tag => "#{s.version}" }
17 |
18 | s.source_files = "ios/**/*.{h,m,swift}"
19 | s.exclude_files = "ios/OnfidoSdkTests/"
20 | s.requires_arc = true
21 |
22 | s.dependency "React"
23 | s.dependency "Onfido", "~> 32.6.0"
24 | end
25 |
--------------------------------------------------------------------------------
/android/src/main/java/com/onfido/reactnative/sdk/OnfidoSdkPackage.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import com.facebook.react.ReactPackage;
8 | import com.facebook.react.bridge.NativeModule;
9 | import com.facebook.react.bridge.ReactApplicationContext;
10 | import com.facebook.react.uimanager.ViewManager;
11 | import com.facebook.react.bridge.JavaScriptModule;
12 |
13 | public class OnfidoSdkPackage implements ReactPackage {
14 | @Override
15 | public List createNativeModules(ReactApplicationContext reactContext) {
16 | return Arrays.asList(new OnfidoSdkModule(reactContext));
17 | }
18 |
19 | @Override
20 | public List createViewManagers(ReactApplicationContext reactContext) {
21 | return Collections.emptyList();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "react-native-sdk": ["./index"]
6 | },
7 | "allowUnreachableCode": false,
8 | "allowUnusedLabels": false,
9 | "esModuleInterop": true,
10 | "importsNotUsedAsValues": "error",
11 | "forceConsistentCasingInFileNames": true,
12 | "jsx": "react",
13 | "lib": ["esnext"],
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitReturns": true,
18 | "noImplicitUseStrict": false,
19 | "noStrictGenericChecks": false,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "resolveJsonModule": true,
23 | "skipLibCheck": true,
24 | "strict": true,
25 | "target": "esnext"
26 | },
27 | "include": ["./js"],
28 | "exclude": ["./SampleApp", "./TestApp"],
29 | "extends": "@tsconfig/react-native/tsconfig.json"
30 | }
--------------------------------------------------------------------------------
/SampleApp/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # Needed for NFC
13 | -keep class org.jmrtd.** { *; }
14 | -keep class net.sf.scuba.** {*;}
15 | -keep class org.bouncycastle.** {*;}
16 | -keep class org.spongycastle.** {*;}
17 | -keep class org.ejbca.** {*;}
18 |
19 | # Needed for NFC
20 | -dontwarn kotlin.time.jdk8.DurationConversionsJDK8Kt
21 | -dontwarn org.ejbca.**
22 | -dontwarn org.bouncycastle.**
23 | -dontwarn module-info
24 | -dontwarn org.jmrtd.**
25 | -dontwarn net.sf.scuba.**
26 | -dontwarn org.spongycastle.**
--------------------------------------------------------------------------------
/SampleApp/android/app/src/androidTest/java/com/sampleapp/DetoxTest.java:
--------------------------------------------------------------------------------
1 | package com.sampleapp;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 | import androidx.test.filters.LargeTest;
5 | import androidx.test.rule.ActivityTestRule;
6 |
7 | import com.wix.detox.Detox;
8 | import com.wix.detox.config.DetoxConfig;
9 |
10 | import org.junit.Rule;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 |
14 | @RunWith(AndroidJUnit4.class)
15 | @LargeTest
16 | public class DetoxTest {
17 |
18 | @Rule
19 | public ActivityTestRule mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
20 |
21 | @Test
22 | public void runDetoxTests() {
23 | DetoxConfig detoxConfig = new DetoxConfig();
24 | detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
25 | detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
26 | detoxConfig.rnContextLoadTimeoutSec = (BuildConfig.DEBUG ? 180 : 60);
27 |
28 | Detox.runTests(mActivityRule, detoxConfig);
29 | }
30 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Onfido
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/SampleApp/ios/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 |
8 | NSPrivacyAccessedAPIType
9 | NSPrivacyAccessedAPICategoryFileTimestamp
10 | NSPrivacyAccessedAPITypeReasons
11 |
12 | C617.1
13 |
14 |
15 |
16 | NSPrivacyAccessedAPIType
17 | NSPrivacyAccessedAPICategoryUserDefaults
18 | NSPrivacyAccessedAPITypeReasons
19 |
20 | CA92.1
21 |
22 |
23 |
24 | NSPrivacyAccessedAPIType
25 | NSPrivacyAccessedAPICategorySystemBootTime
26 | NSPrivacyAccessedAPITypeReasons
27 |
28 | 35F9.1
29 |
30 |
31 |
32 | NSPrivacyCollectedDataTypes
33 |
34 | NSPrivacyTracking
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/SampleApp/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
21 |
22 | android.useAndroidX=true
23 |
24 | # Use this property to enable or disable the Hermes JS engine.
25 | # If set to false, you will be using JSC instead.
26 | hermesEnabled=false
--------------------------------------------------------------------------------
/SampleApp/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Android and Xcode
6 | build/
7 |
8 | # Tooling
9 | ios/.tool-versions
10 |
11 | # Xcode
12 | #
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata
22 | *.xccheckout
23 | *.moved-aside
24 | DerivedData
25 | *.hmap
26 | *.ipa
27 | *.xcuserstate
28 | ios/.xcode.env.local
29 |
30 | # Android/IntelliJ
31 | #
32 | .idea
33 | .gradle
34 | local.properties
35 | *.iml
36 |
37 | # node.js
38 | #
39 | node_modules/
40 | npm-debug.log
41 | yarn-error.log
42 | .yalc/
43 | yalc.lock
44 |
45 | # BUCK
46 | #
47 | buck-out/
48 | \.buckd/
49 | *.keystore
50 | !debug.keystore
51 |
52 | # fastlane
53 | #
54 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
55 | # screenshots whenever they are needed.
56 | # For more information about the recommended setup visit:
57 | # https://docs.fastlane.tools/best-practices/source-control/
58 |
59 | */fastlane/report.xml
60 | */fastlane/Preview.html
61 | */fastlane/screenshots
62 |
63 | # Bundle artifact
64 | #
65 | *.jsbundle
66 |
67 | # CocoaPods
68 | #
69 | /ios/Pods/
70 | /vendor/bundle/
71 |
72 | # Jest
73 | #
74 | coverage
--------------------------------------------------------------------------------
/SampleApp/Router.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {StyleSheet, View} from 'react-native';
3 |
4 | import {NativeRouter, Route} from 'react-router-native';
5 | import App from './App';
6 | import Start from './Start';
7 | import Finish from './Finish';
8 |
9 | export default class Router extends Component {
10 | render() {
11 | return (
12 |
13 |
14 | } />
15 |
16 | }
20 | />
21 |
22 | }
26 | />
27 |
28 |
29 | );
30 | }
31 | }
32 |
33 | const styles = StyleSheet.create({
34 | container: {
35 | flex: 1,
36 | justifyContent: 'center',
37 | alignItems: 'center',
38 | backgroundColor: '#F5FCFF',
39 | },
40 | welcome: {
41 | fontSize: 20,
42 | textAlign: 'center',
43 | margin: 10,
44 | },
45 | instructions: {
46 | textAlign: 'center',
47 | color: '#333333',
48 | marginBottom: 5,
49 | },
50 | });
51 |
--------------------------------------------------------------------------------
/SampleApp/Finish.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {StyleSheet, Text, View} from 'react-native';
3 | import {Link} from 'react-router-native';
4 |
5 | export default props => {
6 | return (
7 |
8 | Status:
9 | {props.match.params.status}
10 | Response:
11 | {props.match.params.message}
12 |
13 | Restart SDK
14 |
15 |
16 | );
17 | };
18 |
19 | const styles = StyleSheet.create({
20 | container: {
21 | flex: 1,
22 | justifyContent: 'center',
23 | alignItems: 'center',
24 | backgroundColor: '#F5FCFF',
25 | },
26 | buttonText: {
27 | fontSize: 20,
28 | textAlign: 'center',
29 | margin: 10,
30 | color: '#FFFFFF',
31 | },
32 | button: {
33 | backgroundColor: '#0080FF',
34 | marginBottom: 10,
35 | borderRadius: 10,
36 | marginTop: 20,
37 | },
38 | welcome: {
39 | fontSize: 20,
40 | textAlign: 'center',
41 | margin: 10,
42 | },
43 | instructions: {
44 | textAlign: 'center',
45 | color: '#333333',
46 | marginBottom: 10,
47 | },
48 | });
49 |
--------------------------------------------------------------------------------
/ios/OnfidoFlowBuilder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoFlowBuilder.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Foundation
8 | import Onfido
9 |
10 | struct OnfidoFlowBuilder {
11 | private let configBuilder: OnfidoConfigBuilder
12 |
13 | init(configBuilder: OnfidoConfigBuilder = OnfidoConfigBuilder()) {
14 | self.configBuilder = configBuilder
15 | }
16 |
17 | func build(
18 | with config: OnfidoPluginConfig,
19 | appearance: Appearance,
20 | customMediaCallback: CallbackReceiver?,
21 | customEncryptedBiometricTokenHandler: EncryptedBiometricTokenHandlerReceiver?
22 | ) throws -> OnfidoFlow {
23 | let mode = try configBuilder.build(
24 | config: config,
25 | appearance: appearance,
26 | mediaCallBack: customMediaCallback,
27 | encryptedBiometricTokenHandler: customEncryptedBiometricTokenHandler
28 | )
29 |
30 | let flow: OnfidoFlow
31 | switch mode {
32 | case .classic(configBuilder: let configBuilder):
33 | let config = try configBuilder.build()
34 | flow = OnfidoFlow(withConfiguration: config)
35 | case .studio(workflowConfig: let workflowConfig):
36 | flow = OnfidoFlow(workflowConfiguration: workflowConfig)
37 | }
38 |
39 | return flow
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/android/src/main/java/com/onfido/reactnative/sdk/AnalyticsCallbackBridge.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.facebook.react.bridge.Arguments;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.modules.core.DeviceEventManagerModule;
8 | import com.onfido.android.sdk.capture.analytics.OnfidoAnalyticsEvent;
9 | import com.onfido.android.sdk.capture.analytics.OnfidoAnalyticsEventListener;
10 |
11 | public class AnalyticsCallbackBridge implements OnfidoAnalyticsEventListener {
12 |
13 | public static final String CALLBACK_NAME = "onfidoAnalyticsCallback";
14 | private final ReactApplicationContext reactContext;
15 |
16 | public AnalyticsCallbackBridge(ReactApplicationContext reactContext) {
17 | this.reactContext = reactContext;
18 | }
19 |
20 | @Override
21 | public void onEvent(@NonNull OnfidoAnalyticsEvent event) {
22 |
23 | var properties = Arguments.createMap();
24 | for (var entry : event.getProperties().entrySet()) {
25 | properties.putString(entry.getKey().toString(), entry.getValue());
26 | }
27 |
28 | var params = Arguments.createMap();
29 | params.putString("type", event.getType().toString());
30 | params.putMap("properties", properties);
31 |
32 | reactContext
33 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
34 | .emit(CALLBACK_NAME, params);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SampleApp/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load("create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.sampleapp",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.sampleapp",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/android/publish.gradle:
--------------------------------------------------------------------------------
1 | import groovy.json.JsonSlurper
2 |
3 | afterEvaluate {
4 | tasks.register('sourceJar', Jar) {
5 | from android.sourceSets.main.java.srcDirs
6 | archiveClassifier = "sources"
7 | }
8 |
9 | publishing {
10 | def packageJson = new JsonSlurper().parseText(file('../package.json').text)
11 |
12 | publications {
13 | mavenJava(MavenPublication) {
14 | // The new gradle publish plugin doesn't allow the @onfido/ prefix
15 | artifactId = packageJson.name.replace("@onfido/", "onfido-")
16 | groupId = 'com.onfido.reactnative.sdk'
17 | version = packageJson.version
18 |
19 | from components.findByName('release')
20 |
21 | artifact sourceJar
22 |
23 | pom {
24 | name = packageJson.title
25 | description = packageJson.description
26 | url = packageJson.repository.baseUrl
27 |
28 | licenses {
29 | license {
30 | name = packageJson.license
31 | url = packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename
32 | distribution = 'repo'
33 | }
34 | }
35 |
36 | developers {
37 | developer {
38 | id = packageJson.author.email
39 | name = packageJson.author.name
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ios/EncryptedBiometricTokenHandlerReceiver.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EncryptedBiometricTokenHandlerReceiver.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Foundation
8 | import Onfido
9 |
10 | final class EncryptedBiometricTokenHandlerReceiver {
11 | private let onTokenRequestedCallback: (([String: String]) -> Void)?
12 | private let onTokenGeneratedCallback: (([String: String]) -> Void)?
13 |
14 | private var onTokenRequestedCompletion: ((String) -> Void)?
15 |
16 | init(
17 | withTokenRequestedCallback tokenRequestedCallback: (([String: String]) -> Void)?,
18 | andTokenGeneratedCallback tokenGeneratedCallback: (([String: String]) -> Void)?
19 | ) {
20 | self.onTokenRequestedCallback = tokenRequestedCallback
21 | self.onTokenGeneratedCallback = tokenGeneratedCallback
22 | }
23 |
24 | func provide(encryptedBiometricToken: String) {
25 | onTokenRequestedCompletion?(encryptedBiometricToken)
26 | }
27 | }
28 |
29 | extension EncryptedBiometricTokenHandlerReceiver: EncryptedBiometricTokenHandler {
30 | func onTokenRequested(customerUserHash: String, completion: @escaping (String) -> Void) {
31 | onTokenRequestedCompletion = completion
32 | let dictionary = [
33 | "customerUserHash" : customerUserHash
34 | ]
35 | onTokenRequestedCallback?(dictionary)
36 | }
37 |
38 | func onTokenGenerated(customerUserHash: String, encryptedBiometricToken: String) {
39 | let dictionary = [
40 | "customerUserHash" : customerUserHash,
41 | "encryptedBiometricToken" : encryptedBiometricToken
42 | ]
43 | onTokenGeneratedCallback?(dictionary)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSExceptionDomains
28 |
29 | localhost
30 |
31 | NSExceptionAllowsInsecureHTTPLoads
32 |
33 |
34 |
35 |
36 | NSLocationWhenInUseUsageDescription
37 |
38 | UILaunchStoryboardName
39 | LaunchScreen
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UIViewControllerBasedStatusBarAppearance
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/scripts/android_add_maven_link.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This script adds the bintray maven url to android/build.gradle.
3 | *
4 | * allprojects {
5 | * repositories {
6 | * maven { url "https://dl.bintray.com/onfido/maven" }
7 | * }
8 | * }
9 | *
10 | * Note: This script was written to work with ES5
11 | */
12 |
13 | var fs = require('fs');
14 |
15 | var mavenUrl = 'mavenCentral()';
16 | var targetCurrentPath = '../../../';
17 | var targetFile = 'android/build.gradle';
18 | var targetFileWithFullPath = targetCurrentPath + targetFile;
19 |
20 | var contents = fs.readFileSync(targetFileWithFullPath, 'utf8');
21 | var isLinked = contents.indexOf(mavenUrl) != -1;
22 |
23 | function indexOfOrExit(contents, target, startIndex) {
24 | var index = contents.indexOf(target, startIndex);
25 | if (index == -1) {
26 | console.warn('Warning: could not add', mavenUrl, 'to', targetFile);
27 | process.exit(1);
28 | }
29 | return index;
30 | }
31 |
32 | if (!isLinked) {
33 | var allprojectsIndex = indexOfOrExit(contents, "allprojects", 0);
34 | var repositoriesIndex = indexOfOrExit(contents, "repositories", allprojectsIndex);
35 | var repositoriesBraceIndex = indexOfOrExit(contents, "{", repositoriesIndex) + 1;
36 | var contentsStart = contents.substring(0,repositoriesBraceIndex);
37 | var contentsToInsert = '\n ' + mavenUrl + '\n';
38 | var contentsEnd = contents.substring(repositoriesBraceIndex);
39 | var contentsUpdated = contentsStart + contentsToInsert + contentsEnd;
40 | fs.writeFileSync(targetFileWithFullPath, contentsUpdated);
41 | console.log('Updated:', mavenUrl, 'was added to', targetFile);
42 | } else {
43 | console.log('Verified:', mavenUrl, 'is already in', targetFile);
44 | }
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import "AppDelegate.h"
9 |
10 | #import
11 | #import
12 | #import
13 |
14 | #if RCT_DEV
15 | #import
16 | #endif
17 |
18 | @implementation AppDelegate
19 |
20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
21 | {
22 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
23 |
24 | #if RCT_DEV
25 | [bridge moduleForClass:[RCTDevLoadingView class]];
26 | #endif
27 |
28 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
29 | moduleName:@"SampleApp"
30 | initialProperties:nil];
31 |
32 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
33 |
34 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
35 | UIViewController *rootViewController = [UIViewController new];
36 | rootViewController.view = rootView;
37 | self.window.rootViewController = rootViewController;
38 | [self.window makeKeyAndVisible];
39 | return YES;
40 | }
41 |
42 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
43 | {
44 | #if DEBUG
45 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
46 | #else
47 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
48 | #endif
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/android/README.md:
--------------------------------------------------------------------------------
1 | README
2 | ======
3 |
4 | If you want to publish the lib as a maven dependency, follow these steps before publishing a new version to npm:
5 |
6 | 1. Be sure to have the Android [SDK](https://developer.android.com/studio/index.html) and [NDK](https://developer.android.com/ndk/guides/index.html) installed
7 | 2. Be sure to have a `local.properties` file in this folder that points to the Android SDK and NDK
8 | ```
9 | ndk.dir=/Users/{username}/Library/Android/sdk/ndk-bundle
10 | sdk.dir=/Users/{username}/Library/Android/sdk
11 | ```
12 | 3. Run `./gradlew publishToMavenLocal`
13 | 4. Go to the `~/.m2` directory. Verify that the pom file was generated successfully with the correct version.
14 |
15 |
16 | How to quickly develop the Android Java code using the TestApp:
17 | ======
18 | React Native's "Fast Refresh" feature will not update Java code as you make changes, and reinstalling all npm packages is slow. Instead, you can follow this process to recompile only the Java code when you make changes.
19 |
20 | In one console, from the `TestApp/` directory, run the following commands. It may take 2 or more minutes to build. You only need to run this once: leave it running in the background while you develop.
21 | ```shell
22 | rm -rf node_modules/ && yarn && cd .. && watchman watch-del-all && npx react-native start --reset-cache
23 | ```
24 |
25 | In a second console, from the `TestApp/` directory, update the Android package and launch the virtual device. Run this each time you change Android code.
26 | ```shell
27 | rsync -av ../ node_modules/@onfido/react-native-sdk/ --exclude=TestApp --exclude=SampleApp --exclude=node_modules --exclude=android/build --exclude=.git && npx react-native run-android
28 | ```
29 |
30 | How to run the tests
31 | ======
32 | 1. Run "yarn" or "npm install" from the project root. This will download the React Native Facebook bridge library
33 | 2. Run "./gradlew test" from the "/android" directory.
34 |
--------------------------------------------------------------------------------
/SampleApp/Start.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {StyleSheet, Text, View, TextInput} from 'react-native';
3 | import {Link} from 'react-router-native';
4 |
5 | export default class Start extends Component {
6 | state = {
7 | firstName: null,
8 | lastName: null,
9 | };
10 |
11 | onChangeText = (key, value) => {
12 | this.setState({
13 | [key]: value,
14 | });
15 | };
16 |
17 | render() {
18 | return (
19 |
20 | First Name
21 | this.onChangeText('firstName', text)}
24 | value={this.state.firstName}
25 | />
26 | Last Name
27 | this.onChangeText('lastName', text)}
30 | value={this.state.lastName}
31 | />
32 |
35 | Start SDK
36 |
37 |
38 | );
39 | }
40 | }
41 |
42 | const styles = StyleSheet.create({
43 | container: {
44 | flex: 1,
45 | justifyContent: 'center',
46 | alignItems: 'center',
47 | backgroundColor: '#F5FCFF',
48 | },
49 | buttonText: {
50 | fontSize: 20,
51 | textAlign: 'center',
52 | margin: 10,
53 | color: '#FFFFFF',
54 | },
55 | button: {
56 | backgroundColor: '#0080FF',
57 | marginBottom: 10,
58 | borderRadius: 10,
59 | marginTop: 20,
60 | },
61 | input: {
62 | borderColor: 'gray',
63 | borderWidth: 1,
64 | height: 40,
65 | minWidth: '70%',
66 | },
67 | label: {
68 | fontSize: 18,
69 | textAlign: 'center',
70 | alignSelf: 'flex-start',
71 | marginTop: 10,
72 | marginBottom: 5,
73 | },
74 | });
75 |
--------------------------------------------------------------------------------
/android/src/main/java/com/onfido/reactnative/sdk/BiometricTokenCallbackBridge.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.facebook.react.bridge.Arguments;
6 | import com.facebook.react.bridge.ReactContext;
7 | import com.facebook.react.bridge.WritableMap;
8 | import com.facebook.react.modules.core.DeviceEventManagerModule;
9 | import com.onfido.android.sdk.capture.config.BiometricTokenCallback;
10 |
11 | import kotlin.Unit;
12 | import kotlin.jvm.functions.Function1;
13 |
14 | public class BiometricTokenCallbackBridge implements BiometricTokenCallback {
15 | private final ReactContext reactContext;
16 | private Function1 super String, Unit> provideTokenFunction;
17 |
18 | public BiometricTokenCallbackBridge(ReactContext reactContext) {
19 | this.reactContext = reactContext;
20 | }
21 |
22 | @Override
23 | public void onTokenGenerated(@NonNull String customerUserHash,
24 | @NonNull String biometricToken) {
25 | WritableMap params = Arguments.createMap();
26 | params.putString("customerUserHash", customerUserHash);
27 | params.putString("biometricToken", biometricToken);
28 | reactContext
29 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
30 | .emit("onTokenGenerated", params);
31 | }
32 |
33 | @Override
34 | public void onTokenRequested(@NonNull String customerUserHash,
35 | @NonNull Function1 super String, Unit> provideTokenFunction) {
36 | this.provideTokenFunction = provideTokenFunction;
37 | final WritableMap params = Arguments.createMap();
38 | params.putString("customerUserHash", customerUserHash);
39 | reactContext
40 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
41 | .emit("onTokenRequested", params);
42 | }
43 |
44 | public void provideToken(String biometricToken) {
45 | if (provideTokenFunction != null) {
46 | provideTokenFunction.invoke(biometricToken);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/scripts/android_enable_multi_dex.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This script adds "multiDexEnabled true" to android/app/build.gradle.
3 | *
4 | * android {
5 | * defaultConfig {
6 | * multiDexEnabled true
7 | * }
8 | * }
9 | *
10 | * Note: This script was written to work with ES5
11 | */
12 |
13 | var fs = require('fs');
14 |
15 | var targetConfigName = 'multiDexEnabled';
16 | var targetConfigValue = 'true';
17 | var targetConfig = targetConfigName + ' ' + targetConfigValue;
18 | var targetCurrentPath = '../../../';
19 | var targetFile = 'android/app/build.gradle';
20 | var targetFileWithFullPath = targetCurrentPath + targetFile;
21 | var contents = fs.readFileSync(targetFileWithFullPath, 'utf8');
22 | var targetConfigExists = contents.indexOf(targetConfig) != -1;
23 | var targetConfigNameExists = contents.indexOf(targetConfigName) != -1;
24 |
25 | function indexOfOrExit(contents, target, startIndex) {
26 | var index = contents.indexOf(target, startIndex);
27 | if (index == -1) {
28 | console.warn('Warning: could not add', targetConfig, 'to', targetFile);
29 | process.exit(1);
30 | }
31 | return index;
32 | }
33 |
34 | if (!targetConfigExists && !targetConfigNameExists) {
35 | var androidIndex = indexOfOrExit(contents, "android {", 0);
36 | var defaultConfigIndex = indexOfOrExit(contents, "defaultConfig", androidIndex);
37 | var defaultConfigIndexBraceIndex = indexOfOrExit(contents, "{", defaultConfigIndex) + 1;
38 | var contentsStart = contents.substring(0,defaultConfigIndexBraceIndex);
39 | var contentsToInsert = '\n ' + targetConfig + '\n';
40 | var contentsEnd = contents.substring(defaultConfigIndexBraceIndex);
41 | var contentsUpdated = contentsStart + contentsToInsert + contentsEnd;
42 | console.log('Updated:', targetConfig, 'was added to', targetFile);
43 | fs.writeFileSync(targetFileWithFullPath, contentsUpdated);
44 | } else if (!targetConfigExists && targetConfigNameExists) {
45 | console.log('Warning:', targetConfigName, 'is already in', targetFile, 'but is set to a different value');
46 | } else {
47 | console.log('Verified:', targetConfig, 'is already in', targetFile);
48 | }
--------------------------------------------------------------------------------
/SampleApp/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Resolve react_native_pods.rb with node to allow for hoisting
2 | require Pod::Executable.execute_command('node', ['-p',
3 | 'require.resolve(
4 | "react-native/scripts/react_native_pods.rb",
5 | {paths: [process.argv[1]]},
6 | )', __dir__]).strip
7 |
8 | platform :ios, '13.4'
9 | prepare_react_native_project!
10 |
11 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
12 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
13 | #
14 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
15 | # ```js
16 | # module.exports = {
17 | # dependencies: {
18 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
19 | # ```
20 |
21 | install! 'cocoapods', :deterministic_uuids => false
22 |
23 | production = ENV["PRODUCTION"] == "1"
24 |
25 | target 'SampleApp' do
26 | config = use_native_modules!
27 |
28 | # Flags change depending on the env values.
29 | flags = get_default_flags()
30 |
31 | use_react_native!(
32 | :path => config[:reactNativePath],
33 | # to enable hermes on iOS, change `false` to `true` and then install pods
34 | :hermes_enabled => false,
35 | #:hermes_enabled => flags[:hermes_enabled],
36 | #:fabric_enabled => flags[:fabric_enabled],
37 |
38 | # An absolute path to your application root.
39 | :app_path => "#{Pod::Config.instance.installation_root}/.."
40 | )
41 |
42 | target 'SampleAppTests' do
43 | inherit! :complete
44 | # Pods for testing
45 | end
46 |
47 | post_install do |installer|
48 | # React Native's post-install setup
49 | react_native_post_install(
50 | installer,
51 | config[:reactNativePath],
52 | :mac_catalyst_enabled => false
53 | )
54 |
55 | # Workaround for FOLLY_HAS_COROUTINES issue
56 | # https://github.com/facebook/folly/issues/2297#issuecomment-2442923702
57 | system("chmod -R u+w Pods/RCT-Folly")
58 | Dir.glob("Pods/RCT-Folly/folly/Portability.h").each do |file|
59 | text = File.read(file)
60 | new_contents = text.gsub('#define FOLLY_HAS_COROUTINES 1', '#define FOLLY_HAS_COROUTINES 0')
61 | File.open(file, "w") { |file| file.puts new_contents }
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleAppTests/SampleAppTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | #import
12 | #import
13 |
14 | #define TIMEOUT_SECONDS 600
15 | #define TEXT_TO_LOOK_FOR @"Welcome to React"
16 |
17 | @interface SampleAppTests : XCTestCase
18 |
19 | @end
20 |
21 | @implementation SampleAppTests
22 |
23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24 | {
25 | if (test(view)) {
26 | return YES;
27 | }
28 | for (UIView *subview in [view subviews]) {
29 | if ([self findSubviewInView:subview matching:test]) {
30 | return YES;
31 | }
32 | }
33 | return NO;
34 | }
35 |
36 | - (void)testRendersWelcomeScreen
37 | {
38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40 | BOOL foundElement = NO;
41 |
42 | __block NSString *redboxError = nil;
43 | #ifdef DEBUG
44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
45 | if (level >= RCTLogLevelError) {
46 | redboxError = message;
47 | }
48 | });
49 | #endif
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | #ifdef DEBUG
64 | RCTSetLogFunction(RCTDefaultLogFunction);
65 | #endif
66 |
67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
69 | }
70 |
71 |
72 | @end
73 |
--------------------------------------------------------------------------------
/SampleApp/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | import org.apache.tools.ant.taskdefs.condition.Os
3 |
4 | buildscript {
5 | ext {
6 | buildToolsVersion = "31.0.0"
7 | minSdkVersion = 21
8 | compileSdkVersion = 34
9 | targetSdkVersion = 34
10 | supportLibVersion = "27.1.0"
11 | kotlinVersion = "1.9.22"
12 |
13 | if (System.properties['os.arch'] == "aarch64") {
14 | // For M1 Users we need to use the NDK 24 which added support for aarch64
15 | ndkVersion = "24.0.8215888"
16 | } else {
17 | // Otherwise we default to the side-by-side NDK version from AGP.
18 | ndkVersion = "23.1.7779620"
19 | }
20 | }
21 | repositories {
22 | google()
23 | jcenter()
24 | }
25 | dependencies {
26 | classpath("com.android.tools.build:gradle:8.5.0")
27 | classpath("com.facebook.react:react-native-gradle-plugin")
28 | classpath("de.undercouch:gradle-download-task:5.5.0")
29 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
30 |
31 | // NOTE: Do not place your application dependencies here; they belong
32 | // in the individual module build.gradle files
33 |
34 | }
35 | }
36 |
37 | allprojects {
38 | repositories {
39 | mavenLocal()
40 | mavenCentral()
41 | maven {
42 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
43 | url("$rootDir/../node_modules/react-native/android")
44 | }
45 | maven {
46 | // Android JSC is installed from npm
47 | url("$rootDir/../node_modules/jsc-android/dist")
48 | }
49 |
50 | google()
51 | jcenter()
52 | maven { url 'https://jitpack.io' }
53 | maven { url "$rootDir/../node_modules/detox/Detox-android" }
54 | maven { url "https://maven.google.com" }
55 | }
56 | def REACT_NATIVE_VERSION = new File(['node', '--print',"JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim())
57 |
58 | configurations.all {
59 | resolutionStrategy {
60 | force "com.facebook.react:react-native:" + REACT_NATIVE_VERSION
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/SampleApp/e2eAndroid/sampleAppFlow.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env detox/detox, jest */
2 |
3 | import {waitForElementByText} from '../TestUtils/waitForElement';
4 | import {waitForElementByType} from '../TestUtils/waitForElement';
5 | import {textProps} from '../TestUtils/testProperties';
6 |
7 | describe('Android Sample App flow', () => {
8 | beforeEach(async function () {
9 | await device.reloadReactNative();
10 | });
11 |
12 | it('should complete the document and face flow on Android successfully', async () => {
13 | await element(by.id('firstName')).atIndex(0).typeText(textProps.firstName);
14 | await element(by.id('lastName')).atIndex(1).typeText(textProps.lastName);
15 | await element(by.text('Start SDK')).tap();
16 | await element(by.text('LAUNCH')).tap();
17 | await element(by.text('Start')).tap();
18 | await element(by.text('National Identity Card')).tap();
19 | await element(by.text('Bahrain')).tap();
20 | await element(by.type('androidx.appcompat.widget.AppCompatImageView'))
21 | .atIndex(0)
22 | .tap();
23 | await waitForElementByText('My card is readable');
24 | await element(by.text('My card is readable')).tap();
25 | await waitForElementByText('Take a new picture');
26 | await element(by.text('Take a new picture')).tap();
27 | await waitForElementByType('androidx.appcompat.widget.AppCompatImageView');
28 | await element(by.type('androidx.appcompat.widget.AppCompatImageView'))
29 | .atIndex(0)
30 | .tap();
31 | await waitForElementByText('My card is readable');
32 | await element(by.text('My card is readable')).tap();
33 | await waitForElementByType('androidx.appcompat.widget.AppCompatImageView');
34 | await element(by.type('androidx.appcompat.widget.AppCompatImageView'))
35 | .atIndex(0)
36 | .tap();
37 | await waitForElementByText('My card is readable');
38 | await element(by.text('My card is readable')).tap();
39 | await waitForElementByText('Continue');
40 | await element(by.text('Continue')).tap();
41 | await waitForElementByText('Start recording');
42 | await element(by.text('Start recording')).tap();
43 | await waitForElementByText('Next step');
44 | await element(by.text('Next step')).tap();
45 | await waitForElementByText('Finish recording');
46 | await element(by.text('Finish recording')).tap();
47 | await element(by.text('Submit video')).tap();
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/android/src/test/java/com/onfido/reactnative/sdk/ResponseTest.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import com.onfido.reactnative.sdk.Response.ProofOfAddress;
4 | import com.onfido.reactnative.sdk.Response.ProofOfAddress.ProofOfAddressSide;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertNull;
8 | import org.junit.Test;
9 |
10 | public class ResponseTest {
11 |
12 | @Test
13 | public void shouldCreateResponse() throws Exception {
14 | String frontId = "frontId1";
15 | String backId = "backId2";
16 | String faceId = "faceId3";
17 | String faceVariant = "faceVariant4";
18 | String nfcMediaUUID = "docNfcMediaId123";
19 | ProofOfAddress poa = new ProofOfAddress("type", new ProofOfAddressSide("id1", "type1"), new ProofOfAddressSide("id2", "type2"));
20 | Response testResponse = new Response(frontId, backId, faceId, faceVariant, nfcMediaUUID, poa);
21 | assertEquals(frontId, testResponse.document.front.id);
22 | assertEquals(backId, testResponse.document.back.id);
23 | assertEquals(faceId, testResponse.face.id);
24 | assertEquals(faceVariant, testResponse.face.variant);
25 | }
26 |
27 | @Test
28 | public void shouldCreateResponseDocFrontOnly() throws Exception {
29 | String frontId = "frontId1";
30 | ProofOfAddress poa = new ProofOfAddress("type", new ProofOfAddressSide("id1", "type1"), new ProofOfAddressSide("id2", "type2"));
31 | Response testResponse = new Response(frontId, null, null, null, null, poa);
32 | assertEquals(frontId, testResponse.document.front.id);
33 | assertNull(testResponse.document.back);
34 | assertNull(testResponse.face);
35 | assertEquals(poa, testResponse.proofOfAddress);
36 | }
37 |
38 | @Test
39 | public void shouldCreateResponseFaceOnly() throws Exception {
40 | String faceId = "faceId3";
41 | String faceVariant = "faceVariant4";
42 | ProofOfAddress poa = new ProofOfAddress("type", new ProofOfAddressSide("id", "type"), null);
43 | Response testResponse = new Response(null, null, faceId, faceVariant, null, poa);
44 | assertNull(testResponse.document);
45 | assertEquals(faceId, testResponse.face.id);
46 | assertEquals(faceVariant, testResponse.face.variant);
47 | assertEquals(poa, testResponse.proofOfAddress);
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/scripts/update_colors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This script adds the values from colors.json to a colors.xml resource for android
3 | *
4 | * Note: This script was written to work with ES5
5 | */
6 | const fs = require('fs');
7 | try {
8 | if (fs.existsSync('../../../colors.json')) {
9 | fs.readFile('../../../colors.json', 'utf8', function (err, data) {
10 | let colors = JSON.parse(data)
11 |
12 | // Explictly check and create needed directories to support older js versions
13 | if (!fs.existsSync('android')) {
14 | fs.mkdirSync('android')
15 | }
16 | if (!fs.existsSync('android/src')) {
17 | fs.mkdirSync('android/src')
18 | }
19 | if (!fs.existsSync('android/src/main')) {
20 | fs.mkdirSync('android/src/main')
21 | }
22 | if (!fs.existsSync('android/src/main/res')) {
23 | fs.mkdirSync('android/src/main/res')
24 | }
25 | if (!fs.existsSync('android/src/main/res/values')) {
26 | fs.mkdirSync('android/src/main/res/values')
27 | }
28 |
29 | fs.writeFile('android/src/main/res/values/colors.xml', generateFileContent(colors), function (e) {
30 | if (e != null) {
31 | console.log('\nAn error occured while trying to update colors:\n' + e + '\n')
32 | } else {
33 | console.log("\nColors were successfully updated\n")
34 | }
35 | })
36 | });
37 | } else {
38 | console.log('\nNo colors.json was found. Ensure it is at the same level as your node-modules directory\n')
39 | }
40 | } catch (e) {
41 | console.log(e)
42 | }
43 |
44 | function generateFileContent(colors) {
45 | let fileContent = '\n'
46 | fileContent += '\n'
47 | Object.keys(colors).forEach((color) => {
48 | let keyName = color;
49 | switch (keyName) {
50 | case 'onfidoPrimaryColor':
51 | keyName = 'onfidoPrimaryButtonColor'
52 | break
53 | case 'onfidoAndroidStatusBarColor':
54 | keyName = 'onfidoColorPrimary'
55 | break
56 | case 'onfidoAndroidToolBarColor':
57 | keyName = 'onfidoColorPrimaryDark'
58 | break
59 | }
60 |
61 | if (color !== 'onfidoIosSupportDarkMode') {
62 | fileContent += '\t"
65 | fileContent += colors[color]
66 | fileContent += "\n"
67 | }
68 | })
69 | fileContent += ""
70 | return fileContent
71 | }
72 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | SampleApp
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSAllowsArbitraryLoads
30 |
31 | NSExceptionDomains
32 |
33 | localhost
34 |
35 | NSExceptionAllowsInsecureHTTPLoads
36 |
37 |
38 |
39 |
40 | NSCameraUsageDescription
41 | Required for document and facial capture
42 | NSLocationWhenInUseUsageDescription
43 |
44 | NSMicrophoneUsageDescription
45 | Required for video capture
46 | UILaunchStoryboardName
47 | LaunchScreen
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UIViewControllerBasedStatusBarAppearance
59 |
60 | NFCReaderUsageDescription
61 | Required to read ePassports
62 | com.apple.developer.nfc.readersession.felica.systemcodes
63 |
64 | 12FC
65 |
66 | com.apple.developer.nfc.readersession.iso7816.select-identifiers
67 |
68 | A0000002471001
69 | A0000002472001
70 | 00000000000000
71 | D2760000850101
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/SampleApp/android/app/src/main/java/com/sampleapp/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.sampleapp;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.soloader.SoLoader;
10 | import java.lang.reflect.InvocationTargetException;
11 | import java.util.List;
12 |
13 | public class MainApplication extends Application implements ReactApplication {
14 |
15 | private final ReactNativeHost mReactNativeHost =
16 | new ReactNativeHost(this) {
17 | @Override
18 | public boolean getUseDeveloperSupport() {
19 | return BuildConfig.DEBUG;
20 | }
21 |
22 | @Override
23 | protected List getPackages() {
24 | @SuppressWarnings("UnnecessaryLocalVariable")
25 | List packages = new PackageList(this).getPackages();
26 | // Packages that cannot be autolinked yet can be added manually here, for example:
27 | // packages.add(new MyReactNativePackage());
28 | return packages;
29 | }
30 |
31 | @Override
32 | protected String getJSMainModuleName() {
33 | return "index";
34 | }
35 | };
36 |
37 | @Override
38 | public ReactNativeHost getReactNativeHost() {
39 | return mReactNativeHost;
40 | }
41 |
42 | @Override
43 | public void onCreate() {
44 | super.onCreate();
45 | SoLoader.init(this, /* native exopackage */ false);
46 | initializeFlipper(this); // Remove this line if you don't want Flipper enabled
47 | }
48 |
49 | /**
50 | * Loads Flipper in React Native templates.
51 | *
52 | * @param context
53 | */
54 | private static void initializeFlipper(Context context) {
55 | if (BuildConfig.DEBUG) {
56 | try {
57 | /*
58 | We use reflection here to pick up the class that initializes Flipper,
59 | since Flipper library is not available in release mode
60 | */
61 | Class> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
62 | aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
63 | } catch (ClassNotFoundException e) {
64 | e.printStackTrace();
65 | } catch (NoSuchMethodException e) {
66 | e.printStackTrace();
67 | } catch (IllegalAccessException e) {
68 | e.printStackTrace();
69 | } catch (InvocationTargetException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ios/CallbackReceiver.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CallbackReceiver.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Onfido
8 | import Foundation
9 |
10 | final class CallbackReceiver {
11 | private let onMediaCallback: (([String: Any]) -> Void)?
12 |
13 | init(withCallback callback: (([String: Any]) -> Void)?) {
14 | onMediaCallback = callback
15 | }
16 | }
17 |
18 | extension CallbackReceiver: MediaCallback {
19 | func onMediaCaptured(result: MediaResult) {
20 | var dictionary: [String: Any] = [:]
21 |
22 | switch result {
23 | case let documentResult as MediaDocumentResult:
24 | dictionary[Keys.MediaCallback.captureType] = Keys.CaptureType.document
25 | dictionary[Keys.MediaCallback.documentSide] = documentResult.metadata.side
26 | dictionary[Keys.MediaCallback.documentType] = documentResult.metadata.type
27 | dictionary[Keys.MediaCallback.documentIssuingCountry] = documentResult.metadata.issuingCountry ?? ""
28 | send(dictionary: dictionary, mediaFile: documentResult.file)
29 |
30 | case let livenessReult as LivenessResult:
31 | dictionary[Keys.MediaCallback.captureType] = Keys.CaptureType.video
32 | send(dictionary: dictionary, mediaFile: livenessReult.file)
33 |
34 | case let selfieResult as SelfieResult:
35 | dictionary[Keys.MediaCallback.captureType] = Keys.CaptureType.face
36 | send(dictionary: dictionary, mediaFile: selfieResult.file)
37 |
38 | default:
39 | return
40 | }
41 | }
42 |
43 | private func send(dictionary: [String: Any], mediaFile file: MediaFile) {
44 | let fileData = getArrayOfBytesFromImage(data: file.fileData as NSData).description
45 |
46 | var newDict = dictionary
47 | newDict[Keys.MediaCallback.fileName] = file.fileName
48 | newDict[Keys.MediaCallback.fileData] = fileData
49 | newDict[Keys.MediaCallback.fileType] = file.fileType
50 |
51 | guard let onMediaCallback = onMediaCallback else {
52 | assertionFailure("No onMediaCallback registered")
53 | return
54 | }
55 | onMediaCallback(newDict)
56 | }
57 |
58 | // TODO: Temporary. Removed when introducing breaking change to return Base64 encoded string.
59 | // https://stackoverflow.com/a/65265130
60 | private func getArrayOfBytesFromImage(data: NSData) -> Array {
61 | let count = data.length / MemoryLayout.size
62 | var bytes = [Int8](repeating: 0, count: count)
63 | data.getBytes(&bytes, length:count * MemoryLayout.size)
64 |
65 | var byteArray:Array = Array()
66 | for i in 0 ..< count {
67 | byteArray.append(bytes[i])
68 | }
69 | return byteArray
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/ios/OnfidoPluginConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoPluginConfig.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Foundation
8 |
9 | struct OnfidoPluginConfig: Codable {
10 | let sdkToken: String
11 | let workflowRunId: String?
12 | let flowSteps: OnfidoFlowSteps?
13 | let localisation: OnfidoLocalisation?
14 | let theme: Theme?
15 | let hideLogo: Bool?
16 | let logoCoBrand: Bool?
17 | let disableNFC: Bool?
18 | let nfcOption: OnfidoNFCOptions?
19 | let disableMobileSdkAnalytics: Bool?
20 | }
21 |
22 | struct OnfidoFlowSteps: Codable {
23 | var welcome: Bool?
24 | var proofOfAddress: Bool?
25 | var captureDocument: OnfidoCaptureDocument?
26 | var captureFace: OnfidoCaptureFace?
27 | }
28 |
29 | struct OnfidoCaptureDocument: Codable {
30 | let countryCode: String?
31 | let alpha2CountryCode: String?
32 | let docType: OnfidoDocumentType?
33 | let allowedDocumentTypes: [OnfidoDocumentType]?
34 | let pages: OnfidoDocumentPages?
35 | let title: String?
36 | }
37 |
38 | struct OnfidoCaptureFace: Codable {
39 | let type: OnfidoCaptureType
40 | let recordAudio: Bool?
41 | let showIntro: Bool?
42 | let manualVideoCapture: Bool?
43 | }
44 |
45 | struct OnfidoLocalisation: Codable {
46 | let stringsFileName: String?
47 |
48 | enum CodingKeys: String, CodingKey {
49 | case stringsFileName = "ios_strings_file_name"
50 | }
51 | }
52 |
53 | enum Theme: String, Codable {
54 | case dark = "DARK"
55 | case light = "LIGHT"
56 | case automatic = "AUTOMATIC"
57 | }
58 |
59 | enum OnfidoDocumentType: String, Codable {
60 | case passport = "PASSPORT"
61 | case drivingLicence = "DRIVING_LICENCE"
62 | case nationalIdentityCard = "NATIONAL_IDENTITY_CARD"
63 | case residencePermit = "RESIDENCE_PERMIT"
64 | case visa = "VISA"
65 | case workPermit = "WORK_PERMIT"
66 | case generic = "GENERIC"
67 | }
68 |
69 | enum OnfidoDocumentPages: String, Codable {
70 | case single = "SINGLE"
71 | case frontAndBack = "FRONT_AND_BACK"
72 | }
73 |
74 | enum OnfidoCaptureType: String, Codable {
75 | case photo = "PHOTO"
76 | case video = "VIDEO"
77 | case motion = "MOTION"
78 | }
79 |
80 | enum OnfidoNFCOptions: String, Codable {
81 | case disabled = "DISABLED"
82 | case optional = "OPTIONAL"
83 | case required = "REQUIRED"
84 | }
85 |
86 | struct OnfidoAppearanceConfig: Codable {
87 | let primaryColorHex: String?
88 | let primaryButtonTextColorHex: String?
89 | let primaryButtonColorPressedHex: String?
90 |
91 | enum CodingKeys: String, CodingKey {
92 | case primaryColorHex = "onfidoPrimaryColor"
93 | case primaryButtonTextColorHex = "onfidoPrimaryButtonTextColor"
94 | case primaryButtonColorPressedHex = "onfidoPrimaryButtonColorPressed"
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@onfido/react-native-sdk",
3 | "title": "React Native Onfido Sdk",
4 | "version": "15.3.0",
5 | "description": "Onfido React Native SDK",
6 | "main": "index.ts",
7 | "scripts": {
8 | "lint": "echo \"Skipping SDK linting...\"",
9 | "test": "echo \"RN SDK testing...\"; jest --coverage",
10 | "updateGradleMultiDex": "node scripts/android_enable_multi_dex.js",
11 | "updateGradleMavenLink": "node scripts/android_add_maven_link.js",
12 | "updateBuildGradle": "npm run updateGradleMultiDex && npm run updateGradleMavenLink",
13 | "updateColors": "node scripts/update_colors.js",
14 | "updateOnfido": "npm run updateBuildGradle && npm run updateColors",
15 | "iOSTest": "cd ios && xcodebuild test-without-building -workspace \"OnfidoSdk.xcworkspace\" -scheme \"OnfidoSdkTests\" -destination \"platform=iOS Simulator,name=iPhone 8,OS=13.3\" -only-testing:OnfidoSdkTests"
16 | },
17 | "publishConfig": {
18 | "access": "public"
19 | },
20 | "jest": {
21 | "preset": "react-native",
22 | "transformIgnorePatterns": [
23 | "/node_modules/(?!(@react-native|react-native)/).*/"
24 | ],
25 | "testPathIgnorePatterns": [
26 | "/TestApp",
27 | "/SampleApp"
28 | ],
29 | "globals": {
30 | "__DEV__": true
31 | },
32 | "moduleFileExtensions": [
33 | "js",
34 | "json",
35 | "jsx",
36 | "ts",
37 | "tsx",
38 | "node",
39 | "android.js",
40 | "ios.js"
41 | ]
42 | },
43 | "repository": {
44 | "type": "git",
45 | "url": "git+https://github.com/onfido/react-native-sdk.git",
46 | "baseUrl": "https://github.com/onfido/react-native-sdk"
47 | },
48 | "keywords": [
49 | "react-native",
50 | "onfido",
51 | "sdk",
52 | "document",
53 | "capture",
54 | "identity",
55 | "verification"
56 | ],
57 | "author": {
58 | "name": "SDK Customer Support",
59 | "email": "react-native-sdk@onfido.com",
60 | "url": "https://github.com/onfido"
61 | },
62 | "license": "MIT",
63 | "licenseFilename": "LICENSE",
64 | "readmeFilename": "README.md",
65 | "peerDependencies": {
66 | "react": ">=17.0.0",
67 | "react-native": ">=0.70.0 <1.0.x"
68 | },
69 | "devDependencies": {
70 | "@babel/cli": "^7.10.5",
71 | "@babel/core": "^7.20.0",
72 | "@babel/preset-env": "^7.20.0",
73 | "@react-native-community/cli-platform-android": "^6.3.0",
74 | "@react-native/metro-config": "^0.73.5",
75 | "@types/react-native": "^0.72.1",
76 | "babel-jest": "^29.6.3",
77 | "babel-preset-react-native": "^5.0.0",
78 | "husky": "^8.0.3",
79 | "jest": "^29.6.3",
80 | "metro-react-native-babel-preset": "^0.77.0",
81 | "react": "18.2.0",
82 | "react-native": "0.73.8",
83 | "typescript": "^5.0.4"
84 | },
85 | "dependencies": {
86 | "js-base64": "3.7.5"
87 | },
88 | "engines": {
89 | "node": ">=18"
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/android/src/main/java/com/onfido/reactnative/sdk/Response.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import javax.annotation.Nullable;
4 |
5 | /**
6 | * The response object represents the results of a successful execution of the Onfido SDK.
7 | */
8 | class Response {
9 | public class Identifiable {
10 | public Identifiable(String id) {
11 | this.id = id;
12 | }
13 | public String id = "default";
14 | }
15 | public class Document {
16 | public Identifiable front;
17 | public Identifiable back;
18 | public Identifiable nfcMediaId;
19 | public Identifiable typeSelected;
20 | @Nullable public Identifiable countrySelected;
21 |
22 | }
23 | public class Face extends Response.Identifiable {
24 | public Face(String id, String variant) {
25 | super(id);
26 | this.variant = variant;
27 | }
28 | public String variant;
29 | }
30 | public static class ProofOfAddress {
31 | public String type;
32 | public ProofOfAddressSide front;
33 | @Nullable public ProofOfAddressSide back;
34 |
35 | public ProofOfAddress(String type, ProofOfAddressSide front, @Nullable ProofOfAddressSide back) {
36 | this.type = type;
37 | this.front = front;
38 | this.back = back;
39 | }
40 | public static class ProofOfAddressSide {
41 | public String id;
42 | @Nullable public String type;
43 |
44 | public ProofOfAddressSide(String id, @Nullable String type) {
45 | this.id = id;
46 | this.type = type;
47 | }
48 | }
49 | }
50 |
51 | public Document document;
52 | public Face face;
53 | public ProofOfAddress proofOfAddress;
54 |
55 | public Response(String frontId, String backId, String faceId, String faceVariant, String nfcMediaUUID, ProofOfAddress proofOfAddress) {
56 | initDocument(frontId, backId, nfcMediaUUID);
57 | initFace(faceId, faceVariant);
58 | this.proofOfAddress = proofOfAddress;
59 | }
60 |
61 | private void initDocument(String frontId, String backId, String nfcMediaUUID) {
62 | if (frontId != null || backId != null || nfcMediaUUID != null) {
63 | document = new Document();
64 | if (frontId != null) {
65 | document.front = new Identifiable(frontId);
66 | }
67 | if (backId != null) {
68 | document.back = new Identifiable(backId);
69 | }
70 | if (nfcMediaUUID != null) {
71 | document.nfcMediaId = new Identifiable(nfcMediaUUID);
72 | }
73 | }
74 | }
75 |
76 | private void initFace(String faceId, String faceVariant) {
77 | if (faceId != null || faceVariant != null) {
78 | face = new Face(faceId, faceVariant);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Resolve react_native_pods.rb with node to allow for hoisting
2 | require Pod::Executable.execute_command('node', ['-p',
3 | 'require.resolve(
4 | "react-native/scripts/react_native_pods.rb",
5 | {paths: [process.argv[1]]},
6 | )', __dir__]).strip
7 |
8 | platform :ios, '13.4'
9 | prepare_react_native_project!
10 |
11 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
12 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
13 | #
14 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
15 | # ```js
16 | # module.exports = {
17 | # dependencies: {
18 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
19 | # ```
20 |
21 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
22 |
23 | # Enable concurrent installation and disable input/output paths for CI consistency
24 | install! 'cocoapods',
25 | warn_for_multiple_pod_sources: false,
26 | deterministic_uuids: false,
27 | disable_input_output_paths: true
28 |
29 | target 'OnfidoSdk' do
30 | pod 'Onfido', '~> 32.6.0'
31 |
32 | config = use_native_modules!
33 | use_react_native!(
34 | :path => config[:reactNativePath],
35 | # to enable hermes on iOS, change `false` to `true` and then install pods
36 | :hermes_enabled => false
37 | #:hermes_enabled => flags[:hermes_enabled],
38 | #:fabric_enabled => flags[:fabric_enabled],
39 | )
40 |
41 | target 'OnfidoSdkTests' do
42 | # inherit! :search_paths
43 | # Pods for testing
44 | end
45 |
46 | # unary_function and binary_function are no longer provided in C++17 and newer standard modes as part of Xcode 15.
47 | # They can be re-enabled with setting _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION
48 | # Ref: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Deprecations
49 | # Solution: https://github.com/facebook/react-native/issues/37748#issuecomment-1580589448
50 |
51 | # Workarounds and settings for Xcode 15 and Folly coroutines
52 | post_install do |installer|
53 | installer.pods_project.targets.each do |target|
54 | target.build_configurations.each do |config|
55 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', '_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION']
56 | end
57 | end
58 |
59 | # Workaround for `FOLLY_HAS_COROUTINES` set to `1` on CI causing attempt to import non-existent `Coroutine.h`
60 | system("chmod -R u+w Pods/RCT-Folly")
61 | Dir.glob("Pods/RCT-Folly/folly/Portability.h").each do |file|
62 | text = File.read(file)
63 | new_contents = text.gsub('#define FOLLY_HAS_COROUTINES 1', '#define FOLLY_HAS_COROUTINES 0')
64 | File.open(file, "w") { |file| file.puts new_contents }
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # As we're using yarn, not npm
2 | package-lock.json
3 |
4 | # OSX
5 | .DS_Store
6 |
7 | # Android and XCode
8 | build/
9 |
10 | # Xcode
11 | #
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata
21 | *.xccheckout
22 | *.moved-aside
23 | DerivedData
24 | *.hmap
25 | *.ipa
26 | *.xcuserstate
27 | project.xcworkspace
28 | # Root dir shouldn't have Xcode project
29 | /*.xcodeproj
30 |
31 | # Android/IntelliJ
32 | #
33 | .idea
34 | .gradle
35 | local.properties
36 | *.iml
37 | android/bin/
38 |
39 | # Android/Eclipse
40 | #
41 | **/.project
42 | **/org.eclipse.buildship.core.prefs
43 |
44 | # Android
45 | #
46 | **/android/.classpath
47 | **/android/app/.classpath
48 |
49 | # node.js
50 | #
51 | node_modules/
52 | SampleApp/.yalc/
53 | SampleApp/.yalc.lock
54 | TestApp/.yalc/
55 | TestApp/.yalc.lock
56 |
57 | # Built application files
58 | #
59 | *.apk
60 | *.aar
61 | *.ap_
62 | *.aab
63 |
64 | # Files for the ART/Dalvik VM
65 | #
66 | *.dex
67 |
68 | # Java class files
69 | #
70 | *.class
71 |
72 | # Generated files
73 | #
74 | bin/
75 | gen/
76 | out/
77 |
78 | # Proguard folder generated by Eclipse
79 | #
80 | proguard/
81 |
82 | # Watchman
83 | #
84 | .watchmanconfig
85 |
86 | # Log Files
87 | #
88 | *.log
89 |
90 | # Android Studio Navigation editor temp files
91 | #
92 | .navigation/
93 |
94 | # Android Studio captures folder
95 | #
96 | captures/
97 |
98 | # Keystore files
99 | #
100 | *.jks
101 | *.keystore
102 |
103 | # External native build folder generated in Android Studio 2.2 and later
104 | #
105 | .externalNativeBuild
106 | .cxx/
107 |
108 | # Freeline
109 | #
110 | freeline.py
111 | freeline/
112 | freeline_project_description.json
113 |
114 |
115 | # Version control
116 | #
117 | vcs.xml
118 |
119 | # lint
120 | #
121 | lint/intermediates/
122 | lint/generated/
123 | lint/outputs/
124 | lint/tmp/
125 |
126 | # Visual Studio Code
127 | #
128 | .vscode
129 | .vs
130 |
131 | # fastlane
132 | #
133 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
134 | # screenshots whenever they are needed.
135 | # For more information about the recommended setup visit:
136 | # https://docs.fastlane.tools/best-practices/source-control/
137 | */fastlane/report.xml
138 | */fastlane/Preview.html
139 | */fastlane/screenshots
140 | */fastlane/test_output
141 | */fastlane/readme.md
142 |
143 | # Bundle artifact
144 | #
145 | *.jsbundle
146 |
147 | # CocoaPods
148 | #
149 | /ios/Pods/
150 |
151 | # Directory for ignored files
152 | #
153 | gitignored/
154 |
155 | # Jest
156 | #
157 | coverage
158 |
159 | # Temporary files created by Metro to check the health of the file watcher
160 | .metro-health-check*
161 |
162 | # testing
163 | /coverage
164 | TestApp/.env
165 | TestApp/ios/Podfile.lock
166 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk.xcodeproj/xcshareddata/xcschemes/OnfidoSdk.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/SampleApp/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.7)
5 | base64
6 | nkf
7 | rexml
8 | activesupport (7.2.1.2)
9 | base64
10 | bigdecimal
11 | concurrent-ruby (~> 1.0, >= 1.3.1)
12 | connection_pool (>= 2.2.5)
13 | drb
14 | i18n (>= 1.6, < 2)
15 | logger (>= 1.4.2)
16 | minitest (>= 5.1)
17 | securerandom (>= 0.3)
18 | tzinfo (~> 2.0, >= 2.0.5)
19 | addressable (2.8.7)
20 | public_suffix (>= 2.0.2, < 7.0)
21 | algoliasearch (1.27.5)
22 | httpclient (~> 2.8, >= 2.8.3)
23 | json (>= 1.5.1)
24 | atomos (0.1.3)
25 | base64 (0.2.0)
26 | bigdecimal (3.1.8)
27 | claide (1.1.0)
28 | cocoapods (1.16.1)
29 | addressable (~> 2.8)
30 | claide (>= 1.0.2, < 2.0)
31 | cocoapods-core (= 1.16.1)
32 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
33 | cocoapods-downloader (>= 2.1, < 3.0)
34 | cocoapods-plugins (>= 1.0.0, < 2.0)
35 | cocoapods-search (>= 1.0.0, < 2.0)
36 | cocoapods-trunk (>= 1.6.0, < 2.0)
37 | cocoapods-try (>= 1.1.0, < 2.0)
38 | colored2 (~> 3.1)
39 | escape (~> 0.0.4)
40 | fourflusher (>= 2.3.0, < 3.0)
41 | gh_inspector (~> 1.0)
42 | molinillo (~> 0.8.0)
43 | nap (~> 1.0)
44 | ruby-macho (>= 2.3.0, < 3.0)
45 | xcodeproj (>= 1.26.0, < 2.0)
46 | cocoapods-core (1.16.1)
47 | activesupport (>= 5.0, < 8)
48 | addressable (~> 2.8)
49 | algoliasearch (~> 1.0)
50 | concurrent-ruby (~> 1.1)
51 | fuzzy_match (~> 2.0.4)
52 | nap (~> 1.0)
53 | netrc (~> 0.11)
54 | public_suffix (~> 4.0)
55 | typhoeus (~> 1.0)
56 | cocoapods-deintegrate (1.0.5)
57 | cocoapods-downloader (2.1)
58 | cocoapods-plugins (1.0.0)
59 | nap
60 | cocoapods-search (1.0.1)
61 | cocoapods-trunk (1.6.0)
62 | nap (>= 0.8, < 2.0)
63 | netrc (~> 0.11)
64 | cocoapods-try (1.2.0)
65 | colored2 (3.1.2)
66 | concurrent-ruby (1.3.4)
67 | connection_pool (2.4.1)
68 | drb (2.2.1)
69 | escape (0.0.4)
70 | ethon (0.16.0)
71 | ffi (>= 1.15.0)
72 | ffi (1.17.0-arm64-darwin)
73 | ffi (1.17.0-x86_64-darwin)
74 | fourflusher (2.3.1)
75 | fuzzy_match (2.0.4)
76 | gh_inspector (1.1.3)
77 | httpclient (2.8.3)
78 | i18n (1.14.6)
79 | concurrent-ruby (~> 1.0)
80 | json (2.7.4)
81 | logger (1.6.1)
82 | minitest (5.25.1)
83 | molinillo (0.8.0)
84 | nanaimo (0.4.0)
85 | nap (1.1.0)
86 | netrc (0.11.0)
87 | nkf (0.2.0)
88 | public_suffix (4.0.7)
89 | rexml (3.3.9)
90 | ruby-macho (2.5.1)
91 | securerandom (0.3.1)
92 | typhoeus (1.4.1)
93 | ethon (>= 0.9.0)
94 | tzinfo (2.0.6)
95 | concurrent-ruby (~> 1.0)
96 | xcodeproj (1.26.0)
97 | CFPropertyList (>= 2.3.3, < 4.0)
98 | atomos (~> 0.1.3)
99 | claide (>= 1.0.2, < 2.0)
100 | colored2 (~> 3.1)
101 | nanaimo (~> 0.4.0)
102 | rexml (>= 3.3.6, < 4.0)
103 |
104 | PLATFORMS
105 | arm64-darwin-22
106 | arm64-darwin-23
107 | x86_64-darwin-21
108 |
109 | DEPENDENCIES
110 | cocoapods (= 1.16.1)
111 |
112 | RUBY VERSION
113 | ruby 3.1.1p18
114 |
115 | BUNDLED WITH
116 | 2.4.19
117 |
--------------------------------------------------------------------------------
/SampleApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SampleApp",
3 | "version": "0.0.1",
4 | "private": true,
5 | "license": "MIT",
6 | "scripts": {
7 | "create-avd": "avdmanager create avd -n Pixel_API_28_AOSP -k \"system-images;android-28;google_play;x86\" --device \"Nexus 5X\"",
8 | "delete-avd": "avdmanager delete avd -n Pixel_API_28_AOSP",
9 | "list-avd": "avdmanager list avd",
10 | "android": "react-native run-android",
11 | "ios": "react-native run-ios",
12 | "start": "react-native start",
13 | "test": "echo \"SampleApp testing...\"; jest --coverage",
14 | "lint": "echo \"SampleApp linting...\"; eslint .",
15 | "preinstall": "(cd ../ && npx yalc publish) && npx yalc add @onfido/react-native-sdk",
16 | "postinstall": "node scripts/examples_postinstall.js && rm -rf node_modules/@onfido/react-native-sdk/node_modules",
17 | "start-e2e-android-sampleapp": "export $(./scripts/get_env.sh e2eAndroid | xargs) && npx react-native start",
18 | "test-e2e-android-debug-sampleapp": "detox build -c android.emu.debug.sampleapp && detox test -c android.emu.debug.sampleapp -o e2eAndroid/config.json",
19 | "test-e2e-android-release-sampleapp": "detox build -c android.emu.release.sampleapp && detox test -c android.emu.release.sampleapp -o e2eAndroid/config.json",
20 | "refresh-native": "(cd ../ && npx yalc publish --push)",
21 | "refresh-ios": "yarn refresh-native && yarn ios",
22 | "clean-project": "./node_modules/.bin/react-native-clean-project"
23 | },
24 | "dependencies": {
25 | "@onfido/react-native-sdk": "file:.yalc/@onfido/react-native-sdk",
26 | "react": "18.2.0",
27 | "react-native": "0.73.8",
28 | "react-native-dotenv": "^0.2.0",
29 | "react-router-native": "^5.1.2"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.20.0",
33 | "@babel/preset-env": "^7.20.2",
34 | "@babel/runtime": "^7.20.0",
35 | "@react-native-community/cli-platform-android": "^6.3.0",
36 | "@react-native/eslint-config": "^0.73.2",
37 | "@react-native/metro-config": "^0.73.5",
38 | "@tsconfig/react-native": "^3.0.0",
39 | "@types/react": "^18.2.6",
40 | "@types/react-test-renderer": "^18.0.0",
41 | "babel-jest": "^29.6.3",
42 | "detox": "^19.7.1",
43 | "eslint": "^7.14.0",
44 | "eslint-plugin-detox": "^1.0.0",
45 | "jest": "^29.6.3",
46 | "metro-react-native-babel-preset": "^0.77.0",
47 | "react-native-clean-project": "^3.6.7",
48 | "react-test-renderer": "18.2.0"
49 | },
50 | "resolutions": {
51 | "**/**/lodash": "^4.17.17",
52 | "colors": "^1.4.0"
53 | },
54 | "detox": {
55 | "test-runner": "jest",
56 | "configurations": {
57 | "android.emu.debug.sampleapp": {
58 | "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
59 | "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
60 | "type": "android.emulator",
61 | "name": "emulator"
62 | },
63 | "android.emu.release.sampleapp": {
64 | "binaryPath": "android/app/build/outputs/apk/release/app-release-bitrise-signed.apk",
65 | "build": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
66 | "type": "android.emulator",
67 | "name": "emulator"
68 | }
69 | }
70 | },
71 | "engines": {
72 | "node": ">=18"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/SampleApp/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem http://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/ios/OnfidoSdkTests/ResponseTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseTest.swift
3 | // OnfidoSdkTests
4 | //
5 | // Created by Santana, Luis on 3/5/20.
6 | // Copyright © 2020 Onfido. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Onfido
11 | import XCTest
12 | @testable import OnfidoSdk
13 |
14 | struct TestDocumentSideResult: ReactDocumentSideResult {
15 | let id: String
16 | }
17 |
18 | struct TestDocumentResult: ReactDocumentResult {
19 | let reactFront: ReactDocumentSideResult
20 | let reactBack: ReactDocumentSideResult?
21 | var reactNfcMediaId: String?
22 | var reactTypeSelected: String
23 | var reactCountrySelected: String?
24 | }
25 |
26 | struct TestFaceResult: ReactFaceResult {
27 | let id: String
28 | let variant: FaceResultVariant
29 | }
30 |
31 | class ResponseTests: XCTestCase {
32 | func testResponseOfSingleSidedDocumentCheck() {
33 | let documentResult = TestDocumentResult(
34 | reactFront: TestDocumentSideResult(id: "single-side-test"),
35 | reactBack: nil,
36 | reactTypeSelected: "passport"
37 | )
38 |
39 | let response = createResponse(document: documentResult)
40 |
41 | let document = response["document"]!
42 | let front = document["front"] as! [String: String]
43 | XCTAssertEqual(front["id"], "single-side-test")
44 | XCTAssertNil(document["back"])
45 | XCTAssertNil(response["face"])
46 | }
47 |
48 | func testResponseOfDoubleSidedDocumentCheck() {
49 | let documentResult = TestDocumentResult(
50 | reactFront: TestDocumentSideResult(id: "double-side-test-1"),
51 | reactBack: TestDocumentSideResult(id: "double-side-test-2"),
52 | reactTypeSelected: "type"
53 | )
54 |
55 | let response = createResponse(document: documentResult)
56 |
57 | let document = response["document"]!
58 | let front = document["front"] as! [String: String]
59 | let back = document["back"] as! [String: String]
60 | XCTAssertEqual(front["id"], "double-side-test-1")
61 | XCTAssertEqual(back["id"], "double-side-test-2")
62 | XCTAssertNil(response["face"])
63 | }
64 |
65 | func testResponseOfDoubleSidedDocumentCheckWithNfcMediaId() {
66 | let documentResult = TestDocumentResult(
67 | reactFront: TestDocumentSideResult(id: "double-side-test-1"),
68 | reactBack: TestDocumentSideResult(id: "double-side-test-2"),
69 | reactNfcMediaId: "nfcMediaId",
70 | reactTypeSelected: "type"
71 | )
72 |
73 | let response = createResponse(document: documentResult)
74 |
75 | let document = response["document"]!
76 | let front = document["front"] as! [String: String]
77 | let back = document["back"] as! [String: String]
78 | let nfcMediaId = document["nfcMediaId"] as! [String: String]
79 | XCTAssertEqual(front["id"], "double-side-test-1")
80 | XCTAssertEqual(back["id"], "double-side-test-2")
81 | XCTAssertEqual(nfcMediaId["id"], "nfcMediaId")
82 | XCTAssertNil(response["face"])
83 | }
84 |
85 | func testResponseOfFaceCheck() {
86 | let faceResult = TestFaceResult(id: "face-test", variant: .photo)
87 |
88 | let response = createResponse(face: faceResult)
89 |
90 | let face = response["face"] as! [String: String]
91 | XCTAssertEqual(face["id"], "face-test")
92 | XCTAssertEqual(face["variant"], "PHOTO")
93 | XCTAssertNil(response["document"])
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/SampleApp/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Button, StyleSheet, Text, View, Platform} from 'react-native';
3 | import {Onfido, OnfidoCaptureType} from '@onfido/react-native-sdk';
4 | import {Redirect} from 'react-router-native';
5 | import createSdkToken from './backend-server-example';
6 |
7 | export default class App extends Component {
8 | state = {
9 | title: 'Welcome to Onfido React Native SDK!',
10 | subtitle: "To get started, press 'Launch'",
11 | status: 'Starting',
12 | message: '--',
13 | sdkToken: null,
14 | sdkFlowComplete: false,
15 | workflowRunId: null,
16 | };
17 |
18 | componentDidMount() {
19 | // In your app, you will need to gather the user's information beforehand for the sdk to work. Only first and last name are required.
20 | const propsMatch = this.props.match ? this.props.match : {params: {}};
21 | const {firstName, lastName} = propsMatch.params;
22 | // Your application id may be different on iOS and Android so you'll need to check which platform the code is running on first.
23 | const applicationId =
24 | Platform.OS === 'ios'
25 | ? 'org.reactjs.native.example.SampleApp'
26 | : 'com.sampleapp';
27 | const applicant = {
28 | first_name: !firstName || firstName.trim() === '' ? 'Jane' : firstName,
29 | last_name: !lastName || lastName.trim() === '' ? 'Doe' : lastName,
30 | };
31 | this.getSDKToken(applicant, applicationId);
32 | }
33 |
34 | getSDKToken = async (applicant, applicationId) => {
35 | const newState = await createSdkToken(applicant, applicationId);
36 | this.setState(newState);
37 | };
38 |
39 | startSDK = () => {
40 | Onfido.start({
41 | sdkToken: this.state.sdkToken,
42 | workflowRunId: this.state.workflowRunId,
43 | localisation: {
44 | ios_strings_file_name: 'Localizable',
45 | },
46 | flowSteps: {
47 | welcome: true,
48 | captureDocument: {},
49 | captureFace: {
50 | type: OnfidoCaptureType.VIDEO,
51 | },
52 | },
53 | })
54 | .then(response => {
55 | this.setState({
56 | status: 'resolved',
57 | message: JSON.stringify(response),
58 | sdkFlowComplete: true,
59 | });
60 | })
61 | .catch(error => {
62 | this.setState({
63 | status: 'rejected',
64 | message: error.code + ': ' + error.message,
65 | sdkFlowComplete: true,
66 | });
67 | });
68 | };
69 |
70 | render() {
71 | return (
72 |
73 |
74 | {this.state.title}
75 |
76 |
77 | {this.state.subtitle}
78 |
79 |
84 | );
85 | }
86 | }
87 |
88 | const styles = StyleSheet.create({
89 | container: {
90 | flex: 1,
91 | justifyContent: 'center',
92 | alignItems: 'center',
93 | backgroundColor: '#F5FCFF',
94 | },
95 | welcome: {
96 | fontSize: 20,
97 | textAlign: 'center',
98 | margin: 10,
99 | },
100 | instructions: {
101 | textAlign: 'center',
102 | color: '#333333',
103 | marginBottom: 10,
104 | },
105 | });
106 |
--------------------------------------------------------------------------------
/ios/OnfidoSdk.xcodeproj/xcshareddata/xcschemes/OnfidoSdkTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
64 |
70 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/SampleApp/ios/SampleApp/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/SampleApp/README.md:
--------------------------------------------------------------------------------
1 | # Sample App for @onfido/react-native-sdk
2 |
3 | ## Summary
4 |
5 | You can use this sample app to test the React Native SDK and get an idea of how to integrate with it.
6 |
7 | ## Install the required tools
8 |
9 | ### Install required Android tools
10 |
11 | Make sure you have installed:
12 | - node (https://nodejs.org/en/download/)
13 | - watchman (`brew install watchman`)
14 | - [JDK 8 or newer](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
15 | - [Android Studio](https://developer.android.com/studio/index.html), configured as specified in [the react-native guide for Android](https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment)
16 | - Open `AVD Manager` in `Android Studio`, Click `+ Add Device` and install `Marshmallow 23 x86_64` image.
17 |
18 | Set up your device:
19 | - To run on a physical device, [enable debugging, and plug it in](https://facebook.github.io/react-native/docs/running-on-device.html#1-enable-debugging-over-usb)
20 | - To run on an emulator, [ensure you have an AVD created](https://facebook.github.io/react-native/docs/getting-started.html#using-a-virtual-device), and running (or follow instructions below on how to use custom commands for managing AVDs)
21 |
22 | ### Install required iOS tools
23 |
24 | Make sure you have installed:
25 | - node (https://nodejs.org/en/download/)
26 | - Xcode 10+ (https://developer.apple.com/download/)
27 | - watchman (`brew install watchman`)
28 | - pods (`gem install cocoapods`)
29 |
30 | Set up your device:
31 | - Follow the [official documentation](https://facebook.github.io/react-native/docs/running-on-device) to setup and run app within a physical device
32 |
33 | ## Step 1: Setup
34 |
35 | ### Set up the API Token
36 | Before running the sample app you will need to open SampleApp/backend-server-example.js and replace 'YOUR_API_TOKEN_HERE' with your API token. You can use our [sandbox](https://documentation.onfido.com/#sandbox-testing) environment to test the integration, and you will find the API tokens inside your [Onfido Dashboard](https://onfido.com/dashboard/api/tokens). You can create API tokens inside your Onfido Dashboard as well.
37 |
38 | | :warning: Do not use your API token in your client code. This server code is only included here as an example. |
39 | | --- |
40 |
41 | ## Step 2: Build and run the sample app
42 | All commands should start in the `SampleApp/` directory:
43 | ```shell
44 | cd SampleApp
45 | ```
46 |
47 | In one console, run the following to install the necessary packages, run the build, and start the server. It may take 2 or more minutes to build.
48 | ```shell
49 | yarn && cd ios && pod install && cd .. && watchman watch-del-all && npx react-native start --reset-cache
50 | ```
51 |
52 | Open a second console. Launch the iOS app:
53 | ```shell
54 | npx react-native run-ios
55 | ```
56 |
57 | Launch the Android app:
58 | ```shell
59 | npx react-native run-android
60 | ```
61 |
62 | # Testing the code
63 |
64 | ## Unit
65 |
66 | `yarn test` will kick off the unit tests.
67 |
68 | ## End-to-end
69 |
70 | We have end-to-end tests that run through the app on emulator.
71 |
72 | ### Android
73 |
74 | Create an emulator (naming **"Detox_Emulator"** is important):
75 |
76 | yarn create-avd -n Detox_Emulator
77 |
78 | In one terminal window compile the code for end-to-end testing:
79 |
80 | yarn start-e2e-android-sampleapp
81 |
82 | In another boot the Android emulator & automated tests:
83 |
84 | yarn test-e2e-android-debug-sampleapp
85 |
86 |
87 | ## Set up custom colors
88 | You can change the colors in SampleApp/colors.json if you wish to customize the sample app but, this is not required.
89 |
90 | After changing the colors, run the following to apply your changes to your Android build:
91 | ```shell
92 | cd SampleApp
93 | yarn
94 | npm --prefix node_modules/@onfido/react-native-sdk/ run updateColors
95 | ```
--------------------------------------------------------------------------------
/ios/OnfidoResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnfidoResponse.swift
3 | //
4 | // Copyright © 2016-2025 Onfido. All rights reserved.
5 | //
6 |
7 | import Foundation
8 | import Onfido
9 |
10 | // 📝 Protocols are for testing purposes since SDK types are final
11 | protocol ReactDocumentSideResult {
12 | var id: String { get }
13 | }
14 | protocol ReactDocumentResult {
15 | var reactFront: ReactDocumentSideResult { get }
16 | var reactBack: ReactDocumentSideResult? { get }
17 | var reactTypeSelected: String { get }
18 | var reactCountrySelected: String? { get }
19 | var reactNfcMediaId: String? { get }
20 | }
21 |
22 | protocol ReactFaceResult {
23 | var id: String { get }
24 | var variant: FaceResultVariant { get }
25 | }
26 |
27 | protocol ReactProofOfAddressResult {
28 | var reactFront: ReactProofOfAddressSideResult { get }
29 | var reactBack: ReactProofOfAddressSideResult? { get }
30 | var reactType: String { get }
31 | }
32 |
33 | protocol ReactProofOfAddressSideResult {
34 | var id: String { get }
35 | var type: String? { get }
36 | }
37 |
38 | extension DocumentSideResult: ReactDocumentSideResult {}
39 | extension DocumentResult: ReactDocumentResult {
40 | var reactFront: ReactDocumentSideResult { front }
41 | var reactBack: ReactDocumentSideResult? { back }
42 | var reactTypeSelected: String { typeSelected }
43 | var reactCountrySelected: String? { countrySelected }
44 | var reactNfcMediaId: String? { nfcMediaId }
45 | }
46 |
47 | extension FaceResult: ReactFaceResult {}
48 |
49 | extension ProofOfAddressSideResult: ReactProofOfAddressSideResult {}
50 | extension ProofOfAddressResult: ReactProofOfAddressResult {
51 | var reactFront: ReactProofOfAddressSideResult { front }
52 | var reactBack: ReactProofOfAddressSideResult? { back }
53 | var reactType: String { type }
54 | }
55 |
56 | func createResponse(_ results: [OnfidoResult]) -> [String: [String: Any]] {
57 | let document: DocumentResult? = results.compactMap { result in
58 | guard case let .document(documentResult) = result else { return nil }
59 | return documentResult
60 | }.first
61 |
62 | let face: FaceResult? = results.compactMap { result in
63 | guard case let .face(faceResult) = result else { return nil }
64 | return faceResult
65 | }.first
66 |
67 | let poa: ProofOfAddressResult? = results.compactMap { result in
68 | guard case let .proofOfAddress(proofOfAddressResult) = result else { return nil }
69 | return proofOfAddressResult
70 | }.first
71 |
72 | return createResponse(document: document, face: face)
73 | }
74 |
75 | // TODO: Refactor to Encodable
76 | func createResponse(
77 | document: ReactDocumentResult? = nil,
78 | face: ReactFaceResult? = nil,
79 | proofOfAddress: ReactProofOfAddressResult? = nil
80 | ) -> [String: [String: Any]] {
81 | var response = [String: [String: Any]]()
82 |
83 | if let documentResponse = document {
84 | response["document"] = ["front": ["id": documentResponse.reactFront.id]]
85 | if let backId = documentResponse.reactBack?.id,
86 | backId != documentResponse.reactFront.id
87 | {
88 | response["document"]?["back"] = ["id": documentResponse.reactBack?.id]
89 | }
90 |
91 | if let nfcId = documentResponse.reactNfcMediaId
92 | {
93 | response["document"]?["nfcMediaId"] = ["id": nfcId]
94 | }
95 | }
96 |
97 | if let faceResponse = face {
98 | let faceVariant: String = {
99 | switch faceResponse.variant {
100 | case .photo:
101 | return "PHOTO"
102 | case .video:
103 | return "VIDEO"
104 | case .motion:
105 | return "MOTION"
106 | }
107 | }()
108 | response["face"] = ["id": faceResponse.id, "variant": faceVariant]
109 | }
110 |
111 | if let poaResponse = proofOfAddress {
112 | response["proofOfAddress"] = ["front": ["id": poaResponse.reactFront.id]]
113 |
114 | if let backId = poaResponse.reactBack?.id,
115 | backId != poaResponse.reactFront.id
116 | {
117 | response["proofOfAddress"]?["back"] = ["id": backId]
118 | }
119 | response["proofOfAddress"]?["type"] = poaResponse.reactType
120 | }
121 |
122 | return response
123 | }
124 |
--------------------------------------------------------------------------------
/MIGRATION.md:
--------------------------------------------------------------------------------
1 | # Onfido SDK Migration Guides
2 |
3 | The guides below are provided to ease the transition of existing applications using the Onfido React Native SDK from one version to another that introduces breaking API changes.
4 |
5 | If your migration involves upgrading across multiple SDK versions, be sure to read each individual guide in order to account for all relevant breaking changes.
6 |
7 | * [Onfido react native SDK 12.0.0 Migration Guide](#onfido-rn-sdk-900-migration-guide)
8 | * [Onfido react native SDK 9.0.0 Migration Guide](#onfido-rn-sdk-900-migration-guide)
9 |
10 | ## Onfido React Native SDK 12.0.0 Migration Guide
11 |
12 | ### Breaking API Changes
13 |
14 | - Motion is now supported on all devices. Motion capture fallback configuration has therefore been removed.
15 | - If you currently set a `motionCaptureFallback` for `captureFace`, then you should be aware that this configuration is no longer available, so you can safely remove it from your integration code.
16 |
17 | Before 12.0.0:
18 |
19 | ```
20 | config = {
21 | sdkToken: “EXAMPLE-TOKEN-123”,
22 | flowSteps: {
23 | welcome: true,
24 | ...
25 | captureFace: {
26 | type: OnfidoCaptureType.MOTION,
27 | motionCaptureFallback: {
28 | type: OnfidoCaptureType.PHOTO
29 | },
30 | },
31 | },
32 | }
33 | ```
34 |
35 | After 12.0.0:
36 |
37 | ```
38 | config = {
39 | sdkToken: “EXAMPLE-TOKEN-123”,
40 | flowSteps: {
41 | welcome: true,
42 | ...
43 | captureFace: {
44 | type: OnfidoCaptureType.MOTION
45 | },
46 | },
47 | }
48 | ```
49 |
50 | - The option to set the `bubbleErrorBackgroundColor` as part of the appearance configuration has been removed, as this configuration option is not longer available. If you are currently configuring `bubbleErrorBackgroundColor` as part of your `colors.json` file, you can now safely remove it.
51 |
52 | - The flag `supportDarkMode` on the appearance configuration has been removed. Use `userInterfaceStyle` instead to configure the same behaviour.
53 |
54 | Before 12.0.0:
55 |
56 | ```
57 | {
58 | "onfidoPrimaryColor": "#FF0000",
59 | "backgroundColor": {
60 | "light": "#FCFCFD",
61 | "dark": "#000000"
62 | },
63 | "supportDarkMode": true,
64 | ...
65 | }
66 | ```
67 |
68 | After 12.0.0:
69 |
70 | ```
71 | {
72 | "onfidoPrimaryColor": "#FF0000",
73 | "backgroundColor": {
74 | "light": "#FCFCFD",
75 | "dark": "#000000"
76 | },
77 | "userInterfaceStyle": "dark",
78 | ...
79 | }
80 | ```
81 |
82 | ## Onfido React Native SDK 9.0.0 Migration Guide
83 |
84 | ### Breaking API Changes
85 |
86 | - Extra customization was introduced to the Capture Face step (for more information, see our [readme file](https://github.com/onfido/react-native-sdk/blob/master/README.md#2-parameter-details)). A breaking change was introduced when defining the fallbacks for a Motion type face capture, you can see from the example below how to update.
87 |
88 | Before 9.0.0:
89 |
90 | ```
91 | config = {
92 | sdkToken: “EXAMPLE-TOKEN-123”,
93 | flowSteps: {
94 | welcome: true,
95 | ...
96 | captureFace: {
97 | type: OnfidoCaptureType.MOTION,
98 | options: VIDEO_CAPTURE_FALLBACK
99 | },
100 | },
101 | }
102 | ```
103 |
104 | After 9.0.0:
105 |
106 | ```
107 | config = {
108 | sdkToken: “EXAMPLE-TOKEN-123”,
109 | flowSteps: {
110 | welcome: true,
111 | ...
112 | captureFace: {
113 | type: OnfidoCaptureType.MOTION,
114 | motionCaptureFallback: {
115 | type: OnfidoCaptureType.PHOTO
116 | },
117 | },
118 | },
119 | }
120 | ```
121 |
122 | - In fact, `options` key was entirely removed from `captureFace`. `captureFace` can be one of the 3 following types:
123 |
124 | ```
125 | type OnfidoFaceSelfieCapture = {
126 | type: OnfidoCaptureType.PHOTO;
127 | showIntro?: boolean
128 | };
129 |
130 | type OnfidoFaceVideoCapture = {
131 | type: OnfidoCaptureType.VIDEO;
132 | showIntro?: boolean;
133 | showConfirmation?: boolean;
134 | manualVideoCapture?: boolean;
135 | };
136 |
137 | type OnfidoFaceMotionCapture = {
138 | type: OnfidoCaptureType.MOTION;
139 | recordAudio?: boolean;
140 | motionCaptureFallback?: OnfidoFaceSelfieCapture | OnfidoFaceVideoCapture;
141 | };
142 | ```
143 |
144 | - Near Field Communication (NFC) is now enabled by default and offered to customers when both the document and the device support NFC. To disable NFC, please refer to our [NFC reference guide](https://documentation.onfido.com/guide/document-report-nfc#react-native-1).
145 |
--------------------------------------------------------------------------------
/SampleApp/backend-server-example.js:
--------------------------------------------------------------------------------
1 | /**
2 | * BEGIN BACKEND SERVER CODE EXAMPLE
3 | *
4 | * The applicant must be created in your backend server. The apiToken must never be in code or in
5 | * memory of the client code, or nefarious actors will be able to mis-use it.
6 | * If the workflowId is provided, the standard steps will be ovewritten.
7 | *
8 | * The code below is meant to demo a working integration of the Onfido React Native SDK.
9 | */
10 |
11 | const createSdkToken = async (applicant, applicationId) => {
12 | const apiToken = 'YOUR_API_TOKEN_HERE'; // DO NOT expose your api token in client code: keep it on the backend server.
13 | const workflowId = null; // This is not mandatory for the standard integration, and make sure to keep it on the backend server.
14 |
15 | const applicantResponse = await fetch(
16 | 'https://api.onfido.com/v3/applicants',
17 | {
18 | method: 'POST',
19 | headers: {
20 | Authorization: 'Token token=' + apiToken,
21 | 'Content-Type': 'application/json',
22 | },
23 | body: JSON.stringify(applicant),
24 | },
25 | );
26 |
27 | if (!applicantResponse.ok) {
28 | console.log(applicantResponse, 'error');
29 | return {
30 | status: 'Unable to start the SDK',
31 | message:
32 | "API Token is required to initiate SDK flow. Check your internet connection or API token. To try again, press 'Launch'",
33 | sdkToken: null,
34 | };
35 | }
36 |
37 | const sdkRequestBody = {
38 | applicant_id: '',
39 | application_id: applicationId,
40 | };
41 |
42 | await applicantResponse
43 | .json()
44 | .then(responseJson => (sdkRequestBody.applicant_id = responseJson.id))
45 | .catch(err => {
46 | console.log(err, 'error');
47 | return {
48 | status: 'Unable to start the SDK',
49 | message:
50 | 'Unexpected error occurred while trying to get the applicant id from the response.',
51 | sdkToken: null,
52 | };
53 | });
54 |
55 | const sdkTokenResponse = await fetch('https://api.onfido.com/v3/sdk_token', {
56 | method: 'POST',
57 | headers: {
58 | Authorization: 'Token token=' + apiToken,
59 | 'Content-Type': 'application/json',
60 | },
61 | body: JSON.stringify(sdkRequestBody),
62 | });
63 |
64 | if (!sdkTokenResponse.ok) {
65 | console.log(sdkTokenResponse, 'error');
66 | return {
67 | status: 'Unable to start the SDK',
68 | message:
69 | "Application id is required to initiate SDK flow. Check your internet connection or application id. To try again, press 'Launch'",
70 | sdkToken: null,
71 | };
72 | }
73 |
74 | let sdkToken;
75 | await sdkTokenResponse
76 | .json()
77 | .then(responseJson => (sdkToken = responseJson.token))
78 | .catch(err => {
79 | console.log(err, 'error');
80 | return {
81 | status: 'Unable to start the SDK',
82 | message:
83 | 'Unexpected error occurred while trying to get the SDK token from the response.',
84 | sdkToken: null,
85 | };
86 | });
87 |
88 | let workflowRunId;
89 | if (workflowId) {
90 | const workflowRunIdBody = {
91 | workflow_id: workflowId,
92 | applicant_id: sdkRequestBody.applicant_id,
93 | };
94 | const workflowRunIdResponse = await fetch(
95 | 'https://api.onfido.com/v3.5/workflow_runs',
96 | {
97 | method: 'POST',
98 | headers: {
99 | Authorization: 'Token token=' + apiToken,
100 | 'Content-Type': 'application/json',
101 | },
102 | body: JSON.stringify(workflowRunIdBody),
103 | },
104 | );
105 |
106 | if (!workflowRunIdResponse.ok) {
107 | console.log(workflowRunIdResponse, 'error');
108 | return {
109 | status: 'Unable to start the SDK',
110 | message: 'Error retrieving workflow run id from server',
111 | sdkToken: sdkToken,
112 | workflowRunId: null,
113 | };
114 | }
115 |
116 | await workflowRunIdResponse
117 | .json()
118 | .then(responseJson => (workflowRunId = responseJson.id))
119 | .catch(err => {
120 | console.log(err, 'error');
121 | return {
122 | status: 'Unable to start the SDK',
123 | message:
124 | 'Unexpected error occurred while trying to get the workflow run id from the response.',
125 | sdkToken: sdkToken,
126 | workflowRunId: null,
127 | };
128 | });
129 | }
130 |
131 | return {
132 | sdkToken,
133 | workflowRunId,
134 | };
135 | };
136 |
137 | /**
138 | * END BACKEND SERVER CODE EXAMPLE
139 | */
140 |
141 | export default createSdkToken;
142 |
--------------------------------------------------------------------------------
/android/src/test/java/com/onfido/reactnative/sdk/ReactNativeBridgeUtilesTest.java:
--------------------------------------------------------------------------------
1 | package com.onfido.reactnative.sdk;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import com.facebook.react.bridge.Arguments;
6 | import com.facebook.react.bridge.JavaOnlyMap;
7 | import com.facebook.react.bridge.WritableMap;
8 | import com.onfido.android.sdk.capture.config.DocumentMetadata;
9 | import com.onfido.android.sdk.capture.config.MediaFile;
10 | import com.onfido.android.sdk.capture.config.MediaResult;
11 | import com.onfido.android.sdk.capture.config.MediaResult.DocumentResult;
12 | import com.onfido.android.sdk.capture.config.MediaResult.LivenessResult;
13 | import com.onfido.android.sdk.capture.config.MediaResult.SelfieResult;
14 | import com.onfido.android.sdk.capture.utils.CountryCode;
15 | import com.onfido.api.client.data.DocSide;
16 | import com.onfido.api.client.data.DocType;
17 |
18 | import org.junit.Before;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.mockito.stubbing.Answer;
22 | import org.powermock.api.mockito.PowerMockito;
23 | import org.powermock.core.classloader.annotations.PrepareForTest;
24 | import org.powermock.modules.junit4.PowerMockRunner;
25 |
26 | import java.util.Arrays;
27 |
28 | @RunWith(PowerMockRunner.class)
29 | @PrepareForTest(Arguments.class)
30 | public class ReactNativeBridgeUtilesTest {
31 |
32 | @Before
33 | public void init() {
34 | // Facebook's WritableMap uses platform-specific implementations, so it must be mocked
35 | // See http://g.co/androidstudio/not-mocked
36 | PowerMockito.mockStatic(Arguments.class);
37 | Answer