React Native 指纹登录实现:从组件集成到状态管理

作者:星野时间:2026-10-23 23:18:42浏览:276

本文详解 React Native 应用中指纹登录功能的实现。通过集成 react-native-fingerprint-scanner 库,结合 ActionSheet 组件控制界面显示,重点解决 Android API 低于 23 版本的兼容性问题。文章提供了基于函数式组件的重写方案,涵盖设备检测、API 适配、组件生命周期管理及状态控制等核心步骤,确保指纹识别流程在真机环境下的稳定运行。

React Native 指纹登录功能概述

本文介绍 React Native 应用中的指纹登录功能实现细节。

React Native 指纹登录功能概述

近期开发的 React Native 应用程序集成了五种登录方式:普通账号密码、短信验证码、手势密码、指纹识别及人脸识别。为便于查阅,特此整理登录功能合集,本节重点讲解指纹登录模块。该模块通过调用手机硬件指纹传感器采集用户指纹数据,经后端或本地校验成功后,自动完成登录流程。

首先展示最终实现效果,以真实设备录制的 GIF 动图为例,直观呈现交互过程。

React Native 指纹登录功能概述

解析上述 GIF 中展示的核心功能点:

1. 用户点击特定操作选项时,弹出指纹识别界面;点击取消按钮或界面空白区域可关闭该识别窗口。

2. 即使切换至其他登录方式界面,仍可通过“更多操作方式”入口重新唤起指纹识别功能。

组件选型与真机调试要求

基于上述功能分析,系统需构建一个独立的指纹识别组件,并通过操作项组件控制其弹出与切换。操作项部分选用 antd-mobile-rn 库中的 ActionSheet 组件;指纹识别核心组件则采用 react-native-fingerprint-scanner。该组件在 GitHub 上拥有 642 个 Star,具备较高的可信度,官方仓库地址为 https://github.com/hieuvp/react-native-fingerprint-scanner。需特别注意,模拟器不支持指纹识别功能,调试时必须使用真机设备。

参照官方文档进行下载与 Demo 运行后,发现存在兼容性问题,需进一步调整。

官方 Demo 采用 React 16 之前的 Class 组件写法,且对指纹识别组件的唤起与隐藏逻辑描述较为简略。因此,需重新梳理逻辑,并使用现代函数式组件语法进行重构。

指纹识别执行流程与 Android 适配

指纹识别的标准执行流程如下:

1. 检测设备硬件是否支持指纹识别功能。

2. 检查 Android API 版本是否低于 23。由于 Android 6.0(API 23)之后官方才提供指纹识别 API,若设备 API 版本低于 23,需进行特殊适配处理。

3. 从 react-native-fingerprint-scanner 库中引入 FingerprintScanner,并调用 FingerprintScanner.authenticate 方法以启动指纹识别组件。

4. 当用户点击取消按钮或屏幕空白区域时,隐藏指纹识别组件。

5. 在指纹识别成功时触发对应事件(如执行登录逻辑)。

指纹组件实现与状态控制逻辑

依据上述流程,在 FingerPrint/index.tsx 文件中编写指纹组件,关键代码已添加详细注释。


import React, {Component, useState, useCallback} from 'react';
import {
 Alert,
 Image,
 Text,
 TouchableOpacity,
 View,
 ViewPropTypes,
 Platform,
 StyleSheet,
} from 'react-native';
import FingerprintScanner from 'react-native-fingerprint-scanner';
import ShakingText from './ShakingText.component';
import {connector, ModelState} from '@/models/connect';
import {useFocusEffect} from "@react-navigation/native";


interface Props extends ModelState{
 fingerPrint,
 setFingerPrint,
}

const FingerPrintPopup: React.FC<Props> = React.memo(props => {
 let {fingerPrint, setFingerPrint,dispatch} = props;
 const description = null;

 const [LegacyInfo, setLegacyInfo] = useState({
  errorMessageLegacy: undefined,
  biometricLegacy: undefined
 })
 useFocusEffect(
  React.useCallback(() => {
   console.log("进入指纹组件");
   //判断设备是否支持指纹识别
   detectFingerprintAvailable();
   //判断Android API是不是<23,高于此版本使用标准指纹解锁api;低于此版本使用兼容适配版本
   if (requiresLegacyAuthentication()) {
    authLegacy();
   } else {
    authCurrent();
   }

   return () => {
    console.log("离开指纹组件");
    //组件卸载,停止指纹监听指纹扫描器并释放内部缓存
    FingerprintScanner.release();
   }
  }, [])
 )

 //判断安卓版本
 function requiresLegacyAuthentication() {
  return Platform.Version < 23;
 }

 //控制指纹组件消失
 const handleFingerprintDismissed = () => {
  setFingerPrint({
   ...fingerPrint,
   popupShowed: false
  });
 };
 //检测手机是否支持指纹识别
 const detectFingerprintAvailable = () => {
  FingerprintScanner
   .isSensorAvailable()
   .catch(error => {
    Alert.alert("您的设备不支持指纹识别,请选择其他方式登录")
    setFingerPrint({
     ...fingerPrint,
     errorMessage: error.message,
     biometric: error.biometric,
     popupShowed: false,
    })
   });
 }
 //android API>23时,调用authCurrent
 const authCurrent = () => {
  FingerprintScanner
   .authenticate({title: '指纹登录', cancelButton: '取消'})
   .then(() => {
    //离开页面时将popupShowed置为false
    handleFingerprintDismissed();
    //指纹验证成功后的事件,比如登录
    successVerify();
   })
   .catch(() => {
    //点击取消或上方空白区隐藏组件后,将popupShowed置为false
    //这里是控制指纹组件切换显示/隐藏的关键!
    handleFingerprintDismissed();
   })
 }

 //指纹验证成功后的事件,比如登录
 const successVerify = () => {
  dispatch({
   type: 'user/login',
   payload: {
    username: "张三",
    password: '123456',
   }
  });

 }
 //android API<23时调用指纹组件的兼容写法
 const authLegacy = () => {
  FingerprintScanner
   .authenticate({onAttempt: handleAuthenticationAttemptedLegacy})
   .then(() => {
    //指纹验证成功
    handleFingerprintDismissed();
    Alert.alert('指纹身份验证', '身份验证成功');
    successVerify();
   })
   .catch((error) => {
    //指纹验证失败
    setLegacyInfo({errorMessageLegacy: error.message, biometricLegacy: error.biometric});
    description.shake();
    handleFingerprintDismissed();
   });
 }

 //当用户尝试扫描指纹但失败时的回调函数
 const handleAuthenticationAttemptedLegacy = (error) => {
  setLegacyInfo({
   ...LegacyInfo,
   errorMessageLegacy: error.message
  });
  description.shake();
 };

 //手动写一个指纹验证的组件
 const renderLegacy = (
  <View style={styles.container}>
   <View style={styles.contentContainer}>

    <Image
     style={styles.logo}
     source={require('../../../assets/login/finger_print.png')}
    />

    <Text style={styles.heading}>
     生物识别{'\n'}身份验证
    </Text>
    <ShakingText
     ref={(instance) => {
      description = instance;
     }}
     style={styles.description(!!LegacyInfo.errorMessageLegacy)}>
     {LegacyInfo.errorMessageLegacy || `Scan your ${LegacyInfo.biometricLegacy} on the\ndevice scanner to continue`}
    </ShakingText>

    <TouchableOpacity
     style={styles.buttonContainer}
     onPress={handleFingerprintDismissed}
    >
     <Text style={styles.buttonText}>
      返回
     </Text>
    </TouchableOpacity>

   </View>
  </View>
 );

 return () => {
  //android API>23时,不需要渲染;否则渲染renderLegacy的组件
  if (requiresLegacyAuthentication()) {
   return renderLegacy
  }

  return null;

 }

})


export default connector(FingerPrintPopup);
const styles = StyleSheet.create({
 container: {
  position: 'absolute',
  top: 0,
  bottom: 0,
  left: 0,
  right: 0,
  backgroundColor: 'rgba(0, 164, 222, 0.9)',
  flexDirection: 'column',
  justifyContent: 'center',
  alignItems: 'center',
 },
 contentContainer: {
  flexDirection: 'column',
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: '#ffffff',
 },
 logo: {
  marginVertical: 45,
 },
 heading: {
  textAlign: 'center',
  color: '#00a4de',
  fontSize: 21,
 },
 description: (error) => {
  return {
   textAlign: 'center',
   color: error ? '#ea3d13' : '#a5a5a5',
   height: 65,
   fontSize: 18,
   marginVertical: 10,
   marginHorizontal: 20,
  }
 },
 buttonContainer: {
  padding: 20,
 },
 buttonText: {
  color: '#8fbc5a',
  fontSize: 15,
  fontWeight: 'bold',
 },
});

代码逻辑显示,当 Android API 版本大于等于 23 时,无需渲染自定义指纹识别组件;而对于 API 低于 23 的旧版本设备,需手动渲染一个兼容组件。此处引用了 ShakingText 组件,该组件由官方提供,直接复制代码至 ShakingText.component.js 即可使用。


import PropTypes from 'prop-types';
import React, { Component } from 'react';
import {
 Animated,
 Text,
} from 'react-native';

class ShakingText extends Component {

 componentWillMount() {
  this.shakedValue = new Animated.Value(0);
 }

 get animatedStyle() {
  return {
   transform: [
    {
     translateY: this.shakedValue.interpolate({
      inputRange: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
      outputRange: [0, 10, -15, 12, -9, 18, -7, 10, -11, 5, 0],
     }),
    },
    {
     translateX: this.shakedValue.interpolate({
      inputRange: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
      outputRange: [0, 2, -3, 4, -4, 3, -3, 4, -5, 2, 0],
     }),
    },
   ],
  };
 }

 shake = () => {
  this.shakedValue.setValue(0);
  Animated.spring(this.shakedValue, {
   toValue: 1,
   friction: 3,
   tension: 10,
  }).start(() => this.shakedValue.setValue(0));
 };

 render() {
  return (
   <Animated.Text
    {...this.props}
    style={[this.animatedStyle, this.props.style]}
   />
  );
 }
}

ShakingText.propTypes = {
 children: PropTypes.oneOfType([
  PropTypes.arrayOf(PropTypes.node),
  PropTypes.node
 ]),
 style:Text.propTypes.style,
};

export default ShakingText;

指纹组件编写完成后,需利用 ActionSheet 组件来切换和控制指纹组件的显示与隐藏。通过 state 中的 popupShowed 变量控制组件状态,具体实现代码位于 LoginSheet/index.tsx 处。


import React,{useState} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {px2rem} from "@/utils/px2rem";
import {ActionSheet} from "@ant-design/react-native";
import {navigateReplace} from "@/utils/navigation";
import FingerprintPopup from "@/pages/Account/FingerPrint";
import {connector,ModelState} from '@/models/connect';


interface Props {

}
const LoginSheet: React.FC<Props> = React.memo(props => {
 const {dispatch} = props;

 const [fingerPrint,setFingerPrint] = useState({
  errorMessage: undefined,
  biometric: undefined,
  popupShowed: false,
 })
 
 //点击指纹登录选项时,将popupShowed置为true
 const handleFingerprintShowed = () => {
  setFingerPrint({
   ...fingerPrint,
   popupShowed: true
  });
 }
 
 const showActionSheet = () =>{
  const BUTTONS = [
   '账号 / 短信登录',
   '手势登录',
   '指纹登录',
   '人脸识别登录',
   '取消',
  ];
  ActionSheet.showActionSheetWithOptions(
   {
    options: BUTTONS,
    cancelButtonIndex: 4,
   },
   buttonIndex => {
    const clickOption = BUTTONS[buttonIndex];
    console.log('clicked: ',clickOption);
    switch (clickOption){
     case '账号 / 短信登录':
      navigateReplace("Login");
      return;
     case '手势登录':
      navigateReplace("GestureUnlock");
      return;
     case '指纹登录':
      //显示指纹登录
      handleFingerprintShowed();
      return;
     case '人脸识别登录':
      navigateReplace("Login");
      return;
    }
   }
  );
 }

 return (
  <View style={styles.container}>
   <View style={styles.more}>
    <Text style={styles.moreText} onPress={showActionSheet}>更多登录方式</Text>
   </View>
   {fingerPrint.popupShowed ? (
    <FingerprintPopup
     fingerPrint={fingerPrint}
     setFingerPrint={setFingerPrint}
    />
   ) : null}
  </View>
 );

})

export default connector(LoginSheet);
const styles = StyleSheet.create({
 container:{

 },
 more:{
  width:'100%',
  alignItems:'center',
  height:px2rem(50),
  marginBottom:px2rem(30),
 },
 moreText:{
  // color:'#a1a1a1'
 }
});

至此,React Native 指纹登录功能开发完毕。核心要点总结如下:

控制指纹组件显示与隐藏的关键在于管理 popupShowed 的 true/false 状态,以此决定 FingerprintPopup 组件的渲染与否。每次唤醒组件时,需先显示 FingerprintPopup 组件,在初始化阶段判断设备可用性及系统版本,随后调用组件展示逻辑。每次隐藏组件时,需通过隐藏 FingerprintPopup 组件,并在组件卸载阶段释放指纹监听器 FingerprintScanner.release();。无论指纹识别成功、失败还是用户点击取消,均需将 popupShowed 置为 false;仅当指纹识别失败时,保持当前状态不做额外操作。

总结

本文介绍了 React Native 指纹登录的实现方法,更多相关 React Native 指纹登录内容可搜索本站往期文章或浏览后续相关教程。感谢支持。

作者最新文章