Home · Android & Kotlin Tutorials

AndroidX Biometric Library: Getting Started

In this tutorial you will learn how to use the AndroidX Biometric Library by showing the biometric prompt and using its callbacks.

5/5 2 Ratings

Version

  • Kotlin 1.3, Android 6.0, Android Studio 3.5

After long hours spent working on your app, nothing beats seeing it fully functional. Although building a good-looking, bug-free app is important, you also need to include security features to help keep your users protected. There are many security features available, with biometric security being particularly effective.

The Android Biometric Library makes adding these features easy and fun.
This library is available back to API level 23 and includes a biometric prompt UI out of the box. It also lets you see if a device supports biometric hardware with a single method call.

In this tutorial, you’ll use the Android Biometric Library to build an app called SecurePass. You’ll learn how to:

  • Use the AndroidX Biometric API.
  • Initialize BiometricPrompt and callbacks.
  • Use it with Android’s SharedPreferences.
Note: This tutorial assumes you understand the basics of Android development with Kotlin. If you’re new to Android development, please go through Beginning Android Development with Kotlin to understand the basics. If you’re new to Kotlin, check out this Introduction to Kotlin tutorial.

Getting Started

Download the project materials by clicking the Download Materials button at the top or bottom of this tutorial. Launch Android Studio 3.5.3 or later and select the Open an existing Android Studio project option. Then navigate to and select the begin project folder.

Android Sutdio Welcome Screen with Open an existing Android Studio project boxed in red

Once Gradle build loading is complete, build and run the app. Explore the begin project.

SecurePass App Main Screen with no content

Adding the Biometric Library Dependency

First, open build.gradle (Module:app) and add the following library dependency within dependencies:

implementation 'androidx.biometric:biometric:1.0.1'

Click Sync now to sync the project so you can use the Biometric API.

Gradle Sync screen with an arrow pointing to Sync Now

Working With Biometric API

Now, you’ll learn how to initialize the BiometricPrompt and use its biometric callbacks.

Open MainActivity.kt and add the following code at the bottom of onCreate:

val executor = ContextCompat.getMainExecutor(this)
val biometricManager = BiometricManager.from(this)

Add the BiometricManager missing import by pressing Option+Enter on Mac or Alt+Enter on PC.

Here, you get a reference to the Executor that performs tasks on the main thread and a reference of BiometricManager, both for the current context. You pass executor to your biometric prompt, which uses it to perform UI operations. Then you take advantage of biometricManager to see if the device supports biometric hardware.

You’ll see all that in a moment.

Next, add the following code block just below biometricManager initialization:

when (biometricManager.canAuthenticate()) {
  BiometricManager.BIOMETRIC_SUCCESS ->
    authUser(executor)
  BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
    Toast.makeText(
        this,
        getString(R.string.error_msg_no_biometric_hardware),
        Toast.LENGTH_LONG
    ).show()
  BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
    Toast.makeText(
        this,
        getString(R.string.error_msg_biometric_hw_unavailable),
        Toast.LENGTH_LONG
    ).show()
  BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
    Toast.makeText(
        this,
        getString(R.string.error_msg_biometric_not_setup),
        Toast.LENGTH_LONG
    ).show()
}

Don’t be afraid of the unresolved reference of authUser. You’ll define it soon.

In the code above, you use biometricManager to see if the user’s device supports biometric features before you perform any authentication. If it doesn’t, you show a user-friendly message stating the device doesn’t support this feature.

Adding Biometric Authentication

You’ll now create the authUser function which takes executor as a paremeter. You’ll use this function to perform biometric authentication if the device can handle it. Copy the code below at the bottom of MainActivity.kt.

private fun authUser(executor: Executor) {

}

Add the following code inside authUser.:

// 1
val promptInfo = BiometricPrompt.PromptInfo.Builder()
    // 2
    .setTitle(getString(R.string.auth_title))
    // 3
    .setSubtitle(getString(R.string.auth_subtitle))
    // 4
    .setDescription(getString(R.string.auth_description))
    // 5
    .setDeviceCredentialAllowed(true)
    // 6
    .build()

Add BiometricPrompt missing import by pressing Option+Enter on Mac or Alt+Enter on PC. Select Import, if asked, and choose androidx.biometric.

Here you create the authentication dialog by specifying its properties.

Here’s a code breakdown:

  1. promptInfo: Declares this variable and intializes it with BiometricPrompt.PromptInfo builder to build the authentication dialog.
  2. setTitle: Gives the dialog a title.
  3. setSubtitle: Assigns the dialog a subtitle that is placed below the main title.
  4. setDescription: Describes this dialog so the end-user understands what it is and the function behind it.
  5. setDeviceCredentialAllowed(true): Use this to let a user whose device doesn’t support fingerprint authentication use a password or a pattern instead.
  6. build(): Call this to build the dialog with the properties you specified above.

Now that you’ve set up the authentication dialog, you need to handle the callbacks and the flow of when the user interacts with it.

Handling the Authentication Callbacks

Add the following block of code below promptInfo initialization:

// 1
val biometricPrompt = BiometricPrompt(this, executor,
    object : BiometricPrompt.AuthenticationCallback() {
      // 2
      override fun onAuthenticationSucceeded(
          result: BiometricPrompt.AuthenticationResult
      ) {
        super.onAuthenticationSucceeded(result)
        main_layout.visibility = View.VISIBLE
      }
      // 3
      override fun onAuthenticationError(
          errorCode: Int, errString: CharSequence
      ) {
        super.onAuthenticationError(errorCode, errString)
        Toast.makeText(
            applicationContext,
            getString(R.string.error_msg_auth_error, errString),
            Toast.LENGTH_SHORT
        ).show()
      }
      // 4
      override fun onAuthenticationFailed() {
        super.onAuthenticationFailed()
        Toast.makeText(applicationContext,
            getString(R.string.error_msg_auth_failed),
            Toast.LENGTH_SHORT
        ).show()
      }
    })

That’s a lot of code. Here’s a breakdown:

  1. You declare a variable called biometricPrompt and initialize it with BiometricPrompt. BiometricPrompttakes three parameters: The context, the executor and the authentication callbacks. The callbacks deal with whether the authentication is successful, an error occurred we can recover from, or when it completely fails.
  2. When the user authenticates successfully, onAuthenticationSucceeded triggers and changes the visibility of the layout from View.GONE to View.VISIBLE.
  3. When an error occurs that can’t be recovered from, onAuthenticationError is triggered. In this case you show a Toast to the user, explaining what happened.
  4. onAuthenticationFailed: This callback triggers when a biometric is valid but isn’t recognized. In this case you show another Toast to the user.

Finally, add this line of code at the bottom of authUser to see the dialog triggered on the screen:

biometricPrompt.authenticate(promptInfo)

You authenticate the dialog by passing promptInfo, which holds the dialog properties, to biometricPrompt so you can see the dialog.

Now, moment you’ve been waiting for. :]

Build and run the project to see the authentication in action.

Box stating Authentication Required with a fingerprint icon

User opens app, sees Authentication prompt and uses fingerprint to access account

Finally! It feels good to see the biometric dialog appear on your screen. :]

Instead of using a fingerprint for authentication, you also have the option of using a password.

User opens app, sees authentication prompt and chooses to enter password

Persisting Data After Authentication

Right now, the profile screen looks static, and you can’t interact with it that much. You’ll make it interactive by using Android SharedPreferences to persist your info on your device. Then you’ll see your info appear again the next time you open the app.

Open activity_main.xml and add the following code at the end, right before the closing LinearLayout tag.

<Button
 android:id="@+id/btnSave"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="@string/label_save_changes" />

Here you added an Android Button to save the data from the form to SharedPreferences.

Next, go back to MainActivity.kt and add this code at the bottom of onCreate:

 	 
btnSave.setOnClickListener {
}	 

You added OnClickListener so the button responds to your action whenever you tap on it.

Working With Shared Preferences

Now it’s time to work with shared preferences by adding the following code just above btnSave.setOnClickListener.

val sharedPreferences: SharedPreferences = 
    getSharedPreferences("user_data", Context.MODE_PRIVATE)

Here, you declare a variable of a type SharedPreferences and initialize it with getSharedPreferences, which takes two parameters. The first parameter is the name of the preference file. The second is the operation mode and is set to Context.MODE_PRIVATE so only this app can access this file.

Next, add the following code inside btnSave.setOnClickListener:

//1
val editor = sharedPreferences.edit()
//2
editor.putString("Name", etName.text.toString())
editor.putString("Email", etEmail.text.toString())
editor.putString("Phone", etPhone.text.toString())
//3
editor.apply()
//4
etName.setText("")
etEmail.setText("")
etPhone.setText("")

Here’s what you added:

  1. sharedPreferences.edit(): You call this method when you want to begin to presist your data.
  2. editor.putString: You use this when you want to save a String data type inside shared peferences. This takes two parameters. The first parameter is the name of the value you want store while the second is the value you want to store under this name.
  3. editor.apply(): Finally, you call this when you want to save values inside SharedPreferences.
  4. After you save your data, you clear it from the screen. Here, you clear the name, email and phone number.

Build and run the app to see the progress.

User opens app, gets authentication prompt and stars to create account

Isn’t it cool to see it working? :] But you might be asking why the data that you entered doesn’t appear after you relaunch the app. Good question.

To solve that problem, add the following code at the bottom of onCreate:

etName.setText(sharedPreferences.getString("Name", ""))
etEmail.setText(sharedPreferences.getString("Email", ""))
etPhone.setText(sharedPreferences.getString("Phone", ""))

Earlier you uses editor.putString to save the data. To retrieve it you use sharedPreferences.getString("", ""). You use getString because the data type you initially saved was of type String.

This takes two parameters: first is the name of the value that you want to retrieve, while the second parameter is a default value that you provide in case the original value is empty.

Now build and run the app to see the result.

User opens app, gets authentication prompt and sees the saved data

Where to Go From Here?

You can download the completed end project by clicking on the Download Materials button at the top or bottom of this tutorial.

Be sure to check out AndroidX Biometric Library documentation to find out about other uses for this API, such as customization and cryptography.

I hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!

Average Rating

5/5

Add a rating for this content

2 ratings

More like this

Contributors

Comments