บทความและข่าวสาร | Seven Peaks Insights

เข้าใจการทำงานของ AndroidX Biometric


เขียนโดย Android Developer ผู้มีประสบการณ์ของเรา

 
close-up-hands-holding-smartphone-with-lock_23-2149101163-300x200


เกริ่นนำ

ระบบ biometric authentication (การยืนยันตัวตนด้วยข้อมูลทางชีวภาพ) บนมือถือนั้นมีใช้งานมาหลายปีแล้ว ซึ่งผู้ผลิตอุปกรณ์ก็นิยมนำเทคโนโลยีนี้ไปใช้กันอย่างแพร่หลาย เป็นไปได้ว่าผู้ใช้สมาร์ตโฟนทุกคนน่าจะเคยใช้งาน biometric authentication กันมาบ้างแล้ว ซึ่งเป็นระบบที่แอปพลิเคชันด้านการชำระเงินนิยมนำไปใช้งานเพื่อให้ผู้ใช้ได้รับความสะดวกสบายและมั่นใจในความปลอดภัย

ในฐานะที่ผมเป็นนักพัฒนาก็อยากจะอธิบายในบทความนี้ว่า เราสามารถนำ AndroidX Biometric API อันทรงพลังไปใช้งานกับแอปพลิเคชัน Android แบบง่ายๆ และใช้ประโยชน์มันให้เต็มประสิทธิภาพได้อย่างไร

 

เข้าใจที่มา

FingerPrintManager เป็นคลาสที่เริ่มมีให้ใช้งานตั้งแต่ Android 6.0 (API level 23) ซึ่งเปิดให้เข้าถึงการทำงานของเครื่องสแกนลายนิ้วมือเท่านั้น อย่างไรก็ตาม มันก็ยังไม่มี UI ใดๆ ติดมาไว้เลย นักพัฒนาจึงต้อง implement UI ให้กับอุปกรณ์แต่ละเครื่องขึ้นมาเองเพื่อให้รองรับ biometric authentication ได้ ซึ่งการพัฒนา UI แบบปรับแต่งเองนั้นไม่ใช่เรื่องง่ายๆ เลย ยิ่งไปกว่านั้น เซนเซอร์แบบที่อยู่ในหน้าจอยังทำให้การพัฒนายากยิ่งขึ้นไปอีก

หลังจากที่ได้รับฟีดแบ็กจากนักพัฒนา ทำให้ Android 9 (API level 28) เริ่มนโยบายเกี่ยวกับการพัฒนา UI ของระบบตรวจสอบลายนิ้วมือที่มีมาตรฐานขึ้น นอกจากนั้น BiometricPrompt ยังเข้ามาเสริมในการทำงานของเซนเซอร์ที่รองรับได้มากกว่าแค่ลายนิ้วมือ ซึ่งไม่เพียงแต่ช่วยให้นักพัฒนามีชุดของ API ที่สามารถนำมาปรับปแต่งได้ง่ายๆ เพื่อสร้าง UI ที่ผู้ใช้คุ้นเคยและสอดคล้องกับระบบเท่านั้น แต่ยังช่วยลดความซับซ้อนในการสื่อสารกับฮาร์ดแวร์มากมายที่เกี่ยวข้องกับ biometric บนอุปกรณ์ต่างๆ อีกต่างหาก ทั้งยังทำให้บรรดา OEM ได้รับประโยชน์ไปด้วย เนื่องจากพวกเขาสามารถปรับแต่ง API เหล่านี้เพื่อ implement สไตล์ของตัวเองลงไปและสร้างระบบ biometric ใหม่ๆ ขึ้นมาได้โดยไม่ต้องกังวลว่านักพัฒนาจะปรับตัวตามได้หรือไม่

ใน Android 10 (API level 29) นั้น ทีมงานที่ดูแลด้าน Android Framework และความปลอดภัยได้ปรับปรุง AndroidX Biometric Library  ให้ดียิ่งขึ้น ซึ่งทำให้การตรวจสอบ biometric ทั้งหมดใน Android 10 นั้นสามารถนำไปใช้งานกับอุปกรณ์ทุกชนิดที่รัน Android 6.0 (API level 23) ขึ้นไปได้ นอกจากการรองรับ biometric authentication ที่หลากหลายแล้ว ยังมีการเพิ่ม BiometricManager ขึ้นมาเพื่อช่วยให้นักพัฒนาสามารถเช็กได้ว่าอุปกรณ์นั้นๆ รองรับ biometric authentication หรือไม่ ด้วยการใช้ API เพียงตัวเดียว

 

การรองรับรุ่นเก่าๆ

ตามที่บอกไว้ก่อนหน้านี้ว่า AndroidX Biometric เริ่มมีให้ใช้ใน Android 10 เป็นต้นไป และรองรับการทำงานของ biometric authentication ตั้งแต่ API 23 เป็นต้นไป และการใช้งานรหัสปลดล็อกอื่นๆ อย่างเช่น รหัสผ่าน, PIN, และแพตเทิร์น นั้นก็รองรับย้อนไปถึง API 21 เลยทีเดียว

 

Integration:

เอาละ มาถึงเนื้อหาส่วนที่น่าสนุกกันแล้ว

เราสามารถแบ่ง biometric authentication ออกเป็น 5 ขั้นตอนง่ายๆ ต่อไปนี้

ขั้นตอนที่ 1: เพิ่ม Gradle dependency เข้าไป

เพิ่ม dependency ต่อไปนี้ลงไปในไฟล์ Gradle ที่ app level

implementation "androidx.biometric:biometric:1.1.0"

ขั้นตอนที่ 2: เช็กว่าอุปกรณ์ดังกล่าวรองรับ biometric authentication หรือไม่

Biometric Library ทำให้ BiometricManager สามารถเช็กได้ว่าอุปกรณ์ของผู้ใช้รองรับฟีเจอร์ biometric authentication หรือไม่ ก่อนที่จะสร้างระบบยืนยันตัวตนขึ้นมา ถ้าหากว่าไม่ คุณก็สามารถแสดงข้อความบอกผู้ใช้ได้ว่าอุปกรณ์นั้นๆ ไม่รองรับ biometric authentication

biometricManager.canAuthenticate(int)

ค่า int  นั้นแทนประเภทของระบบยืนยันตัวตนที่คุณต้องการ ซึ่งมีระบบยืนยันตัวตนที่คุณสามารถเลือกใช้งานได้อยู่ 3 ประเภท ได้แก่

  • BIOMETRIC_WEAK สำหรับ non-crypto authentication
  • BIOMETRIC_STRONG สำหรับ crypto-based authentication
  • DEVICE_CREDENTIAL สำหรับ non-biometric Credential

private fun authenticateUser() { val biometricManager = BiometricManager.from(this) when (biometricManager.canAuthenticate(BIOMETRIC_WEAK)) { BiometricManager.BIOMETRIC_SUCCESS -> showBiometricPrompt() BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> showMessage("There is no suitable hardware") BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> showMessage("The hardware is unavailable. Try again later") BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> showMessage("No biometric or device credential is enrolled") BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> showMessage("A security vulnerability has been discovered with one or more hardware sensors") BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> showMessage("The specified options are incompatible with the current Android version") BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> showMessage("Unable to determine whether the user can authenticate") } }

เราสามารถรวม authenticator เหล่านี้ไว้ด้วยกันได้ เช่น BIOMETRIC_WEAK | DEVICE_CREDENTIAL

แต่ว่าไม่ใช่ทุก API ที่สามารถนำมารวมกันได้ ตัวอย่างเช่น DEVICE_CREDENTIAL นั้นไม่รองรับในเวอร์ชันก่อนหน้า API 30 ส่วน BIOMETRIC_STRONG | DEVICE_CREDENTIAL ก็ไม่รองรับใน API 28–29

ขั้นตอนที่ 3: สร้าง UI ด้วย PromptInfo object

PromptInfo object บรรจุ metadata และ configuration ต่างๆ เอาไว้สำหรับ BiometricPrompt ของเรา ซึ่งเราสามารถปรับแต่ง prompt ด้วย method เช่น setTitle, setSubtitle, setDescription และ setNegativeButtonText ได้ การใช้ setAllowedAuthenticatorsทำให้เราสามารถระบุได้ว่าเราอนุญาตให้ใช้รหัสปลดล็อก (PIN, แพตเทิร์น หรือ รหัสผ่าน) เป็น fallback หรือไม่ และใช้ setConfirmationRequired เพื่อเปิดหรือปิดการยืนยันแบบ explicit สำหรับ implicit authentication method เช่น ใบหน้า หรือ ม่านตา ได้ ซึ่งจะเป็นประโยชน์ในสถานการณ์ที่เราต้องการยืนยันการทำธุรกรรมจากผู้ใช้อีกครั้งก่อนที่จะเริ่มกระบวนการ

val promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("AndroidX Biometric") .setSubtitle("Authenticate user via Biometric") .setDescription("Please authenticate yourself here") .setAllowedAuthenticators(BIOMETRIC_WEAK) .setNegativeButtonText("Cancel") .setConfirmationRequired(true) .build()

1_adCwEsEnTZO1n3thB0LQFQ
1_g8g83XR3XAErra2r8XajgA


อย่างไรก็ตาม การแสดงข้อความยืนยันแบบ explicit นั้นขึ้นอยู่กับอุปกรณ์แต่ละเครื่องด้วย ซึ่งทำให้ข้อความยืนยันแบบ explicit จะไม่ได้รับการแสดงในบางอุปกรณ์แม้ว่าจะตั้งค่าไว้เป็น true ผ่านทาง setConfirmationRequired method ก็ตาม

ขั้นตอนที่ 4: สร้าง instance ของ BiometricPrompt ขึ้นมา

AndroidX BiometricPrompt ช่วยคุณทำในเรื่องยากๆ ไปหมดแล้วด้วยการรวบรวม UI metadata, แสดง authentication prompt ให้ผู้ใช้เห็น, และคืนค่าผลลัพธ์ของการยืนยันตัวตนในรูปแบบของ callback โดยมันจำเป็นต้องใช้ 4 component ต่อไปนี้จึงจะทำงานได้

  • activity หรือ fragment หนึ่งตัว เพื่อให้ fragmentManager รู้ว่าจะต้องใช้อะไรในการแสดงไดอะล็อกในการยืนยันตัวตน
  • PromptInfo object ที่บรรจุ UI metadata เอาไว้
  • executor หนึ่งตัวที่กำหนดว่า thread ไหนที่ callback นี้จะต้องรัน ถ้าเราต้องการรัน callback บน UI thread เราก็สามารถใช้ main executor จาก ContextCompat.getMainExecutor() method ได้
  • AuthenticationCallback หนึ่งตัวที่เราสามารถนำมารับผลการยืนยันตัวตนของเราได้ ซึ่ง AuthenticationCallback จะบรรจุ 3 method ที่เราสามารถ override ได้ ซึ่งได้แก่: onAuthenticationSucceeded ที่จะถูกเรียกเมื่อการยืนยันตัวตนสำเร็จ, onAuthenticationFailed ที่จะถูกเรียกเมื่อระบบไม่รู้จัก biometric นั้น (เช่น ใช้นิ้วอื่นวางลงไปบนเซนเซอร์), และ onAuthenticationError ที่จะทำงานเมื่อเกิดข้อผิดพลาดที่ไม่สามารถแก้ไขได้ เช่น เมื่อผู้ใช้ยกเลิกกระบวนการยืนยันตัวตน หรือเมื่อไม่มีข้อมูล biometric บนอุปกรณ์ดังกล่าว, ซึ่ง onAuthenticationFailed จะแตกต่างจาก onAuthenticationSucceeded และ onAuthenticationError ตรงที่มันไม่ใช่ terminal callback ซึ่งหมายความว่า คุณอาจจะได้รับ callback หลายตัวจากการใช้งาน method นี้

private val authCallback = object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { showMessage("Authentication successful") } override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { showMessage("Unrecoverable error => $errString") } override fun onAuthenticationFailed() { showMessage("Could not recognise the user") } } // Step 4 val biometricPrompt = BiometricPrompt(this@MainActivity, ContextCompat.getMainExecutor(this), authCallback)

ขั้นตอนที่ 5: ให้ผู้ใช้ยืนยันตัวตน

ขั้นตอนสุดท้าย คือแสดง biometric prompt ให้ผู้ใช้เห็นและบอกให้ยืนยันตัวตนbiometricPrompt.authenticate(promptInfo)

โดย prompt นี้สามารถยกเลิกได้ด้วยคำสั่ง
biometricPrompt.cancelAuthentication()

แต่ถ้าหากแอปฯ ของคุณต้องการให้ผู้ใช้ยืนยันตัวตนด้วยStrong biometric หรือใช้งานการเข้ารหัสแบบ cryptographic ใน KeyStore คุณควรใช้ authenticate(PromptInfo, CryptoObject)แทน

 

สรุปทิ้งท้าย

พลังของ AndroidX Biometric Library อยู่ที่การลดความยุ่งยากซับซ้อนในการสื่อสารระหว่างเซนเซอร์ biometric authentication หลากหลายประเภท (เช่น ลายนิ้วมือ, ใบหน้า, และม่านตา) ลงได้ และมี API ที่เรียบง่ายให้นักพัฒนาและ OEM สามารถปรับแต่งได้ตามต้องการ อย่างไรก็ตาม ในตอนนี้ยังไม่มีวิธีตรวจสอบว่าอุปกรณ์นั้นๆ มีเซนเซอร์ biometric แบบไหนด้วยการใช้ไลบรารีนี้ ดังนั้น คุณอาจต้องแสดงข้อความให้ผู้ใช้ทราบว่าใช้งานข้อมูล biometric แทนที่จะแสดงข้อความที่เฉพาะเจาะจงอย่างเช่น ลายนิ้วมือ หรือ ใบหน้า เป็นต้น

ผมหวังว่าจะช่วยให้คุณรู้อะไรใหม่ๆ จากบทความนี้ ขอให้สนุกกับการเรียนรู้!

 

เขียนโดย

Sifat UI Haque, Android Tech Lead ที่ Seven Peaks Software

คลิกตรงนี้เพื่อติดตาม Sifat ที่ Medium

คุณคือ software developer กำลังมองหางานใหม่อยู่ใช่ไหม?
มาร่วมเป็นส่วนหนึ่งของทีม developer ชั้นนำกับเราสิ
ดูตำแหน่งที่เปิดรับ