IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android - 指纹识别API示例 -> 正文阅读

[移动开发]Android - 指纹识别API示例

– 前言

需求说明:app经常要验证码验证用户手机号保证安全性,现在想接入指纹识别来代替验证码验证,不支持指纹识别的设备照常用验证码。

了解API

Android在23(Android M 6.0)新增了对指纹识别的硬件支持,应用可以通过调用系统Api实现指纹验证相关功能,相对于传统的手势,密码等验证方式,指纹验证安全性更高,速度也更快。

  • Android 23(Android M 6.0)新增 指纹识别Api:FingerprintManager,开发者通过该Api打开指纹认证时,系统仅会打开设备的指纹模块监听,并不会有UI相关展示,需要开发者根据自身App要求弹出对应的交互流程。
  • Android 28(Android P 9.0)新增 生物识别Api:BiometricManager,推荐替换掉原来的FM,囊括指纹、人脸、虹膜等生物特征识别,不过现阶段只开放了指纹相关。开发者使用该Api进行指纹认证时,系统在会打开设备的指纹模块监听的同时,还会弹出一个系统级的Dialog提示用户正在进行指纹解锁流程。

Goolge提供的API只是指纹跟设备中的指纹库进行比对,得到验证的状态(成功/失败…),无法得到唯一的指纹信息,也就无法绑定账户。 前端提供一个开关,当用户开启指纹后,将状态保存在本地,但每次指纹识别前都要判断满足要求才能正常走流程。


– 认证流程

第零步:在清单文件中申明权限

<!-- 使用生物特征识别、触摸传感器和指纹认证的许可-->
    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>

第一步:判断设备满足认证的前提要求(四步)

  1. Android6.0及以上版本
  2. 判断硬件支持指纹识别
  3. 判断已设置密码锁
  4. 判断至少注册了一个指纹
/**
* 1.>Android 6.0 & 2.支持指纹识别 & 3.已设置开屏密码 & 4.已录入指纹
*/
private boolean isSupportFingerprint(){
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            Toast.makeText(mContext, "系统版本过低,不支持指纹功能", Toast.LENGTH_SHORT).show();
            return false;
        } else {
            KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
            fingerprintManager = (FingerprintManager)getSystemService(FINGERPRINT_SERVICE);
            if (fingerprintManager == null || !fingerprintManager.isHardwareDetected()) {
                Toast.makeText(mContext, "您的系统不支持指纹功能", Toast.LENGTH_SHORT).show();
                return false;
            } else if (keyguardManager != null && !keyguardManager.isKeyguardSecure()) {
                Toast.makeText(mContext, "请在设置界面开启锁屏密码,并录入指纹后再尝试", Toast.LENGTH_LONG).show();
                return false;
            } else if (!fingerprintManager.hasEnrolledFingerprints()) {
            	
                Toast.makeText(mContext, "您还没有录入指纹, 请在系统设置录入至少一个指纹", Toast.LENGTH_LONG).show();
                return false;
            }
            return true;
        }

第二步:两种设备调用不同的指纹管理类

判断版本在9.0以上还是以下,以上用FingerprintManager类进行指纹识别,并自定义监听时的Dialog,以下用BiometricManager类进行指纹识别,自动调用系统Dialog。

1.两种流程

private void selectMode(String num){
	if(isSupportFingerprint()){
		//9.0以上
		if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
	        overallIdentification();
	    }else {
	    	//6.0~9.0 自定义的Dialog和回调接口
	    	FingerprintDialogFragment dialogFragment = new FingerprintDialogFragment();
	    	dialogFragment.setArguments(bundle);
	    	dialogFragment.showNow(getSupportFragmentManager(),"FingerprintDialogFragment");
	    	dialogFragment.setClickCallBack(new FingerprintDialogFragment.ClickCallBack() {
	    		@Override
	    		public void clickCancel() {
	    			dialogFragment.dismiss();
	    		}
	    		@Override
	    		public void clickConfirm() {
	    			dialogFragment.dismiss();
	    			//...
	    		}
	   		});
		}
    }
}

2. <9.0指纹识别、创建Dialog:FingerprintDialogFragment

1)xml文件

在这里插入图片描述

2)准备密钥:访问Android密钥库并生成用于加密数据的密钥
3)根据密钥生成密码
4)创建指纹认证回调接收事件通知 FingerprintHandler
public class FingerprintDialogFragment extends DialogFragment{
	//只放关键代码...
    private ClickCallBack clickCallBack;
    private Context mContext;
    public final String KEY_NAME = "fingerprintKey";
    private FingerprintHandler fph;
    private FingerprintManager.CryptoObject cryptoObject;
    private FingerprintManager fingerprintManager;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initWindow();
        initView();
        mContext = getContext();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            fingerprintManager = (FingerprintManager)mContext.getSystemService(FINGERPRINT_SERVICE);
            fph = new FingerprintHandler(tvInfo);
            initStart();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void initStart() {
        generateKey();
        //开启指纹验证
        fph.doAuth(fingerprintManager, cryptoObject);
    }

    //准备密钥
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void generateKey() {
        try {
            //生成用于加密数据的非对称密钥
            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
            //密钥生成器
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
            //初始化密钥生成器
            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();
            Cipher cipher = generateCipher(keyStore);
            cryptoObject = new FingerprintManager.CryptoObject(cipher);
        } catch (NoSuchAlgorithmException| NoSuchPaddingException | InvalidKeyException | UnrecoverableKeyException  | KeyStoreException exc) {
            exce.printStackTrace();
        }
    }

    // 生成密码
    private Cipher generateCipher(KeyStore keyStore) {
        try {
            Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
            SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,null);//算法
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher;
        } catch (NoSuchAlgorithmException| NoSuchPaddingException | InvalidKeyException | UnrecoverableKeyException  | KeyStoreException exc) {
            exc.printStackTrace();
        }
        return null;
    }

    // 指纹认证回调:接收事件通知,并且可以知道何时身份验证成功或出现问题
    @RequiresApi(api = Build.VERSION_CODES.M)
    class FingerprintHandler extends FingerprintManager.AuthenticationCallback {
        private TextView tv;

        public FingerprintHandler(TextView tv) {
            this.tv = tv;
        }

        @Override
        public void onAuthenticationError(int errorCode, CharSequence errString) {
            super.onAuthenticationError(errorCode, errString);
            if (errorCode == 1) {
                tv.setTextColor(Color.parseColor("#C8374A"));
                tv.setText(errString + "请录入指纹");
            }else if(errorCode != 5){
                tv.setTextColor(Color.parseColor("#C8374A"));
                tv.setText(errString);
            }
        }

        @Override
        public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
            super.onAuthenticationHelp(helpCode, helpString);
            LogUtils.d("Fingerprint---helpCode:-"+helpCode+"---helpString:"+helpString);
            tv.setTextColor(Color.parseColor("#C8374A"));
            tv.setText(helpString);

        }

        @Override
        public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
            super.onAuthenticationSucceeded(result);
            tv.setTextColor(Color.parseColor("#0c0c0c"));//#C8374A 请触摸指纹传感器
            tv.setText("验证成功");
            if(type==1){
                EventBus.getDefault().post(new FingerprintGoDealBean());
            }else if(type==2){
                EventBus.getDefault().post(new FingerprintTransferBean());
            }
            FingerprintDialogFragment.this.dismiss();
        }

        @Override
        public void onAuthenticationFailed() {//失败次数过多会中止响应一段时间而后再中止sensor的工作
            super.onAuthenticationFailed();
            LogUtils.d("Fingerprint---验证失败-");
            tv.setTextColor(Color.parseColor("#C8374A"));//#C8374A 请触摸指纹传感器
            tv.setText("验证失败");
        }

        public void doAuth(FingerprintManager manager, FingerprintManager.CryptoObject obj) {
            CancellationSignal signal = new CancellationSignal();
            try {
                manager.authenticate(obj, signal, 0, this, null);
            } catch (SecurityException sce) {
            }
        }
    }


    private void initView() {
        tvCancel.setOnClickListener(v -> clickCallBack.clickCancel());
        tvConfirm.setOnClickListener(v -> clickCallBack.clickConfirm());
    }

    interface ClickCallBack {
        void clickCancel();
        void clickConfirm();
    }

    public void setClickCallBack(ClickCallBack clickCallBack) {
        this.clickCallBack = clickCallBack;
    }

    private void initWindow() {
        setCancelable(false);
        Window window = getDialog().getWindow();
        //ColorDrawable(Color.TRANSPARENT)
        window.setBackgroundDrawableResource(R.drawable.shape_body_white_10);
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.width = 800;//280dp
        lp.gravity = Gravity.CENTER;
        window.setAttributes(lp);
    }

}

2. >9.0指纹识别

系统提供的Dialog:(每个厂商不一样)
在这里插入图片描述
在这里插入图片描述

已知的错误状态码errorCode含义:1目前不可用,稍后再试、3超时(与设备和传感器类型有关)、4设备可用存储空间不足、5取消验证、7失败次数太多等待30s、9失败太多次生物验证锁定、10中途取消、13点击了negative button

	@RequiresApi(api = Build.VERSION_CODES.P)
    private void overallIdentification(){
        BiometricPrompt prompt = new BiometricPrompt.Builder(mContext).setTitle("指纹验证").setSubtitle(" ").setDescription("请触摸指纹传感器")
                .setNegativeButton("使用验证码", command -> {
                	//点击监听...
                }, (dialog, which) -> {
                }).build();
        BiometricPrompt.AuthenticationCallback callback = new BiometricPrompt.AuthenticationCallback() {
            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                ToastUtils.showMessage("验证失败");
            }

            @Override
            public void onAuthenticationError(int errorCode, CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                if(errorCode!=10){
                    ToastUtils.showMessage(errString+"");
                }
            }

            @Override
            public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
                super.onAuthenticationHelp(helpCode, helpString);
                ToastUtils.showMessage(helpString+"");
            }

            @Override
            public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                //认证成功...
            }
        };
        CancellationSignal signal = new CancellationSignal();
        //唤起指纹认证界面:展示验证对话框,调用基于加密的身份验证。
        prompt.authenticate(signal,mContext.getMainExecutor(),callback);
    }

参考博客:
https://cloud.tencent.com/developer/article/1474404
https://www.jianshu.com/p/74fb11da9a41
https://blog.csdn.net/qq_34676644/article/details/118758483

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-26 15:21:10  更:2022-05-26 15:21:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 1:02:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码