1. 程式人生 > 程式設計 >React Native登入之指紋登入篇的示例程式碼

React Native登入之指紋登入篇的示例程式碼

在這裡插入圖片描述

React Native登入之指紋登入篇,具體內容如下所示:

最近在做react-native的APP,專案登入使用了普通賬號密碼登入、簡訊登入、手勢登陸、指紋登入和人臉識別登入五種方式,所以準備做一個登入方式的合集。本篇是指紋登入篇,通過手機呼叫指紋感測器來獲取使用者指紋並做校驗,校驗成功則自動登入。

首先展示我們最後達成的成果,畢竟無圖無真相,下方是真機錄屏gif:

在這裡插入圖片描述

分析下gif所展示的功能點:

1,通過點選操作選項來彈出指紋識別介面,點選取消/上方空白處取消指紋識別

2,切換到其他登入方式時,仍然可以呼叫"更多操作方式"來喚起指紋識別

經過功能點分析,我們可以看出,現在需要一個指紋識別的元件,通過操作彈出項來喚起/切換指紋識別的元件。操作項元件我們可以選擇antd-mobile-rn的ActionSheet

元件,指紋識別元件使用react-native-fingerprint-scanner,在github上有642個star,想必是值得信任的,附上元件地址https://github.com/hieuvp/react-native-fingerprint-scanner。(多句嘴,模擬器是沒有指紋識別的功能的,請使用真機除錯)。

接下來按照文件一通操作,下載,跑demo,不出所料有問題出現了。

官方demo使用的是react16之前的class寫法,並且對於喚起/隱藏指紋識別的地方寫的有些模糊,所以我們需要仔細梳理並用新的函式式元件寫法來重寫一次。

指紋識別的過程應該如下:

1,判斷裝置是否支援指紋識別

2,判斷android API是否低於23,因為android 6.0之後官方才支援了指紋識別的api介面,所以如果android 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,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',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以上版本是不需要渲染指紋識別元件的,23以下版本需要自己手動寫一個渲染的元件,引用了一個ShakingText元件,這個元件官網有給,我們直接複製過來就可以,在ShakingText.component.js寫:

import PropTypes from 'prop-types';
import React,{ Component } from 'react';
import {
 Animated,} 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,-11,5,0],}),{
     translateX: this.shakedValue.interpolate({
      inputRange: [0,2,-3,4,-4,3,-5,],};
 }

 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元件來切換和控制指紋元件的顯示隱藏。控制指紋元件的顯示隱藏我們使用popupShowed這個變數來控制,將它放在state中。我們在LoginSheet/index.tsx下寫:

import React,{useState} from 'react';
import {View,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置為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指紋登入內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!