Android 指纹识别(给应用添加指纹解锁)

使用指纹

说明 : 指纹解锁在23 的时候,官方就已经给出了api ,但是由于Android市场复杂,无法形成统一,硬件由不同的厂商开发,导致相同版本的软件系统,搭载的硬件千变万化,导致由的机型不支持指纹识别,但是,这也挡不住指纹识别在接下来的时间中进入Android市场的趋势,因为它相比较输入密码或图案,它更加简单,相比较密码或者图案,它更炫酷 ,本文Demo 使用最新的28 支持的androidx 库中的API及最近火热的kotlin语言完成的


 需要知道的

  1. FingerprintManager : 指纹管理工具类
  2. FingerprintManager.AuthenticationCallback :使用验证的时候传入该接口,通过该接口进行验证结果回调
  3. FingerprintManager.CryptoObject: FingerprintManager 支持的分装加密对象的类

 以上是28以下API 中使用的类 在Android 28版本中google 宣布使用Androidx 库代替Android库,所以在28版本中Android 推荐使用androidx库中的类 所以在本文中我 使用的是推荐是用的FingerprintManagerCompat 二者的使用的方式基本相似


如何使用指纹

  • 开始验证 ,系统默认的每段时间验证指纹次数为5次 次数用完之后自动关闭验证,并且30秒之内不允行在使用验证

验证的方法是authenticate()

/**
*
*@param crypto object associated with the call or null if none required.
* @param flags optional flags; should be 0
* @param cancel an object that can be used to cancel authentication
* @param callback an object to receive authentication events
* @param handler an optional handler for events
**/
@RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
    public void authenticate(@Nullable CryptoObject crypto, int flags,
            @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback,
            @Nullable Handler handler) {
        if (Build.VERSION.SDK_INT >= 23) {
            final FingerprintManager fp = getFingerprintManagerOrNull(mContext);
            if (fp != null) {
                android.os.CancellationSignal cancellationSignal = cancel != null
                        ? (android.os.CancellationSignal) cancel.getCancellationSignalObject()
                        : null;
                fp.authenticate(
                        wrapCryptoObject(crypto),
                        cancellationSignal,
                        flags,
                        wrapCallback(callback),
                        handler);
            }
        }
    }

arg1: 用于通过指纹验证取出AndroidKeyStore中key的值 
arg2: 系统建议为0
arg3: 取消指纹验证 手动关闭验证 可以调用该参数的cancel方法
arg4:返回验证结果
arg5: Handler fingerprint 中的 
消息都是通过handler来传递的 如果不需要则传null 会自动默认创建一个主线程的handler来传递消息


使用指纹识别的条件

通过零碎的知识完成一个Demo 

  • 添加权限(这个权限不需要在6.0中做处理)
  • 判断硬件是否支持
  • 是否已经设置了锁屏 并且已经有一个被录入的指纹
  • 判断是否至少存在一条指纹信息

指纹识别通过之后跳转到 指定页面

进入之后首先弹出对话框,进行指纹验证

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/fingerprint" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="验证指纹" />

    <TextView
        android:id="@+id/fingerprint_error_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:maxLines="1" />

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="5dp"
        android:background="#696969" />

    <TextView
        android:id="@+id/fingerprint_cancel_tv"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="取消"
        android:textSize="16sp" />

</LinearLayout>

使用DialogFragment 完成对话框 新建一个DialogFragment 并且初始化相关的api

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //获取fingerprintManagerCompat对象
        fingerprintManagerCompat = FingerprintManagerCompat.from(context!!)
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog)
    }

在界面显示在前台的时候开始扫描

override fun onResume() {
        super.onResume()
        startListening()
    }
@SuppressLint("MissingPermission")
    private fun startListening() {
        isSelfCancelled = false
        mCancellationSignal = CancellationSignal()
        fingerprintManagerCompat.authenticate(FingerprintManagerCompat.CryptoObject(mCipher), 0, mCancellationSignal, object : FingerprintManagerCompat.AuthenticationCallback() {
        //验证错误
            override fun onAuthenticationError(errMsgId: Int, errString: CharSequence?) {
                if (!isSelfCancelled) {
                    errorMsg.text = errString
                    if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                        Toast.makeText(mActivity, errString, Toast.LENGTH_SHORT).show()
                        dismiss()
                        mActivity.finish()
                    }
                }
            }
                //成功
            override fun onAuthenticationSucceeded(result: FingerprintManagerCompat.AuthenticationResult?) {
                MainActivity.startActivity(mActivity, true)
            }
            //错误时提示帮助,比如说指纹错误,我们将显示在界面上 让用户知道情况
            override fun onAuthenticationHelp(helpMsgId: Int, helpString: CharSequence?) {
                errorMsg.text = helpString
            }
            //验证失败
            override fun onAuthenticationFailed() {
                errorMsg.text = "指纹验证失败,请重试"
            }
        }, null)
    }

在不可见的时候停止验证

if (null != mCancellationSignal) {
            mCancellationSignal.cancel()
            isSelfCancelled = true
        }

在MainActivity 中首先判断是否验证成功 是 跳转到目标页 否则的话需要进行验证 
在这个过程中我们需要做的就是判断是否支持,判断是否满足指纹验证的条件(条件在上面)

if (intent.getBooleanExtra("isSuccess", false)) {
            WelcomeActivity.startActivity(this)
            finish()
        } else {
            //判断是否支持该功能
            if (supportFingerprint()) {
                initKey() //生成一个对称加密的key
                initCipher() //生成一个Cipher对象
            }
        }

验证条件

 if (Build.VERSION.SDK_INT < 23) {
            Toast.makeText(this, "系统不支持指纹功能", Toast.LENGTH_SHORT).show()
            return false
        } else {
            val keyguardManager = getSystemService(KeyguardManager::class.java)
            val managerCompat = FingerprintManagerCompat.from(this)
            if (!managerCompat.isHardwareDetected) {
                Toast.makeText(this, "系统不支持指纹功能", Toast.LENGTH_SHORT).show()
                return false
            } else if (!keyguardManager.isKeyguardSecure) {
                Toast.makeText(this, "屏幕未设置锁屏 请先设置锁屏并添加一个指纹", Toast.LENGTH_SHORT).show()
                return false
            } else if (!managerCompat.hasEnrolledFingerprints()) {
                Toast.makeText(this, "至少在系统中添加一个指纹", Toast.LENGTH_SHORT).show()
                return false
            }
        }

必须生成一个加密的key 和一个Cipher对象

//生成Cipher
private fun initCipher() {
        val key = keyStore.getKey(DEFAULT_KEY_NAME, null) as SecretKey
        val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                + KeyProperties.BLOCK_MODE_CBC + "/"
                + KeyProperties.ENCRYPTION_PADDING_PKCS7)
        cipher.init(Cipher.ENCRYPT_MODE, key)
        showFingerPrintDialog(cipher)
    }
    //生成一个key
private fun initKey() {
        keyStore = KeyStore.getInstance("AndroidKeyStore")
        keyStore.load(null)
        val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
        val builder = KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setUserAuthenticationRequired(true)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
        keyGenerator.init(builder.build())
        keyGenerator.generateKey()
    }

 验证成功就可

发布了80 篇原创文章 · 获赞 93 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_40251830/article/details/83066086