fer*_*dok 3 android kotlin android-biometric-prompt android-biometric
我正在使用 androidx.biometric:biometric:1.0.1
一切正常,但是当我的设备没有生物识别传感器时(或者当用户没有设置他的指纹等)并且我在进行身份验证后尝试使用DeviceCredentials 时,我的功能输入数据无效。
class MainActivity : AppCompatActivity() {
private val TAG = MainActivity::class.java.name
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.first).setOnClickListener {
authenticate(MyData(1, "first"))
}
findViewById<View>(R.id.second).setOnClickListener {
authenticate(MyData(2, "second"))
}
}
private fun authenticate(data: MyData) {
Log.e(TAG, "starting auth with $data")
val biometricPrompt = BiometricPrompt(
this,
ContextCompat.getMainExecutor(this),
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
Log.e(TAG, "auth done : $data")
}
})
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setDeviceCredentialAllowed(true)
.setTitle("title")
.build()
biometricPrompt.authenticate(promptInfo)
}
}
data class MyData(
val id: Int,
val text: String
)
Run Code Online (Sandbox Code Playgroud)
首先我点击我的first
按钮,进行身份验证,然后我点击我的second
按钮并进行身份验证,然后android logcat是这样的:
E/com.test.biometrictest.MainActivity: starting auth with MyData(id=1, text=first)
E/com.test.biometrictest.MainActivity: auth done : MyData(id=1, text=first)
E/com.test.biometrictest.MainActivity: starting auth with MyData(id=2, text=second)
E/com.test.biometrictest.MainActivity: auth done : MyData(id=1, text=first)
Run Code Online (Sandbox Code Playgroud)
正如您在最后一行中看到的 MyData id 和文本无效!autneticate
调用 onAuthenticationSucceeded 时函数 input(data) 不一样!
(如果您尝试对其进行测试,请务必使用 DeviceCredentials 而不是生物识别技术,我的意思是模式或密码,请取消设置您的指纹)为什么数据在回调中无效?
它可以在 android 10 或指纹上正常工作
我不想使用 onSaveInstanceState。
当你创建一个新的BiometricPrompt
类实例时,它会LifecycleObserver
向活动添加一个,正如我发现的那样,它永远不会删除它。因此,当您BiometricPrompt
在一个活动中有多个实例时,同时有多个实例LifecycleObserver
会导致此问题。
对于 Android Q 之前的设备,有一个名为的透明活动DeviceCredentialHandlerActivity
和一个名为的桥接类DeviceCredentialHandlerBridge
,它们支持设备凭据身份验证。BiometricPrompt
管理不同状态下的桥,并在需要时最终调用状态中的回调方法onResume
(在离开凭证窗口后返回活动时)。当有多个时LifecycleObserver
,第一个会处理结果并重置桥接器,所以其他观察者无事可做。这就是第一个回调实现在您的代码中调用两次的原因。
解决方案:LifecycleObserver
当您创建BiometricPrompt
类的新实例时,
您应该从活动中删除。由于无法直接访问观察者,因此您需要在此处使用反射。我根据此解决方案修改了您的代码,如下所示:
class MainActivity : AppCompatActivity() {
private val TAG = MainActivity::class.java.name
private var lastLifecycleObserver: LifecycleObserver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.first).setOnClickListener {
authenticate(MyData(1, "first"))
}
findViewById<View>(R.id.second).setOnClickListener {
authenticate(MyData(2, "second"))
}
}
private fun authenticate(data: MyData) {
Log.e(TAG, "starting auth with $data")
lastLifecycleObserver?.let {
lifecycle.removeObserver(it)
lastLifecycleObserver = null
}
val biometricPrompt = BiometricPrompt(
this,
ContextCompat.getMainExecutor(this),
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
Log.e(TAG, "auth done : $data")
}
})
var field = BiometricPrompt::class.java.getDeclaredField("mLifecycleObserver")
field.isAccessible = true
lastLifecycleObserver = field.get(biometricPrompt) as LifecycleObserver
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setDeviceCredentialAllowed(true)
.setTitle("title")
.build()
biometricPrompt.authenticate(promptInfo)
}
}
data class MyData(
val id: Int,
val text: String
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2586 次 |
最近记录: |