BiometricPromptで、指紋認証を利用した本人確認を実装する際
指紋以外の方法でも認証を通過できるように、PIN/Password/Patternを許可したいと考えています。
環境
言語:Kotlin
エミュレータ:Pixel3(API29)
(budild.gradle 一部省略)
gradle
1apply plugin: 'com.android.application' 2apply plugin: 'kotlin-android' 3apply plugin: 'kotlin-android-extensions' 4 5 6android { 7 compileSdkVersion 29 8 buildToolsVersion "29.0.2" 9 defaultConfig { 10 minSdkVersion 27 11 targetSdkVersion 29 12 } 13} 14 15dependencies { 16 implementation fileTree(dir: 'libs', include: ['*.jar']) 17 implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 18 implementation 'androidx.appcompat:appcompat:1.1.0' 19 implementation 'androidx.core:core-ktx:1.1.0' 20 implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 21 testImplementation 'junit:junit:4.12' 22 androidTestImplementation 'androidx.test.ext:junit:1.1.1' 23 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 24 25 implementation 'androidx.biometric:biometric:1.0.0' 26}
実装内容
MainActivity
1class MainActivity : AppCompatActivity() { 2 3 private val status by lazy { findViewById<TextView>(R.id.textView_status) } 4 5 6 override fun onCreate(savedInstanceState: Bundle?) { 7 super.onCreate(savedInstanceState) 8 setContentView(R.layout.activity_main) 9 10 // Android端末に、PIN・指紋認証・パターン認証が設定されているかを確認 11 val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager 12 if (!keyguardManager.isKeyguardSecure) { 13 Toast.makeText(this, "PINとか設定されてないよ", Toast.LENGTH_SHORT).show() 14 } 15 16 findViewById<Button>(R.id.btnAuth).setOnClickListener { 17 val promptInfo = BiometricPrompt.PromptInfo.Builder() 18 .setTitle("タイトル") 19 .setSubtitle("サブタイトル") 20 .setDescription("認証テストに使うよ") 21 .setDeviceCredentialAllowed(true) // Allow Pin/Password/Pattern 22 .build() 23 val handler = Handler() 24 25 BiometricPrompt(this, Executors.newSingleThreadExecutor(), object : BiometricPrompt.AuthenticationCallback(){ 26 override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { 27 super.onAuthenticationError(errorCode, errString) 28 Log.d("LOG", "BiometricPrompt Error : ($errorCode)$errString") 29 handler.post{ status.text = errString } 30 } 31 override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { 32 super.onAuthenticationSucceeded(result) 33 Log.d("LOG", "BiometricPrompt Succeeded : ${result.cryptoObject}") 34 handler.post{ status.text = result.toString() } 35 } 36 37 override fun onAuthenticationFailed() { 38 super.onAuthenticationFailed() 39 Log.d("LOG", "BiometricPrompt Failed") 40 } 41 }).authenticate(promptInfo) 42 } 43 } 44 45 46 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 47 super.onActivityResult(requestCode, resultCode, data) 48 Log.d("LOG", "onActivityResult : $resultCode") 49 } 50}
Logcat
1D/LOG: BiometricPrompt Error : (5)認証をキャンセルしました
問題
上記の実装でエミュレータ上で起動した場合、Fingerprintでの認証は通過しますが、
PINコードを利用した場合、AuthenticationCallbackではErrorで認証をキャンセルした扱いになります。
従来のKeyguardManagerから、Intentを発行していたみたいに、
onActivityResultに戻ってくるのかと思っても、どうやらそこに入ってきてもいないようです。
BiometricPromptでPINを利用するには、どのようにCallbackを受け取ればよいのでしょうか?
参考
あなたの回答
tips
プレビュー