B4A Library BiometricManager - Biometric Authentication

Erel

Administrator
Staff member
Licensed User


This class replaces FingerprintManager (https://www.b4x.com/android/forum/threads/fingerprint-authentication.72500/#content).
It works with all the device supported biometric authentication features.

Setup:
1. Open B4A Sdk Manager, search for biometric and install androidx.biometric:biometric.
2. Add to the activity:
B4X:
#AdditionalJar: androidx.biometric:biometric
#Extends: android.support.v4.app.FragmentActivity
'or: android.support.v7.app.AppCompatActivity
3. Add to the manifest editor:
B4X:
AddPermission(android.permission.USE_BIOMETRIC)
Usage:
- Call CanAuthenticate. It will return "SUCCESS" if biometric authentication is supported and configured.
- Call Show to show the authentication dialog and wait for the Complete event.

See the attached example.

Depends on AndroidX SDK which is supported by B4A v9.3+
 

Attachments

Last edited:

AscySoft

Active Member
Licensed User
This is the crush logcat after downloading and building in release mode.
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
biometricmanager_canauthenticate (java line: 47)
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:131)
at b4a.example.biometricmanager._canauthenticate(biometricmanager.java:47)
at b4a.example.main._activity_create(main.java:349)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:196)
at b4a.example.main.afterFirstLayout(main.java:104)
at b4a.example.main.access$000(main.java:17)
at b4a.example.main$WaitForLayout.run(main.java:82)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: java.lang.SecurityException: Must have android.permission.USE_FINGERPRINT permission.: Neither user 10088 nor current process has android.permission.USE_FINGERPRINT.
at android.os.Parcel.readException(Parcel.java:1967)
at android.os.Parcel.readException(Parcel.java:1913)
at android.hardware.fingerprint.IFingerprintService$Stub$Proxy.isHardwareDetected(IFingerprintService.java:496)
at android.hardware.fingerprint.FingerprintManager.isHardwareDetected(FingerprintManager.java:1112)
at androidx.core.hardware.fingerprint.FingerprintManagerCompat.isHardwareDetected(FingerprintManagerCompat.java:83)
at androidx.biometric.BiometricManager.canAuthenticate(BiometricManager.java:125)
... 16 more
After that I edited manifest file, I put a new line at the end (lefting everything in place) "AddPermission(android.permission.USE_FINGERPRINT)"
And then app lounches without error, but after pressing "Authenticate" another nice crush...
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
biometricmanager_show (java line: 144)
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:131)
at b4a.example.biometricmanager._show(biometricmanager.java:144)
at b4a.example.main$ResumableSub_btnAuth_Click.resume(main.java:397)
at b4a.example.main._btnauth_click(main.java:375)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:196)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:180)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:176)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
at android.view.View.performClick(View.java:6897)
at android.widget.TextView.performClick(TextView.java:12693)
at android.view.View$PerformClick.run(View.java:26104)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:659)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:552)
at androidx.appcompat.app.AppCompatDialog.setContentView(AppCompatDialog.java:95)
at androidx.appcompat.app.AlertController.installContent(AlertController.java:232)
at androidx.appcompat.app.AlertDialog.onCreate(AlertDialog.java:279)
at android.app.Dialog.dispatchOnCreate(Dialog.java:494)
at android.app.Dialog.show(Dialog.java:342)
at androidx.fragment.app.DialogFragment.onStart(DialogFragment.java:486)
at androidx.fragment.app.Fragment.performStart(Fragment.java:2632)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:915)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl.executePendingTransactions(FragmentManagerImpl.java:183)
at androidx.biometric.BiometricPrompt.authenticateInternal(BiometricPrompt.java:793)
at androidx.biometric.BiometricPrompt.authenticate(BiometricPrompt.java:662)
... 20 more
You need to use a Theme.AppCompat theme?? Why?
 

Erel

Administrator
Staff member
Licensed User
Looks like the behavior depends on the Android version. Which version are you using?

Does it work with this in the manifest editor:
B4X:
AddPermission(android.permission.USE_BIOMETRIC)
AddPermission(android.permission.USE_FINGERPRINT)

SetApplicationAttribute(android:theme, "@style/MyAppTheme")

CreateResource(values, theme.xml,
<resources>
    <style name="MyAppTheme" parent="Theme.AppCompat.Light">
   </style>
</resources>
)
And:

B4X:
#Extends: android.support.v7.app.AppCompatActivity
#AdditionalJar: com.android.support:appcompat-v7
 

AscySoft

Active Member
Licensed User
I can confirm that with added code in the manifest editor and without
B4X:
#Extends: android.support.v7.app.AppCompatActivity
#AdditionalJar: com.android.support:appcompat-v7
is working as expected.
I tested on Samsung A5 2017 (SM-A52F) on Android 8.0.0
BTW: is this better than Fingerprint Manager? Or is it just more easy to implement?
 

Erel

Administrator
Staff member
Licensed User
can confirm that with added code in the manifest editor and without
What happens when you add these two lines (instead of the previous #Extends line)?

BTW: is this better than Fingerprint Manager?
This one is better as it is not limited to fingerprints and on Android 9 or 10+ it is based on a new API that replaces the previous one.
 

HAH

Active Member
Licensed User
Is this library scan fingerprint directly without relaying on fingerprint manager?
Can we use it to scan and save finger that is not pre-registred in fingerprint manager?
 

avalle

Active Member
Licensed User
My device (Samsung S10 / Android 9) supports multiple biometric authentication options (e.g. face recognition and fingerprint).

With the code in the sample only the preferred option set in the System Preferences is triggered.
How do I allow for both options to be enabled at the same time? (same as for unlocking the device)
Or how do I enable only one option regardless the default option set in the Preferences?

I tried to add
B4X:
AddPermission(android.permission.USE_FINGERPRINT)
into the Manifest, but with no result.

Thanks
Andrea
 

Erel

Administrator
Staff member
Licensed User
I don't think that it is possible.

You can try to add this line to Show sub:
B4X:
PromptInfoBuilder.RunMethod("setDeviceCredentialAllowed", Array(True))
It will allow the user to authenticate with PIN or password however based on my tests it doesn't work properly (the event is not always raised) so I don't recommend setting it.
 
Top