Notice
Recent Posts
Recent Comments
Link
투케이2K
304. (AndroidStudio/android/java) 지문 (finger) 인증 수행 클래스 파일 정의 및 사용 방법 정의 실시 본문
Android
304. (AndroidStudio/android/java) 지문 (finger) 인증 수행 클래스 파일 정의 및 사용 방법 정의 실시
투케이2K 2022. 6. 24. 20:52[개발 환경 설정]
개발 툴 : AndroidStudio
개발 언어 : java
[A_Finger : 소스 코드]
import static android.content.Context.FINGERPRINT_SERVICE;
import static android.content.Context.KEYGUARD_SERVICE;
import android.Manifest;
import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
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.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
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;
public class A_Finger {
/**
* // -----------------------------------------
* TODO [클래스 설명]
* // -----------------------------------------
* 1. 지문 인증 수행 클래스
* // -----------------------------------------
* 2. 필요 퍼미션 :
* <uses-permission android:name="android.permission.USE_FINGERPRINT" />
* <uses-permission android:name="android.permission.USE_BIOMETRIC"/>
* // -----------------------------------------
* 3. 제약 조건 :
* 안드로이드 디바이스 기기내 지문인증 기능을 사용하기 위해서는 마시멜로 버전 이상이어야합니다
* 지문인증 기능을 사용하기 위해서는 안드로이드 시스템 설정 내에 보안 설정 >> 잠금 설정 >> 지문 설정이되어야합니다
* // -----------------------------------------
* */
/**
* // -----------------------------------------
* TODO [호출 및 사용 방법]
* // -----------------------------------------
* 1. 브로드 캐스트 알림 채널 등록 : onCreate
*
* try {
* IntentFilter filter = new IntentFilter(); // [인텐트 필터 선언]
* filter.addAction(A_Finger.FINGER_AUTH_CHANNER); // [푸시 알림 받기 위함]
* LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mMessageReceiver, filter); // [알림을 받는 리시버 지정]
* }
* catch (Exception e){
* e.printStackTrace();
* }
* // -----------------------------------------
* 2. 브로드 캐스트 알림 채널 해제 : onDestroy
*
* try {
* LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mMessageReceiver);
* }
* catch (Exception e){
* e.printStackTrace();
* }
* // -----------------------------------------
* 3. 실시간 지문 인증 성공 상태 알림 리시버 등록
*
* private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
* @Override
* public void onReceive(Context context, Intent intent) {
*
* // [특정 채널에서 푸시 알림을 받은 경우]
* if(A_Finger.FINGER_AUTH_CHANNER.equals(String.valueOf(intent.getAction()))) {
*
* // [인텐트로 전달 받은 메시지 확인]
* String message = String.valueOf(intent.getStringExtra("message"));
*
* // [지문 인증 성공 인지 확인 실시]
* if (A_Finger.SUCCESS_FINGER.equals(message)){ // [지문 인증 성공한 경우]
*
* }
* }
* }
* };
* // -----------------------------------------
* 4. 지문 인증 기능 호출 실시 :
*
* new A_Finger().FingerStart(getActivity());
* // -----------------------------------------
* */
// TODO [지문 인증에 필요한 객체 선언 실시]
private static final String KEY_NAME = "simpleAuth_twok_key";
private FingerprintManager fingerprintManager;
private KeyguardManager keyguardManager;
private KeyStore keyStore;
private KeyGenerator keyGenerator;
public static Cipher cipher;
private FingerprintManager.CryptoObject cryptoObject;
// TODO [팝업창 사용을 위해 객체 정의 및 알림 표시 내용 정의]
AlertDialog.Builder builder;
AlertDialog alertDialog;
private static final String AL_TITLE = "알 림";
private static final String AL_OK = "확 인";
private static final String AL_NO = "취 소";
// TODO [전역 변수 선언 실시]
private static final String USE_NO_DEVICE = "지문을 사용할 수 없는 디바이스 입니다.";
private static final String PERMISSON_IS_NO = "지문 인증 사용을 허용해 주세요.";
private static final String DEVICE_LOCK_NO = "지문 인증을 사용하기 위해서는 디바이스 잠금 화면을 설정해 주세요.";
private static final String FINGER_REG_NO = "잠금 설정에 등록된 지문이 없습니다. 지문을 먼저 등록해주세요.";
private static final String FINGER_START_MSG = "손가락을 지문인식 센서에 대 주세요.";
private static final String VER_NO_DEVICE = "지문을 사용할 수 없는 하위 버전의 디바이스 입니다.";
private static final String FAIL_FINGER = "지문 인증 실패 ... 다시 시도해주세요.";
public static final String SUCCESS_FINGER = "지문 인증에 성공했습니다.";
public static final String FINGER_AUTH_CHANNER = "FINGER_AUTH_CHANNER"; // [브로드 캐스트 알림 채널]
// TODO [모바일 버전 확인 및 지문인증 수행 메소드]
public void FingerStart(Context mContext){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ // TODO [안드로이드 마시멜로우 부터 사용 가능]
//TODO [Manifest에 Fingerprint 퍼미션을 추가해 워야 사용가능]
fingerprintManager = (FingerprintManager) mContext.getSystemService(FINGERPRINT_SERVICE);
keyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
//TODO [지문을 사용할 수 없는 디바이스인 경우]
if(!fingerprintManager.isHardwareDetected()){
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(USE_NO_DEVICE)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
USE_NO_DEVICE,
AL_OK,
""
);
}
//TODO [지문 인증 사용을 거부한 경우]
else if(ContextCompat.checkSelfPermission(mContext,
Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED){
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(PERMISSON_IS_NO)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
PERMISSON_IS_NO,
AL_OK,
""
);
}
//TODO [잠금 설정에 등록된 지문이 없는 경우]
else if(!keyguardManager.isKeyguardSecure()){
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(DEVICE_LOCK_NO)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
DEVICE_LOCK_NO,
AL_OK,
""
);
}
//TODO [잠금 설정에 등록된 지문이 없는 경우]
else if(!fingerprintManager.hasEnrolledFingerprints()){
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(FINGER_REG_NO)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
FINGER_REG_NO,
AL_OK,
""
);
}
//TODO [모든 관문을 성공적으로 통과 (지문인식을 지원하고 지문 사용이 허용되어 있고 잠금화면이 설정되었고 지문이 등록되어 있을때)]
else {
Log.i("---","---");
Log.w("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(FINGER_START_MSG)+"]");
Log.w("//===========//","================================================");
Log.i("---","---");
//TODO [지문 인증 실행]
generateKey();
if(cipherInit()){
cryptoObject = new FingerprintManager.CryptoObject(cipher);
// [핸들러 실행]
C_FingerprintHandler fingerprintHandler = new C_FingerprintHandler(mContext);
fingerprintHandler.startAutho(fingerprintManager, cryptoObject);
}
// [디자인 표시 Alert 팝업창 알림 실시]
showAuthAlert(
mContext,
FINGER_START_MSG
);
}
}
else{ //TODO [디바이스가 마시멜로 이하인 경우]
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> FingerStart :: 모바일 버전 확인 및 지문 인증 수행 실시]");
Log.i("","\n"+"[결 과 :: "+String.valueOf(VER_NO_DEVICE)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
VER_NO_DEVICE,
AL_OK,
""
);
}
}
//TODO [암호화 된 지문 관리자를 만드는 데 사용할 암호를 초기화 메소드]
@RequiresApi(api = Build.VERSION_CODES.M)
public boolean cipherInit(){
Log.i("---","---");
Log.d("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> cipherInit :: 지문 인증 암호 초기화 수행 실시]");
Log.d("//===========//","================================================");
Log.i("---","---");
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);
}
}
//TODO [비밀 키를 생성하는 메소드]
@RequiresApi(api = Build.VERSION_CODES.M)
protected void generateKey() {
Log.i("---","---");
Log.d("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> generateKey :: 지문 인증 비밀키 생성 수행]");
Log.d("//===========//","================================================");
Log.i("---","---");
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);
keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
keyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | CertificateException | IOException e){
throw new RuntimeException(e);
}
}
//TODO [지문 인식 수행 부분]
@RequiresApi(api = Build.VERSION_CODES.M)
public class C_FingerprintHandler extends FingerprintManager.AuthenticationCallback{
// [지문인식 객체 선언]
CancellationSignal cancellationSignal;
private Context mContext;
// [클래스 생성자 초기화]
public C_FingerprintHandler(Context context){
this.mContext = context;
}
// [지문인식 인증 시작 메소드]
@RequiresApi(api = Build.VERSION_CODES.M)
public void startAutho(FingerprintManager fingerprintManager, FingerprintManager.CryptoObject cryptoObject){
Log.i("---","---");
Log.w("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> startAutho :: 지문 인증 시작 실시]");
Log.w("//===========//","================================================");
Log.i("---","---");
try {
cancellationSignal = new CancellationSignal();
fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, this, null);
}
catch (Exception e){
e.printStackTrace();
}
}
// [지문인식 인증 에러 메소드]
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
this.update(""+errString, false);
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> onAuthenticationError :: 지문 인증 에러 발생]");
Log.i("","\n"+"[Error :: "+String.valueOf(errString.toString())+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [에러 메시지 확인]
String comment = String.valueOf(errString.toString());
/**
* // -----------------------------------
* [주요 에러 메시지 정리]
* // -----------------------------------
* 1) 시도 횟수가 너무 많습니다. 나중에 다시 시도하세요.
* // -----------------------------------
*/
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
comment,
AL_OK,
""
);
}
// [지문인식 인증 실패 메소드]
@Override
public void onAuthenticationFailed() {
this.update("지문인증 실패", false);
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> onAuthenticationFailed :: 지문 인증 실패]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [에러 메시지 확인]
String comment = String.valueOf(FAIL_FINGER);
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
comment,
AL_OK,
""
);
}
// [지문인식 인증 에러 메소드]
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
this.update(""+helpString, false);
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> onAuthenticationHelp :: 지문 인증 실패]");
Log.i("","\n"+"[message :: "+String.valueOf(helpString.toString())+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// [에러 메시지 확인]
String comment = String.valueOf(helpString.toString());
/**
* // -----------------------------------
* [주요 에러 메시지]
* // -----------------------------------
* 1) 손가락을 너무 빨리 움직였습니다. 다시 시도해 주세요.
* // -----------------------------------
* 2) 지문 센서를 깨끗이 닦고 다시 시도하세요.
* // -----------------------------------
*/
// [Alert 팝업창 알림 실시]
showMessageAlert(
mContext,
AL_TITLE,
comment,
AL_OK,
""
);
}
// [지문인식 인증 성공 메소드]
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
this.update(SUCCESS_FINGER, true);
Log.i("---","---");
Log.w("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> onAuthenticationSucceeded :: 지문 인증 성공]");
Log.w("//===========//","================================================");
Log.i("---","---");
}
// [지문인식 인증 중도 취소 메소드]
public void stopFingerAuth(){
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> stopFingerAuth :: 지문 인증 중도 취소]");
Log.e("//===========//","================================================");
Log.i("---","---");
try {
if(cancellationSignal != null && !cancellationSignal.isCanceled()){
cancellationSignal.cancel();
}
}
catch (Exception e){
e.printStackTrace();
}
}
// [지문인식 인증 진행 후 동적 콘텐츠 변경 메소드]
private void update(String message, boolean success) {
Log.i("---","---");
Log.e("//===========//","================================================");
Log.i("","\n"+"[A_Finger > stopFingerAuth : 지문 인증 진행 확인]");
Log.i("","\n"+"[success :: "+String.valueOf(success)+"]");
Log.i("","\n"+"[message :: "+String.valueOf(message)+"]");
Log.e("//===========//","================================================");
Log.i("---","---");
// TODO [지문인증 성공한 경우]
if(success == true) {
// [Alert 팝업창 알림 실시]
/*
showMessageAlert(
mContext,
AL_TITLE,
message,
AL_OK,
""
);
// */
// TODO [지문 인증 성공 알림 전달]
try {
Intent intent = new Intent(FINGER_AUTH_CHANNER); // [채널 명칭 지정]
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); // [플래그 설정]
intent.putExtra("message", String.valueOf(message)); // [데이터 전달]
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); // [브로드 캐스트 알림 전달]
}
catch (Exception e){
e.printStackTrace();
}
// TODO [활성화된 팝업창이 있으면 종료 수행 실시]
try {
if (alertDialog != null){
alertDialog.dismiss(); // [다이얼로그가 활성화 되어있으면 취소]
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
} // TODO [내부 클래스 종료]
// TODO [메시지 팝업창 호출 실시]
public void showMessageAlert(Context mContext, final String title, final String content, final String ok, final String no){
Log.i("---","---");
Log.d("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> showMessageAlert :: 메시지 팝업창 호출 수행 실시]");
Log.i("","\n"+"[title :: "+String.valueOf(title)+"]");
Log.i("","\n"+"[content :: "+String.valueOf(content)+"]");
Log.d("//===========//","================================================");
Log.i("---","---");
// TODO [이미 활성화된 창이 있는지 확인 실시]
try {
if(alertDialog != null){
alertDialog.dismiss(); // [다이얼로그가 활성화 되어있으면 취소]
}
}
catch (Exception e){
e.printStackTrace();
}
try {
// TODO [AlertDialog 팝업창 생성]
builder = new AlertDialog.Builder(mContext);
builder.setTitle(title); // 팝업창 타이틀 지정
//builder.setIcon(R.drawable.ic_launcher_foreground); // 팝업창 아이콘 지정
builder.setMessage(content); // 팝업창 내용 지정
builder.setCancelable(false); // 외부 레이아웃 클릭시도 팝업창이 사라지지않게 설정
builder.setPositiveButton(ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO [확인 버튼 클릭 로직 처리]
}
});
builder.setNegativeButton(no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO [취소 버튼 클릭 로직 처리]
}
});
alertDialog = builder.create();
alertDialog.show();
}
catch (Exception e){
//e.printStackTrace();
Toast.makeText(mContext, content, Toast.LENGTH_SHORT).show();
}
}
// TODO [커스텀 디자인 팝업창 호출 실시]
public void showAuthAlert(Context mContext, final String title){
Log.i("---","---");
Log.d("//===========//","================================================");
Log.i("","\n"+"[A_Finger >> showAuthAlert :: 지문 인증 팝업창 호출 수행 실시]");
Log.i("","\n"+"[title :: "+String.valueOf(title)+"]");
Log.d("//===========//","================================================");
Log.i("---","---");
// TODO [이미 활성화된 창이 있는지 확인 실시]
try {
if(alertDialog != null){
alertDialog.dismiss(); // [다이얼로그가 활성화 되어있으면 취소]
}
}
catch (Exception e){
e.printStackTrace();
}
try {
// TODO [커스텀 디자인 팝업창 레이아웃 지정]
View dialogView=(View)View.inflate(mContext, R.layout.finger_alert,null);
// TODO [AlertDialog 팝업창 생성]
builder = new AlertDialog.Builder(mContext);
builder.setTitle(title); // 팝업창 타이틀 지정
builder.setView(dialogView); // [커스텀 뷰 지정]
alertDialog = builder.create();
alertDialog.show();
}
catch (Exception e){
//e.printStackTrace();
Toast.makeText(mContext, title, Toast.LENGTH_SHORT).show();
}
}
} // TODO [클래스 종료]
[finger_alert.xml : 소스 코드]
<?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:layout_width="100dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="10dp">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_gravity="center"
android:src="@drawable/okfinger"/>
<TextView
android:layout_width="100dp"
android:layout_height="30dp"
android:gravity="center"
android:layout_gravity="center"
android:text=""/>
</LinearLayout>
[결과 출력]
반응형
'Android' 카테고리의 다른 글
Comments