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 次 |
| 最近记录: |