The framework package is provided via this GitHub repository, which contains:
- README.md - this document
- maven - a Maven repository for the Biometrics SDK
- example-app - a sample iProov project to demonstrate the integration
- resources - a directory containing additional development resources
This guide describes how to integrate iProov biometric assurance technologies into your Android app.
iProov offers Genuine Presence Assurance™ technology (also known as "Dynamic Liveness") and Liveness Assurance™ technology (also known as "Express Liveness"):
- Genuine Presence Assurance verifies that an online remote user is the right person, a real person and that they are authenticating right now, for purposes of access control and security.
- Liveness Assurance verifies a remote online user is the right person and a real person for access control and security.
Find out more about how to use iProov in your user journeys in the Implementation Guide.
iProov also supports iOS, Xamarin, Flutter, React Native, and Web.
- Android Studio
minSdkVersion
API Level 26 (Android 8) and above- Compilation target, build tools, and Android compatibility libraries must be API level 31 or above
- AndroidX
- Camera and Internet permissions (defined in the manifest) - Camera permission will be requested and handled by this SDK, if needed
See the Upgrade Guide for information about upgrading from earlier versions of the SDK.
Obtain your API credentials by registering on iPortal.
The Android SDK is provided in Android Library Project (AAR) format as a Maven dependency.
-
Open the
build.gradle
file corresponding to the new, or existing, Android Studio project that you want to integrate. Typically, this is thebuild.gradle
file for theapp
module. -
Add maven to the
repositories
section in yourbuild.gradle
file:repositories { maven { url 'https://raw.githubusercontent.com/iProov/android/master/maven/' } }
Alternatively, in settings.gradle
if you have opted to use dependencyResolutionManagement { ... }
, then add here instead.
-
Add the SDK version to the
dependencies
section in yourbuild.gradle
file:dependencies { implementation('com.iproov.sdk:iproov:10.2.1') }
-
Build your project
TIP: When testing development, using debuggable apps, iProov can provide "development" SPs for you to use.
To enrol (register) or verify (login) a user, follow the steps below.
Obtain these tokens:
- A verify token for logging in an existing user
- An enrol token for registering a new user
See the REST API documentation for details about how to generate tokens.
TIP: In a production app you typically obtain tokens via a server-to-server back-end call. For demos and testing, iProov provides Kotlin and Java sample code for obtaining tokens via iProov API v2 with our open-source Android API Client.
For each scan, you need an IProov.Session
, which you can then call IProov.Session.start()
when you are ready to start (but only once).
Everything you need to run a scan is available in the IProov
Object. Here you will find the function to create a IProov.Session
as follows:
val session: IProov.Session = IProov.createSession(context, baseUrl, token, options)
context
- can be any Android context (your Activity or the Application context)baseUrl
- is the address of the server (SP) you are usingtoken
- the single-use claim token you acquired in the prior stepoptions
- are optional and referenced later in this document (they control the look and feel of the scan's UI among other aspects)
You now have a session and can start a scan, but first we need to talk about states, so you can know what happened.
For the duration of a Scan, you can monitor its state. The primary state let's you know the progress and ultimately concludes with one of four terminal states.
IProov.State
is a sealed class with four intermediate states and four terminal states.
Initially, the scan will begin with IProov.State.Starting
, then it moves to IProov.State.Connecting
as it tries to communicate with the server and reach IProov.State.Connected
when it has done so successfully. Then the UI begins and over time various iterations of IProov.State.Processing
will happen until a terminal state is produced.
IProov's four terminal states are as follows:
IProov.State.Success
- providing aIProov.SuccessResult
(can contain a selfie frame, if set up for your account)IProov.State.Failure
- providing aIProov.FailureResult
(contains a reason code; can contain a selfie frame, if set up for your account)IProov.State.Canceled
- providing a value indicating whether theIProov.Canceler.USER
hit the back button or otherwise moved away from the app, or theIProov.Session
was canceled by theIProov.Canceler.INTEGRATION
i.e. the app calledIProov.Session.cancel()
IProov.State.Error
- providing anIProovException
subclass indicating the cause of the error that prevented the claim from being completed
The last two (Canceled
and Error
) can interrupt the sequence at any time.
The Session provides a val state: StateFlow<IProov.State>
to be collected from.
Additionally, for those wanting to monitor the user experience, there are also UIStates, which indicate when the Session's UI starts and stops.
Similarly, the Session provides a val uiState: StateFlow<IProov.UIState>
to be collected from.
Now the hard work is done, and starting the IProov.Session
is simply achieved with a call to IProov.Session.start()
.
Two possible errors at this point to be aware of:
session.start()
might cause anIProov.State.Error
in the Flow, containing aCaptureAlreadyActiveException
. This is caused if a previousIProov.Session.start()
has yet to complete. You will need to create a newSession
to try again.session.start()
might throw aSessionCannotBeStartedTwiceException
. This is caused ifIProov.Session.start()
is called twice on the same session, no matter the outcome of the first call (a new session is always required).
This is demonstrated in the included Example App, from where the following snippets were taken.
Starting a Session, once you have obtained a token, and then observing on the State is as simple as this:
@Throws(SessionCannotBeStartedTwiceException::class)
private fun startScan(token: String) {
IProov.createSession(applicationContext, Constants.BASE_URL, token).let { session ->
// Observe first, then start
observeSessionState(session) {
session.start()
}
}
}
private fun observeSessionState(session: IProov.Session, whenReady: (() -> Unit)? = null) {
sessionStateJob?.cancel()
sessionStateJob = lifecycleScope.launch(Dispatchers.IO) {
session.state
.onSubscription { whenReady?.invoke() }
.collect { state ->
//TODO Action on State
}
}
}
Since you might need to cope with configuration changes you can fetch the current Session again this way:
class MainActivity : AppCompatActivity() {
private var sessionStateJob: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// In case this activity was recycled during the Session, we reconnect to the current one
IProov.session?.let { session ->
observeSessionState(session)
}
}
}
Of course, using a ViewModel
would prevent the need for this.
Note: You can customize the user experience by passing in an
IProov.Options
object.
Warning:
- The iProov process can be manipulated locally by a malicious user therefore never use iProov as a local authentication method. You cannot trust the returned success result to prove that the user was authenticated or enrolled successfully.
- You can treat the success state as a hint to your app to update the user interface but you must always independently validate the token server-side (using the
validate
API call) before performing any authenticated user actions.
Warning:
- Google states that
singleInstance
andsingleTask
are not recommended for general use. iProov does not recommend the calling activity to have alaunchMode
ofsingleInstance
- when tested,back
does not always work correctly, particularly after the task switcher has momentarily put anystandard
Activity (likeIProov
) into the background.
You can customize the iProov user experience by passing in an instance of IProov.Options
to the call to IProov.createSession()
.
Note: The defaults defined support accessibility requirements and have been verified to comply with WCAG 2.1 AA guidelines. Changing any of these could invalidate compliance.
The following values are found at the top level of IProov.Options
:
Option name | Description | Default |
---|---|---|
title |
The custom title displayed during a claim scan. | "" (Empty string) |
titleTextColor |
The color of the text in the title. | Color.WHITE |
headerBackgroundColor |
The background color of the header bar. | Transparent |
filter |
The filter applied to the camera preview as either LineDrawingFilter or NaturalFilter . With NaturalFilter in LA, surroundColor will be opaque on the new rounded mask area. |
LineDrawingFilter() |
surroundColor |
The color of the area outside the guideline oval. With Clear and Blur natural filters in LA, this colour will be fully opaque on the new rounded mask area. | #66000000 |
font |
Optional custom font for the title and prompt as either PathFont or ResourceFont . |
null |
logo |
Optional custom logo in the header as BitmapIcon , DrawableIcon or ResourceIcon . |
null |
enableScreenshots |
Whether screenshots are enabled during the iProov scan. Disabled by default for security reasons. | false |
closeButton |
Customize the Close button. | R.drawable.ic_arrow_back in Color.WHITE |
promptTextColor |
The color of text in prompt box. | Color.WHITE |
promptBackgroundColor |
The color of the prompt box. | #CC000000 |
promptRoundedCorners |
Whether the prompt has rounded corners. | true |
disableExteriorEffects |
Optionally disable blur and vignette outside the oval. | false |
certificates |
Optionally supply certificates used for pinning. If you are using a reverse proxy you may need to provide your own certificates. Certificate pinning is enabled by default. Certificate should be passed as a string (certificate`s subject public key info as SHA-256 hash). See below for more information |
iProov Server Certificates |
timeoutSecs |
The WebSocket streaming timeout in seconds. To disable timeout, set to 0. | 10 |
orientation |
Set the orientation of the iProov activity. Possible values are (PORTRAIT , REVERSE_PORTRAIT , LANDSCAPE or REVERSE_LANDSCAPE .Note: This option rotates the UI, not the camera. Supports USB cameras on LANDSCAPE displays, such as tablets and kiosks, where the camera is oriented normally. For Liveness Assurance, LANDSCAPE and REVERSE_LANDSCAPE is not allowed. |
PORTRAIT |
camera |
Either use the in-built front-facing camera (FRONT ) or USB EXTERNAL camera support for kiosks. |
FRONT |
By default, the iProov SDK pins to the iProov server certificates, which are used by *.rp.secure.iproov.me
.
If you are using your own reverse-proxy, you will need to update the pinning configuration to pin to your own certificate(s) instead.
Certificates should be passed as a String
, which is base64-encoded SHA-256 hash of a certificate's Subject Public Key Info. You can load a certificate as follows:
options.certificates = listOf(Certificate("O8qZKEXWWkMPISIpvB7DUow++JzIW2g+k9z3U/l5V94="))
To get Subject Public Key Info from a .crt
, use the following command:
$ openssl x509 -in cert.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
To get Subject Public Key Info from a .der
, use the following command:
$ openssl x509 -inform der -in cert.der -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
When multiple certificates are passed, as long as the server matches any of the certificates, the connection will be allowed. Pinning is performed against the whole of the certificate.
You can also disable certificate pinning entirely, by passing an empty array:
options.certificates = listOf()
Warning: Never disable certificate pinning in production apps!
Should your app require additional certificate pinning at app level using the Network Configuration file, please contact our support team which can assist you with the implementation and will provide the latest list of certificates.
Please note that this approach will require you to maintain and update the certificate list for your app to ensure ongoing security and functionality of the iProov SDK
The following values are found under IProov.Options.genuinePresenceAssurance
.
Option name | Description | Defaults |
---|---|---|
readyOvalStrokeColor |
Color for oval stroke when in a GPA "ready" state. | #01AC41 |
notReadyOvalStrokeColor |
Color for oval stroke when in the GPA "not ready" state. | Color.WHITE |
controlYPosition |
Whether to control y position of the face showing prompts. | false |
The following values are found under IProov.Options.livenessPresenceAssurance
.
Option name | Description | Defaults |
---|---|---|
ovalStrokeColor |
Color for oval stroke during LA scan. | Color.WHITE |
completedOvalStrokeColor |
Color for oval stroke after LA scan completes. | #01AC41 |
The SDK ships with support for the following languages:
Language | Code |
---|---|
English (United States) | en-US |
Dutch | nl |
French | fr |
German | de |
Italian | it |
Portuguese | pt |
Portuguese (Brazil) | pt-BR |
Spanish | es |
Spanish (Columbia) | es-CO |
Welsh | cy-GB |
You can customize the strings in the app or localize them into a different language,
All strings are prefixed with iproov__
and you can override them in strings.xml
(download a copy from GitHub).
A failure occurs when iProov successfully processes a claim but the user's identity cannot be verified.
- The capture was successfully received and processed by the server, which returns a result.
- The failure results in a
FailureResult
, which includes an enum calledFailureReason
which has the following properties:feedbackCode
- A string representation of the feedback code.description
- You should present this to the user as it may provide an informative hint for the user to increase their chances of iProoving successfully next time.
An error occurs when a capture claim fails completely and iProov is unable to process it. Errors result in an IProovException
.
The available failure reasons for claims are as follows:
FailureReason value |
description (English) |
GPA | LA |
---|---|---|---|
UNKNOWN |
Try again | ✅ | ✅ |
TOO_MUCH_MOVEMENT |
Keep still | ✅ | |
TOO_BRIGHT |
Move somewhere darker | ✅ | |
TOO_DARK |
Move somewhere brighter | ✅ | |
MISALIGNED_FACE |
Keep your face in the oval | ✅ | ❌ |
EYES_CLOSED |
Keep your eyes open | ✅ | |
FACE_TOO_FAR |
Move your face closer to the screen | ✅ | ❌ |
FACE_TOO_CLOSE |
Move your face farther from the screen | ✅ | ❌ |
SUNGLASSES |
Remove sunglasses | ✅ | |
OBSCURED_FACE |
Remove any face coverings | ✅ | ❌ |
MULTIPLE_FACES |
Ensure only one person is visible |
Key: ✅ = will be returned, ❌ = will not be returned,
These are not an indication of tests being performed but only whether reasons of failure are reported.
An error occurs when an iProov claim cannot be processed completely, in which case one of the following IProovException
classes will be surfaced:
Exception subclass | Further details |
---|---|
MultiWindowUnsupportedException |
The user attempted to iProov in split-screen/multi-screen mode, which is not supported. |
CaptureAlreadyActiveException |
An existing iProov capture is already in progress. Wait until the current capture completes before starting a new one. |
CameraException |
An error occurred acquiring or using the camera. Applicable when using the external camera support. See options.camera . |
CameraPermissionException |
The user did not allow access to the camera when prompted. Prompt the user to enable the camera permission (in Settings). |
FaceDetectorException |
An error occurred with the face detector. |
UnexpectedErrorException |
An unrecoverable error occurred during the transaction. |
ServerException |
The token was invalidated server-side or some other unrecoverable server error occurred. |
NetworkException |
An error occurred with communications to the server. Typically indicates a device connectivity issue, for example, the user's session has timed out or the internet service has been lost. |
UnsupportedDeviceException |
The device is not supported, for example, does not have a front-facing camera. |
InvalidOptionsException |
An error occurred when trying to apply the options you specified. |
ConsentRequiredException |
The user has not granted consent. For iProov internal use only. You can safely ignore. |
For a simple iProov experience that is ready to run out-of-the-box, see the example project on GitHub:
-
Open the
example-app
project in Android Studio. -
Open the
Constants.kt
file and insert your API Key and Secret at the relevant points.
Warning: The example app uses the Android API Client to directly fetch tokens on-device, which is insecure. Production implementations of iProov should always obtain tokens securely from a server-to-server call.
Google provides two variants of their Protobuf Java library: protobuf-java
(full) and protobuf-javalite
(lite). These cannot coexist.
They strongly recommend using the lite version for mobile applications, thus the standard version of the iProov SDK has the lite variant as a dependency.
That said, there are libraries that app developers need, which have dependencies on the full variant, so the app developers are forced to exclude the lite version and rely on the full version to avoid class conflicts that break the build.
To support app developers that find they must use the full variant, we now publish our own variant that has only the full protobuf as a dependency.
To use that just add "-pf"
to the end of the iProov SDK version name e.g. 10.1.0
-> 10.1.0-pf
.
- Documentation Center - Implementation Guide, Glossary, API reference
- Release Notes
- FAQs
- Wiki
For help with integrating the SDK, contact [email protected].