본문 바로가기
MOBILE/Android

안드로이드 지문인식 사용하는 방법

by 지구 2018. 8. 3.

android 에서 printfinger 사용하는 방법 (API 23이상, Mashmellow 이상부터 사용가능)

참고사이트1 :  https://munkijung1992.postype.com/post/1696370

참고사이트2 : http://altongmon.tistory.com/496


                                      


이렇게 지문을 띄워서 맞으면 성공처리를, 틀리면 TextView 가 흔들리는 Animaion 과 함께 Toast 를 띄웠다.


사용자마다 지문을 DB 나 SharePreference 에 등록하여 지문로그인을 구현해볼까도 했지만,

스케줄 상 일단 지문일치여부 구현만으로도 만족..!


그리고, 지문인식을 사용하기 위해 찾아보니 그나마 많이 쓰는 라이브러리가 있대서 사용하려했지만

자꾸 Gradle 에서 Compile 이 안되어가지고 직접 구현했다 ㅠ.ㅠ



* 사용방법 *

1. AndroidManifest.xml 에 지문인식 권한을 위한 퍼미션 추가

1
2
<!-- 지문인식에 필요함 -->
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
cs


2. 다이얼로그로 띄울 예정이므로 보여줄 res-layout 에 dialog_fingerprint.xml 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:padding="5dp">
 
    <ImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        app:srcCompat="@drawable/fingerprint" />
 
    <TextView
        android:id="@+id/dialog_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingBottom="20dp"
        android:paddingTop="20dp"
        android:text="정말 탈퇴하시겠습니까?" />
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <Button
            android:id="@+id/dialog_cancel"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_gravity="center"
            android:background="@drawable/button_radius"
            android:text="취소"
            android:textColor="@color/color_white" />
 
        <Button
            android:id="@+id/dialog_submit"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="@drawable/button_radius"
            android:text="안보여야함"
            android:textColor="@color/color_white"
            android:visibility="gone"/>
 
        <!-- style="?android:attr/borderlessButtonStyle" -->
    </LinearLayout>
 
</LinearLayout>
cs


3. 지문인식을 사용할 Activity 나 Fragment 상단에 필드값을 선언해주고

1
2
3
//지문인식 관련 필드
TextView shakeText;
CustomDialog customDialog;
cs


4. 지문인식을 사용할 Activity 나 Fragment 에 이벤트리스너가 있다면 그 안에 다이얼로그를 띄울 5,6 번째 줄을 추가해준다.

1
2
3
4
5
6
7
8
//회원탈퇴 버튼 => 지문인식으로 본인확인
((Button)getView().findViewById(R.id.mypage_quit)).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        customDialog = new CustomDialog(getContext(),R.layout.dialog_fingerprint);
        customDialog.show();
    }
});
cs


5. 지문인식을 사용할 Activity 나 Fragment 하단에 정의해둔 custom 메소드를 추가해준다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class CustomDialog extends Dialog {
        Button btn;
        EditText editPass;
 
        public CustomDialog(final Context context, int layoutResID) {
            super(context);
 
            if(layoutResID==R.layout.dialog_fingerprint){
                FingerPrint fingerPrint = new FingerPrint(getContext());
                if(fingerPrint.isFingerHarWare()){
                    if(fingerPrint.isFingerPassCode()){
                        fingerPrint.initalize(new FingerprintManager.AuthenticationCallback() {
                            @Override //지문인증에 치명적인 오류가 발생하면 호출
                            public void onAuthenticationError(int errMsgId, CharSequence errString) {
                                Toast.makeText(getContext(), "Authentication error\n" + errString, Toast.LENGTH_SHORT).show();
                            }
                            @Override //오류가 발생하면 호출되지만 치명적인 예외는 아님
                            public void onAuthenticationHelp(int helpMsgId,CharSequence helpString) {
                                Toast.makeText(getContext(), "Authentication help\n" + helpString, Toast.LENGTH_SHORT).show();
                            }
                            @Override //장치에 등록 된 지문이 아닌 경우 호출
                            public void onAuthenticationFailed() {
                                Toast.makeText(getContext(), "등록되지 않은 지문입니다.", Toast.LENGTH_SHORT).show();
                                //틀렸을 시 텍스트 좌우로 흔들어주기
                                Animation shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
                                shakeText = (TextView)findViewById(R.id.dialog_text);
                                shakeText.startAnimation(shake);
                            }
                            @Override //장치에 등록 된 지문이 스캔되었을 때 호출
                            public void onAuthenticationSucceeded( FingerprintManager.AuthenticationResult result) {
                                clientSocketThread = new ClientSocketThread(handler, "quitUser", userVO);
                                clientSocketThread.start();
                                dismiss();
                            }
                        });
                    }else{
                        startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
                    }
                }
            }
            //getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));  //다이얼로그의 배경을 투명으로 만듦
            requestWindowFeature(Window.FEATURE_NO_TITLE);   //다이얼로그의 타이틀바를 없애줌
            setContentView(layoutResID);     //다이얼로그에서 사용할 레이아웃
 
            //취소버튼 => 지문인식에 있음
            ((Button)findViewById(R.id.dialog_cancel)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    dismiss();
                }
            });
            //확인버튼 => 비밀번호변경에 있음
            ((Button)findViewById(R.id.dialog_submit)).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    editPass = (EditText)findViewById(R.id.dialog_edit_password);
 
                    userVO.setPassword(editPass.getText().toString());
                    clientSocketThread = new ClientSocketThread(handler, "updateUser", userVO);
                    clientSocketThread.start();
                    Toast.makeText(getContext(), "정상적으로 변경되었습니다.", Toast.LENGTH_SHORT).show();
                    dismiss();
                }
            });
        }
    } //e.o.CustomDialog
cs


6. 마지막으로 지문인식 사용을 위해 FingerprintManager 와 Keystore 와 KeyGenerator 와 Cipher 를 사용할 클래스를 생성해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package com.nadri.util;
 
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.CancellationSignal;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
 
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
 
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
 
//지문인식 기능은 6.0 이상부터 지원되어 실제 우리 어플에서 사용가능하다는 의미로 선언
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerPrint {
 
    private static final String KeyName = "yourKeyPassword";
    private static final String AndroidKeyStore = "AndroidKeyStore";
 
    private Context mContext;
    private FingerprintManager fingerprintManager;
    private FingerprintManager.CryptoObject cryptoObject;
    private KeyStore keyStore;
    private KeyGenerator keyGenerator;
    private Cipher cipher;
 
    //생성자
    public FingerPrint(Context mContext) {
        this.mContext = mContext;
        setKeyStore();
    }
 
    //콜백 초기화 메소드
    public void initalize(FingerprintManager.AuthenticationCallback callback) {
        CancellationSignal cancellationSignal = new CancellationSignal(); //취소신호
        fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, callback, null);
    }
 
    //하드웨어 지원 가능 여부
    public boolean isFingerHarWare(){
        return fingerprintManager.isHardwareDetected();
    }
 
    //하드웨어 현재 지문 여부
    public boolean isFingerPassCode(){
        return fingerprintManager.hasEnrolledFingerprints();
    }
 
    //KeyStore 세팅
    private void setKeyStore() {
        //FingerPrint Manager Setting
        fingerprintManager = (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE);
        cryptoObject = new FingerprintManager.CryptoObject(cipher);
 
        //keyStore //표준 android 키 저장소 컨테이너 식별자 ("AndroidKeyStore")를 사용하여 키 저장소에 대한 참조를 가져옴
        try {
            keyStore = KeyStore.getInstance(AndroidKeyStore);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        //keyGenerator
        try {
            //key 생성
            keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, AndroidKeyStore);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        //keyGenerator initalize //새 개인 키 생성
        try {
            //빈 ketStore 초기화
            keyStore.load(null);
 
            //keyGenerator 초기화
            keyGenerator.init(new KeyGenParameterSpec.Builder(KeyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                    .build());
 
            //key 생성
            keyGenerator.generateKey();
 
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        // cipher initalize
        try {
            cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        // cipher set Key
        try {
            keyStore.load(null);
            SecretKey key = (SecretKey) keyStore.getKey(KeyName, null);
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } catch (KeyPermanentlyInvalidatedException e) {
            e.printStackTrace();
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
        }
    }
 
}
 
cs


7. 위에까지 하면 되지만, 틀렸을 때 텍스트뷰가 흔들리는 애니메이션을 보여주기 위해 res 에 anim 폴더를 만들고 shake.xml 을 생성해주면 정말 끝!

1
2
3
4
5
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0" android:toXDelta="10" android:duration="500"
    android:interpolator="@anim/cycle_3" />
 
<!-- 0.5초 동안 X10 만큼 3번 흔들어라 -->
cs


반응형

댓글