Code

Code

วันพฤหัสบดีที่ 21 เมษายน พ.ศ. 2559

ANDROID : Fingerprint API Tutorial [การใช้งาน Fingerprint Unlock]




 เริ่มจากอธิบายก่อน Fingerprint API เพิ่งจะเพิ่มมาใน API Level 23 หรือ Android M เพราะฉะนั้นหากต่ำกว่านั้นจะไม่สามารถเรียกใช้งานได้ (แต่ใน Samsung galaxy s6 : Lollipop นั้น samsung เขียน library ขึ้นมาเอง สามารถตามไปศึกษาได้ที่ http://developer.samsung.com/resources/pass ) แต่ใน blog นี้เราจะมาเรียนรู้ fingerprint api ที่ android พัฒนาขึ้นมาเอง และเราต้องใช้ fingerprint ของเครื่อง ไม่สามารถจะสร้างลายนิ้วมือได้เอง ต้องไปเปิดการใช้งานและเพิ่มลายนิ้วมือใน setting ของเครื่องก่อน งั้นเรามาเริ่มกันเลย



   เพิ่ม permission : USE_FINGERPRINT ใน AndroidManifest.xml

<uses-permission android:name="android.permission.USE_FINGERPRINT" />

กลับมาที่ Activity หลักของเราเริ่มจากประกาศตัวแปรที่เราจะใช้งาน

private FingerprintManager fingerprintManager;
private KeyguardManager keyguardManager;

ตรวจสอบเวอร์ชั่นเครื่องว่ารองรับการใช้งาน fingerprint ไหม
* isHardwareDetected จะขึ้นแดงเตือนให้ checkPermission ไม่ต้องเช็คก็ได้นะครับ เพราะไม่ได้อยู่ในกลุ่ม dangerous permissions สามารถไปดูว่า permission ตัวไหนอยู่ในกลุ่ม normal หรือ dangerous จากตรงนี้ http://developer.android.com/guide/topics/security/permissions.html#normal-dangerous

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
.
.
.
        //เช็คเวอร์ชั่นของเครื่องต้อง >= 6.0 M จึงจะใช้งาน fingerprintManager ได้
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
            fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);

            if (fingerprintManager.isHardwareDetected()) {
                // Device support fingerprint authentication
                setupFingerPrint();
            }else{
               txtTitle.setText("Please fill password");
            }

        } else {
            txtTitle.setText("Please fill password");
        }
}


หลักจากตรวจสอบแล้วว่า fingerprint สามารถใช้งานได้ก็เริ่มทำเมธอด setupFingerPrint() ถ้าไม่รองรับ fingerprint ก็ให้ title แสดง Please fill password

private void setupFingerPrint() {
        if (!keyguardManager.isKeyguardSecure()) {
            // Show a message that the user hasn't set up a fingerprint or lock screen.
            Toast.makeText(this,
                    "Secure lock screen hasn't set up.\n"
                            + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint",
                    Toast.LENGTH_LONG).show();
            return;
        }

        if (!fingerprintManager.hasEnrolledFingerprints()) {
            // This happens when no fingerprints are registered.
            Toast.makeText(this,
                    "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
                    Toast.LENGTH_LONG).show();
            return;
        }
    }

อธิบาย
 - keyguardManager.isKeyguardSecure() ตรวจสอบว่าเครื่องได้เปิดการใช้งาน fingerprint ไหม ถ้าไม่ก็ให้แสดงข้อความ
- fingerprintManager.hasEnrolledFingerprints() ตรวจสอบว่าเครื่องได้มีการเพิ่มลายนิ้วมือแล้วหรือยัง ถ้าไม่ก็ให้แสดงข้อความ

หากตรวจสอบแล้วว่าเครื่องเปิดใช้งาน fingerprint และ มีลายนิ้วมือในระบบแล้วก็มาทำ createKey หากจะอัพขึ้นสโตร์ให้เปลี่ยนชื่อ my_key เป็น ชื่อ alias ของ keystore ด้วยนะครับ


/**
     * Alias for our key in the Android Key Store
     */
    private static final String KEY_NAME = "my_key";
    private KeyStore keyStore;
    private KeyGenerator keyGenerator;


/**
     * Creates a symmetric key in the Android Key Store which can only be used after the user has
     * authenticated with fingerprint.
     */
    public void createKey() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
            // for your flow. Use of keys is necessary if you need to know if the set of
            // enrolled fingerprints has changed.

            try {
                keyStore = KeyStore.getInstance("AndroidKeyStore");
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                keyGenerator = KeyGenerator.getInstance(
                        KeyProperties.KEY_ALGORITHM_AES,
                        "AndroidKeyStore");
            } catch (NoSuchAlgorithmException |
                    NoSuchProviderException e) {
                throw new RuntimeException(
                        "Failed to get KeyGenerator instance", e);
            }

            try {
                keyStore.load(null);
                // Set the alias of the entry in Android KeyStore where the key will appear
                // and the constrains (purposes) in the constructor of the Builder
                keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME,
                        KeyProperties.PURPOSE_ENCRYPT |
                                KeyProperties.PURPOSE_DECRYPT)
                        .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                        // Require the user to authenticate with a fingerprint to authorize every use
                        // of the key
                        .setUserAuthenticationRequired(true)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                        .build());
                keyGenerator.generateKey();
                Log.d("main", "createKey: keyGenerate");
            } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
                    | CertificateException | IOException e) {
                throw new RuntimeException(e);
            }
        }

และต่อด้วย Cipher

/**
     * Initialize the {@link Cipher} instance with the created key in the {@link #createKey()}
     * method.
     *
     * @return {@code true} if initialization is successful, {@code false} if the lock screen has
     * been disabled or reset after the key was generated, or if a fingerprint got enrolled after
     * the key was generated.
     */
    private boolean initCipher() {
        try {
            cipher = Cipher.getInstance(
                    KeyProperties.KEY_ALGORITHM_AES + "/"
                            + KeyProperties.BLOCK_MODE_CBC + "/"
                            + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException |
                NoSuchPaddingException e) {
            throw new RuntimeException("Failed to get Cipher", e);
        }

        try {
            keyStore.load(null);
            SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME, null);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return true;
        } catch (KeyPermanentlyInvalidatedException e) {
            return false;
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
                | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to init Cipher", e);
        }
    }

แล้วก็สร้าง class FingerprintHelper ขึ้นมาเพื่อตรวจสอบลายนิ้วมือ

public class FingerprintHelper extends FingerprintManager.AuthenticationCallback {

    private CancellationSignal cancellationSignal;
    private Context context;

    public FingerprintHelper(Context context) {
        this.context = context;
    }

    //เริ่มตรวจสอบลายนิ้วมือ
    public void startAuth(FingerprintManager manager,
                          FingerprintManager.CryptoObject cryptoObject) {

        cancellationSignal = new CancellationSignal();

        if (ActivityCompat.checkSelfPermission(context,
                Manifest.permission.USE_FINGERPRINT) !=
                PackageManager.PERMISSION_GRANTED) {
            return;
        }
        manager.authenticate(cryptoObject, cancellationSignal, 0, this, null);
    }
    //หยุดตรวจสอบลายนิ้วมือ
    public void stopListening() {
        if (cancellationSignal != null) {
            cancellationSignal.cancel();
            cancellationSignal = null;
        }
    }

    @Override
    public void onAuthenticationError(int errorCode, CharSequence errString) {
        super.onAuthenticationError(errorCode, errString);
        Log.e("FingerprintHelper", "onAuthenticationError:" + errString );
    }


    @Override
    public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
        super.onAuthenticationHelp(helpCode, helpString);
        Toast.makeText(context,
                "Authentication help\n" + helpString,
                Toast.LENGTH_LONG).show();
    }

    @Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        super.onAuthenticationSucceeded(result);

        new AlertDialog.Builder(context)
                .setCancelable(false)
                .setMessage("Fingerprint Authentication succeeded")
                .setPositiveButton("ok", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        ((MainActivity) context).onResume();
                    }
                }).show();
    }

    @Override
    public void onAuthenticationFailed() {
        super.onAuthenticationFailed();
        Toast.makeText(context,
                "Authentication failed.",
                Toast.LENGTH_LONG).show();
    }


}

จากนั้นก็เรียกใช้งานในเมธอด setupFingerprint

private FingerprintManager.CryptoObject cryptoObject;
private FingerprintHelper fingerprintHelper;

private void setupFingerPrint() {
        if (!keyguardManager.isKeyguardSecure()) {
            // Show a message that the user hasn't set up a fingerprint or lock screen.
            Toast.makeText(this,
                    "Secure lock screen hasn't set up.\n"
                            + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint",
                    Toast.LENGTH_LONG).show();
            return;
        }

        if (!fingerprintManager.hasEnrolledFingerprints()) {
            // This happens when no fingerprints are registered.
            Toast.makeText(this,
                    "Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
                    Toast.LENGTH_LONG).show();
            return;
        }
        
        createKey();
        if (initCipher()) {
            cryptoObject = new FingerprintManager.CryptoObject(cipher);
            fingerprintHelper = new FingerprintHelper(this);
        }
    }

แล้วจึง override สองเมธอดนี้เพื่อสั่งให้ fingerprint ทำงานหรือหยุดทำงาน

@Override
    protected void onResume() {
        super.onResume();
        if (fingerprintHelper != null) {
            fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (fingerprintHelper != null) {
            fingerprintHelper.stopListening();
        }
    }

ที่นี้แล้วก็สามารถตรวจสอบแล้วนิ้วมือได้แล้ว หากตรวจสอบลายนิ้วมือตรงกับที่ลงทะเบียนในเครื่องไว้จะแสดง dialog แต่หากไม่ตรงกัน ก็จะ Toast แจ้งเตือน user แล้วหากเครื่องไม่รองรับ fingerprint แหละ เราก็มาทำส่วนของตรวจสอบรหัสผ่าน 4 ตัวกัน เริ่มจาก เมธอด checkPassword()


private void checkPassword(TabLayout.Tab tab) {
        if (tab.getPosition() == 1) {
            String password = editTextPassword.getText().toString().trim();
            // example password = 1234
            if (password.equals("1234")) {
                new AlertDialog.Builder(MainActivity.this)
                        .setCancelable(false)
                        .setMessage("Password Authentication succeeded")
                        .setPositiveButton("ok", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                textInputLayout.setError(null);
                            }
                        }).show();
            } else {
                textInputLayout.setError("Password incorrect");
            }
        }
    }

แล้วจากนั้นก็เรียกใช้งานใน


tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                checkPassword(tab);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                checkPassword(tab);
            }
        });

เป็นอันเสร็จเรียบร้อย

DownloadExampleCode

Reference


1 ความคิดเห็น :

  1. ไม่ระบุชื่อ7 เมษายน 2565 เวลา 20:04

    Want To Be An Android Dev.: Android : Fingerprint Api Tutorial [การใช้งาน Fingerprint Unlock] >>>>> Download Now

    >>>>> Download Full

    Want To Be An Android Dev.: Android : Fingerprint Api Tutorial [การใช้งาน Fingerprint Unlock] >>>>> Download LINK

    >>>>> Download Now

    Want To Be An Android Dev.: Android : Fingerprint Api Tutorial [การใช้งาน Fingerprint Unlock] >>>>> Download Full

    >>>>> Download LINK 0R

    ตอบลบ