PingOne Recognize

Getting Started with the PingOne Recognize Mobile SDK

Learn how to integrate the PingOne Recognize SDK in your Android or iOS mobile application, and enroll and authenticate users through the PingOne Recognize platform.

Before jumping into your code editor, make sure that you are familiar with the various components of the authentication system and common biometric integration flows.

Before you begin

Make sure you have both required API keys and the list of production hosts from your PingOne Recognize contact:

  • YOUR_CLOUDSMITH_TOKEN to download the SDK from Cloudsmith repository

  • KEYLESS_API_KEY to configure the mobile SDK

  • KEYLESS_HOSTS a list of node URLs. URLs in KEYLESS_HOSTS must not contain trailing slashes (/).

PingOne Recognize SDK requirements.

  • Android

  • iOS

  • Flutter

  • React Native

The PingOne Recognize SDK uses:

The PingOne Recognize SDK uses:

Set up a physical iOS device for running your app and enable the following permissions:

  • Enable camera permissions: add the Privacy - Camera Usage Description key in your project Info.plist (in Xcode under Project > Info):

    <key>NSCameraUsageDescription</key>
    <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
  • Enable background processing to synchronize PingOne Recognize data. You can find a comprehensive guide in Apple documentation. In short, enable the Background processing mode under Signing & Capabilities/Background Modes. Then add the following in your Info.plist under Permitted background task scheduler identifiers:

    <key>NSCameraUsageDescription</key>
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>YOUR APP IDENTIFIER</string>
    </array>

The PingOne Recognize SDK uses:

  • Flutter 3.0 or higher

  • Dart 3.0 or higher

  • All requirements from both Android and iOS platforms

Set up required permissions as described in the Android and iOS sections.

The PingOne Recognize RN SDK requires:

  • React 18.2.0 or higher

  • React Native 0.71.0 or higher

Additionally, ensure you meet the native requirements for each platform:

  • Android: Minimum SDK 23 (Android 6.0), Kotlin 2.2.0 or higher.

  • iOS: Target version 13.0 or higher

Installation

PingOne Recognize Anti-Inject variant for enhanced frame injection prevention
If you are using the anti-inject SDK variant with runtime application self protection (RASP), you need to:
  1. Set the package repository partners-rasp-* communicated to you by the Delivery team.

  2. Add into your app assets the license file provided by the Delivery team.

  • Android - Gradle

  • iOS - SPM

  • iOS - CocoaPods

  • Flutter

  • React Native

  1. To allow PingOne Recognize to handle the result of registerForActivityResult, you must call PingOne Recognize from an Activity implementing ActivityResultCaller.

    Extend any AndroidX activity that implements this interface, for example ComponentActivity or AppCompatActivity.

  2. If you use Proguard, add the following rules to your Proguard configuration file:

    # {p1recognize} Proguard
    -keep class io.keyless.sdk.** {*;}
    -keepclassmembers class io.keyless.sdk.** {*;}
  3. In the repositories section of the settings.gradle file of your Android app, add the snippet below, replacing YOUR_CLOUDSMITH_TOKEN with the CloudSmith token provided to you by PingOne Recognize.

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
            maven {
                url "https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/maven/"
            }
        }
    }
  4. In the dependencies block of your project build.gradle file, typically app/build.gradle, add:

    dependencies {
    // ...
    
    implementation 'io.keyless:keyless-mobile-sdk:+'
    }
  5. In the android block of your project build.gradle file, make sure you have:

    android {
        // ...
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
        // Add only if you're using Kotlin
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }

Cloudsmith distributes artifacts and works as a Swift Package Registry. To use packages from a registry, set up the environment for that registry and log in.

When working with Swift projects, registries can be configured locally to the project. Xcode does not support local registry configuration, so configure globally for the editor to detect packages.

It is best to run the following commands from a terminal with Xcode closed.
  1. To configure the PingOne Recognize Cloudsmith Package Registry, run:

    swift package-registry set --global --scope keyless https://swift.cloudsmith.io/keyless/partners/
    swift package-registry login https://swift.cloudsmith.io/keyless/partners/ --token <your-api-token>
  2. Use the token provided to you in place of <your-api-token>.

  3. Because this registry is global, provide the scope keyless for the PingOne Recognize Package Registry.

    These commands add the following to ~/.swiftpm/configuration/registries.json:

    {
      "authentication" : {
        "swift.cloudsmith.io" : {
          "loginAPIPath" : "/keyless/<repo>",
          "type" : "token"
        }
      },
      "registries" : {
        "keyless" : {
          "supportsAvailability" : false,
          "url" : "https://swift.cloudsmith.io/keyless/<repo>/"
        }
      },
      "version" : 1
    }
  4. After setup, open Xcode, go to File > Add Package Dependencies, and search for package keyless.mobile-sdk.

Optional: Test Release Candidates

Release candidates are available in a separate repo. Because Xcode does not handle semantic versioning with build numbers well, use this approach:

  1. Download the package manually from Cloudsmith with your token.

  2. Extract the archive to a folder named KeylessSDKPackage.

  3. Drag and drop the extracted folder inside your Xcode project, under the project root.

If a PingOne Recognize SDK package is already configured, it is seamlessly replaced by the local one. Otherwise, add KeylessSDK library to your target from project settings.

Because CocoaPods is in maintenance mode, this method will be discontinued. Prefer SPM.
  1. Create a Podfile if you do not already have one:

    cd your-project-directory
    pod init
  2. Add the keyless-mobile-sdk pod to your Podfile:

    # This is the {p1recognize} repository for partners
    source 'https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git'
    
    target 'MyApp' do
        use_frameworks!
    
        # Add the {p1recognize} pod
        pod 'keyless-mobile-sdk'
    end
  3. Add the following at the bottom of your Podfile:

    post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
        config.build_settings['ENABLE_BITCODE'] = 'NO'
        end
    end
    end
  4. Install pods:

    pod install
    
    Analyzing dependencies
    Cloning spec repo `cloudsmith-YOUR_CLOUDSMITH_TOKEN-keyless-partners-cocoapods-index` from `https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git`
  1. Add the PingOne Recognize SDK repository:

    echo '${CLOUDSMITH_TOKEN}' | dart pub token add https://dart.cloudsmith.io/keyless/flutter/
  2. Add the PingOne Recognize SDK dependency to pubspec.yaml:

    dart pub add keyless_flutter_sdk:PACKAGE_VERSION --hosted-url https://dart.cloudsmith.io/keyless/flutter/
  3. Follow installation steps in both Android and iOS sections to set up native SDKs.

  4. Run flutter pub get to download dependencies:

    flutter pub get

You also need to bridge native SDKs used by the Flutter SDK in the android and ios sections of your Flutter project.

Android

  1. Add the following line in root build.gradle:

    allprojects {
        repositories {
            google()
            mavenCentral()
            maven {
                setUrl("https://dl.cloudsmith.io/YOUR_CUSTOM_TOKEN/keyless/partners/maven/")
            }
        }
    }
  2. Replace YOUR_CUSTOM_TOKEN with the Cloudsmith token provided by the PingOne Recognize integration support team.

  3. Then open your Android.manifest and add the following inside the <application> tag:

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
    
        <meta-data
            android:name="io.keyless.fluttersdk.KeylessInitializer"
            android:value="androidx.startup" />
    </provider>

iOS

  1. Target at least iOS 13 in your project.

  2. Open your PodFile and add:

    source 'https://dl.cloudsmith.io/YOUR_CUSTOM_TOKEN/keyless/partners/cocoapods/index.git'
  3. Add the following permissions in Info.plist:

    <key>NSCameraUsageDescription</key>
    <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
  1. Configure access to the private registry by creating a .npmrc file in your project root:

    @react-native-keyless:registry=https://npm.cloudsmith.io/keyless/partners-rc/
    //npm.cloudsmith.io/keyless/partners/:_authToken=YOUR_CLOUDSMITH_TOKEN

    Replace YOUR_CLOUDSMITH_TOKEN with the token provided to you.

  2. Add the PingOne Recognize SDK dependency:

    # Using npm
    npm install @react-native-keyless/sdk
    
    # Using yarn
    yarn add @react-native-keyless/sdk

Android Setup

  1. Add the PingOne Recognize Maven repository to root build.gradle:

    allprojects {
        repositories {
            google()
            mavenCentral()
            maven {
                url "https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/maven/"
            }
        }
    }
  2. Verify Kotlin version is 2.2.0 or higher in your Android plugin configuration.

iOS Setup

  1. Ensure platform :ios, '13.0' or higher in ios/Podfile.

  2. Add private spec repo at top of Podfile:

    source 'https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git'
    source 'https://cdn.cocoapods.org/'
  3. Add camera permissions in ios/Info.plist:

    <key>NSCameraUsageDescription</key>
    <string>This app uses the camera to scan face.</string>
  4. Install native dependencies:

    cd ios && pod install

Essential Configuration

There is some essential configuration required before you can use the PingOne Recognize SDK.

  • Android

  • iOS

  • Android v4.6

  • iOS v4.6

  • Flutter

  • React Native

  1. Initialize PingOne Recognize SDK in your Application class:

    // MainApplication
    override fun onCreate() {
        super.onCreate()
        // Initialize {p1recognize}
        Keyless.initialize(this)
    }
    If your app crashes with java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher (or React Native bridges do not receive enrollment completion), this may be due to a mismatch between applicationId and Activity namespace.

    In this case, pass your Activities namespace as a second parameter:

    // MainApplication
    override fun onCreate() {
        super.onCreate()
        // Initialize {p1recognize}
        Keyless.initialize(this, "my.app.test")
    }
  2. Add your application class to AndroidManifest.xml:

    <application
        android:allowBackup="true"
        android:name=".MainApplication"
        android:label="@string/app_name"
        android:supportsRtl="true">
    </application>
  3. Configure PingOne Recognize SDK from MainActivity, ViewModel, or your PingOne Recognize integration class. configure is asynchronous, so wait for completion before calling other APIs:

    val setupConfig = SetupConfig(
            apiKey = "KEYLESS_API_KEY",
            hosts = listOf("KEYLESS_HOSTS")
        )
    
     Keyless.configure(setupConfig) { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> {
                Log.d("KeylessSDK", "configure success")
                // {p1recognize} is ready
            }
            is Keyless.KeylessResult.Failure -> {
                Log.d("KeylessSDK", "configure error")
            }
         }
     }
  1. Create SetupConfig and pass it to Keyless.configure (typically in application(:didFinishLaunchingWithOptions:)):

    let setupConfig = SetupConfig(
            apiKey: "KEYLESS_API_KEY",
            hosts: ["KEYLESS_HOSTS"]
        )
    
    if let error = Keyless.configure(configuration: setupConfig) {
        print("{p1recognize}.Configure failed with error: \(error)")
    }
  1. Initialize PingOne Recognize SDK:

    // MainApplication
    override fun onCreate() {
        super.onCreate()
        Keyless.initialize(this)
    }
  2. Add your application class to the manifest.

  3. Configure using SetupConfiguration:

    val setupConfiguration = SetupConfiguration.builder
        .withApiKey("KEYLESS_API_KEY")
        .withHosts(listOf("KEYLESS_HOSTS"))
        .build()
    
    Keyless.configure(setupConfiguration) { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> {
                Log.d("KeylessSDK", "configure success")
            }
            is Keyless.KeylessResult.Failure -> {
                Log.d("KeylessSDK", "configure error")
            }
        }
    }
  1. Create Keyless.SetupConfiguration and pass it to Keyless.configure:

    let setupConfiguration = Keyless.SetupConfiguration.builder
        .withApiKey("KEYLESS_API_KEY")
        .withHosts(["KEYLESS_HOSTS"])
        .build()
    
    if let error = Keyless.configure(configuration: setupConfiguration) {
        print("Keyless.Configure failed with error: \(error)")
    }
  1. Import required packages:

    import 'package:keyless_flutter_sdk/keyless.dart';
    import 'package:keyless_flutter_sdk/models/configurations/setup_configuration.dart';
  2. Configure SDK during app initialization:

    final setupConfiguration = SetupConfiguration(
        apiKey: "KEYLESS_API_KEY",
        hosts: ["KEYLESS_HOSTS"],
    );
    
    try {
        await Keyless.instance.configure(setupConfiguration);
        print("Keyless SDK configured successfully");
    } catch (error) {
        print("Failed to configure Keyless SDK: $error");
    }
  1. Initialize native SDK for Android in MainApplication.kt:

    import io.reactnative.keyless.sdk.KeylessSDKModule
    
    override fun onCreate() {
        super.onCreate()
        KeylessSDKModule.initialize(application = this)
    }
  2. Configure SDK once app starts:

    import Keyless, { SetupConfig } from '@react-native-keyless/sdk';
    
    const config = new SetupConfig({
      apiKey: 'KEYLESS_API_KEY',
      hosts: ['KEYLESS_HOSTS'],
    });
    
    const result = await Keyless.configure(config);
    
    result.fold({
      onSuccess: data => {
        console.log('Keyless SDK configured successfully:', data);
      },
      onFailure: error => {
        console.error('Failed to configure Keyless SDK:', error);
      },
    });

Additional Configuration

In addition to essential configuration parameters, you can also specify optional parameters detailed throughout Mobile SDK docs (for example, Logging, Liveness Settings).

Shared Circuits

This is the target desired number of circuits kept on the server. Use numberOfSharedCircuits to set this value.

Networking Module

If you need to perform network requests on behalf of the Keyless SDK, implement the KLNetworkingModule interface and set networkingModule with your implementation.

  • Android

  • iOS

public interface KLNetworkingModule {
    public fun sendHTTPRequest(
        baseUrl: String,
        path: String,
        method: String,
        headers: Map<String, String>,
        body: String
    ): KLHTTPResponse

    public data class KLHTTPResponse(
        val errorCode: Int,
        val httpCode: Int,
        val responseBody: String
    )
}
public protocol KLNetworkingModule {
    func sendHTTPRequest(
        host: String,
        url: String,
        method: String,
        headers: [String: String],
        body: String
    ) -> KLHTTPResponse
}

public struct KLHTTPResponse {
    var errorCode: Int
    var httpCode: Int
    var responseBody: String
    public init(errorCode: Int, httpCode: Int, responseBody: String) {
        self.errorCode = errorCode
        self.httpCode = httpCode
        self.responseBody = responseBody
    }
}