Skip to main content

FingerprintAPI Example

The Fingerprint API in Android is a security feature that allows users to use their fingerprints to unlock their devices, authenticate payments, and access protected data. This feature was introduced in Android 6.0 Marshmallow and has been improved and updated in subsequent versions of Android. In this article, we will explore how to use the Fingerprint API in Android and provide code examples using Kotlin.

Prerequisites

Before we start, you should have a basic understanding of Android development and Kotlin. You will also need an Android device with a fingerprint scanner and Android Studio installed on your computer.

Step 1: Add Fingerprint Permissions

The first step is to add the necessary permissions to your app's manifest file. Open your app's AndroidManifest.xml file and add the following permissions:

<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

These permissions grant your app permission to use the fingerprint scanner.

Step 2: Check for Fingerprint Hardware

Before we can use the Fingerprint API, we need to check if the device has the necessary hardware. We can do this by calling the hasSystemFeature() method of the PackageManager class. Here's an example:

val packageManager = context.packageManager
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
// Fingerprint scanner not supported
}

Step 3: Create a Fingerprint Manager

Next, we need to create a FingerprintManager object. This can be done using the FingerprintManagerCompat class, which provides compatibility with older versions of Android.

val fingerprintManager = FingerprintManagerCompat.from(context)

Step 4: Check for Enrolled Fingerprints

Before we can authenticate the user's fingerprint, we need to check if the device has any enrolled fingerprints. We can do this by calling the hasEnrolledFingerprints() method:

if (!fingerprintManager.hasEnrolledFingerprints()) {
// No enrolled fingerprints
}

Step 5: Create a Fingerprint Authentication Callback

To handle fingerprint authentication, we need to create a FingerprintManagerCompat.AuthenticationCallback object. This object will receive callbacks when the user attempts to authenticate with their fingerprint.

private val authenticationCallback = object : FingerprintManagerCompat.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: FingerprintManagerCompat.AuthenticationResult?) {
// Fingerprint authentication succeeded
}

override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
// Fingerprint authentication error
}

override fun onAuthenticationFailed() {
// Fingerprint authentication failed
}
}

In this example, we've overridden three methods: onAuthenticationSucceeded(), onAuthenticationError(), and onAuthenticationFailed(). These methods will be called when the user successfully authenticates with their fingerprint, encounters an error during authentication, or fails to authenticate, respectively.

Step 6: Start Fingerprint Authentication

To start fingerprint authentication, we need to call the authenticate() method of the FingerprintManagerCompat object. We'll pass in a CryptoObject object, which provides additional security for the authentication process.

val cryptoObject = FingerprintManagerCompat.CryptoObject(cipher)
fingerprintManager.authenticate(cryptoObject, 0, CancellationSignal(), authenticationCallback, null)

In this example, we've passed in a cipher object as the CryptoObject. This cipher object can be used to encrypt and decrypt data. The 0 parameter specifies the flags for the authentication dialog. We've passed in a new CancellationSignal() object and our authenticationCallback.

More Examples

Learn FingerPrintAPI using this step by step example.

Here is the demo screenshot:

Kotlin Android FingerprintAPI Example

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

No special dependency is needed to use FingerPrintAPI. We will use classes from android.hardware.fingerprint which is available in the standard android sdk.

Step : Create FingerPrint Handler

FingerprintHandler.kt

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.os.Build
import android.os.CancellationSignal
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.view.View
import android.widget.TextView

@RequiresApi(Build.VERSION_CODES.M)
class FingerprintHandler// Constructor
(private val context: Context) : FingerprintManager.AuthenticationCallback() {

fun startAuth(manager: FingerprintManager, cryptoObject: FingerprintManager.CryptoObject) {
val cancellationSignal = CancellationSignal()
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
return
}
manager.authenticate(cryptoObject, cancellationSignal, 0, this, null)
}

override fun onAuthenticationError(errMsgId: Int, errString: CharSequence) {
this.update("Fingerprint Authentication error\n$errString", false)
}

override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence) {
this.update("Fingerprint Authentication help\n$helpString", false)
}

override fun onAuthenticationFailed() {
this.update("Fingerprint Authentication failed.", false)
}

override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
this.update("Fingerprint Authentication succeeded.", true)
}

private fun update(e: String, success: Boolean?) {
val textView = (context as Activity).findViewById<View>(R.id.errorText) as TextView
textView.text = e
if (success!!) {
textView.setTextColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
}
}
}

Step : Write MainActivity code

MainActivity.kt

import android.Manifest
import android.annotation.TargetApi
import android.app.KeyguardManager
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
import android.os.Build
import android.os.Bundle
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.KeyProperties
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.widget.TextView
import java.io.IOException
import java.security.*
import java.security.cert.CertificateException
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.NoSuchPaddingException
import javax.crypto.SecretKey

class MainActivity : AppCompatActivity() {

private var keyStore: KeyStore? = null
// Variable used for storing the key in the Android Keystore container
private val KEY_NAME = "AndroidExamples"
private var cipher: Cipher? = null
private var textView: TextView? = null

@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)

// Initializing both Android Keyguard Manager and Fingerprint Manager
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val fingerprintManager = getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager

textView = findViewById<TextView>(R.id.errorText)

// Check whether the device has a Fingerprint sensor.
if (!fingerprintManager.isHardwareDetected) {
/**
* An error message will be displayed if the device does not contain the fingerprint hardware.
* However if you plan to implement a default authentication method,
* you can redirect the user to a default authentication activity from here.
* Example:
* Intent intent = new Intent(this, DefaultAuthenticationActivity.class);
* startActivity(intent);
*/
textView!!.text = "Your Device does not have a Fingerprint Sensor"
} else {
// Checks whether fingerprint permission is set on manifest
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
textView!!.text = "Fingerprint authentication permission not enabled"
} else {
// Check whether at least one fingerprint is registered
if (!fingerprintManager.hasEnrolledFingerprints()) {
textView!!.text = "Register at least one fingerprint in Settings"
} else {
// Checks whether lock screen security is enabled or not
if (!keyguardManager.isKeyguardSecure) {
textView!!.text = "Lock screen security not enabled in Settings"
} else {
generateKey()

if (cipherInit()) {
val cryptoObject = FingerprintManager.CryptoObject(cipher!!)
val helper = FingerprintHandler(this)
helper.startAuth(fingerprintManager, cryptoObject)
}
}
}
}
}
}

@TargetApi(Build.VERSION_CODES.M)
protected fun generateKey() {
try {
keyStore = KeyStore.getInstance("AndroidKeyStore")
} catch (e: Exception) {
e.printStackTrace()
}

val keyGenerator: KeyGenerator
try {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to get KeyGenerator instance", e)
} catch (e: NoSuchProviderException) {
throw RuntimeException("Failed to get KeyGenerator instance", e)
}

try {
keyStore!!.load(null)
keyGenerator.init(KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).setBlockModes(
KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build())
keyGenerator.generateKey()
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException(e)
} catch (e: InvalidAlgorithmParameterException) {
throw RuntimeException(e)
} catch (e: CertificateException) {
throw RuntimeException(e)
} catch (e: IOException) {
throw RuntimeException(e)
}

}

@TargetApi(Build.VERSION_CODES.M)
fun cipherInit(): Boolean {
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES
+ "/"
+ KeyProperties.BLOCK_MODE_CBC
+ "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to get Cipher", e)
} catch (e: NoSuchPaddingException) {
throw RuntimeException("Failed to get Cipher", e)
}

try {
keyStore!!.load(null)
val key = keyStore!!.getKey(KEY_NAME, null) as SecretKey
cipher!!.init(Cipher.ENCRYPT_MODE, key)
return true
} catch (e: KeyPermanentlyInvalidatedException) {
return false
} catch (e: KeyStoreException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: CertificateException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: UnrecoverableKeyException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: IOException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to init Cipher", e)
} catch (e: InvalidKeyException) {
throw RuntimeException("Failed to init Cipher", e)
}

}
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

NumberLink
1.Download Example
2.Follow code author
3.Code: Apache 2.0 License

Conclusion

In this article, we've explored how to use the Fingerprint API in Android using Kotlin. We've covered the necessary permissions, checking for fingerprint hardware, checking for enrolled fingerprints, creating an authentication callback, and starting fingerprint authentication. With this knowledge, you can add fingerprint authentication to your own Android apps and provide an additional layer of security for your users.