React Native登录之指纹登录篇的示例代码


Posted in Javascript onNovember 03, 2020

React Native登录之指纹登录篇的示例代码

React Native登录之指纹登录篇,具体内容如下所示:

最近在做react-native的APP,项目登录使用了普通账号密码登录、短信登录、手势登陆、指纹登录和人脸识别登录五种方式,所以准备做一个登录方式的合集。本篇是指纹登录篇,通过手机调用指纹传感器来获取用户指纹并做校验,校验成功则自动登录。

首先展示我们最后达成的成果,毕竟无图无真相,下方是真机录屏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使用的是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, 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以上版本是不需要渲染指纹识别组件的,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组件来切换和控制指纹组件的显示隐藏。控制指纹组件的显示隐藏我们使用popupShowed这个变量来控制,将它放在state中。我们在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指纹登录内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jquery ajax 调用失败的原因示例介绍
Sep 27 Javascript
动态加载jquery库的方法
Feb 12 Javascript
jquery隔行换色效果实现方法
Jan 15 Javascript
JS实现的生成随机数的4个函数分享
Feb 11 Javascript
js鼠标点击图片实现随机变换图片的方法
Feb 16 Javascript
JS实现下拉菜单列表与登录注册弹窗效果
Aug 10 Javascript
JavaScript重复元素处理方法分析【统计个数、计算、去重复等】
Dec 14 Javascript
深入浅析vue组件间事件传递
Dec 29 Javascript
JavaScript使用ul中li标签实现删除效果
Apr 15 Javascript
微信小程序API—获取定位的详解
Apr 30 Javascript
微信小程序页面传多个参数跳转页面的实现方法
May 17 Javascript
JavaScript oncopy事件用法实例解析
May 13 Javascript
解决VantUI popup 弹窗不弹出或无蒙层的问题
Nov 03 #Javascript
wepy--用vantUI 实现上弹列表并选择相应的值操作
Nov 03 #Javascript
使用vant的地域控件追加全部选项
Nov 03 #Javascript
vue vant中picker组件的使用
Nov 03 #Javascript
vue-amap根据地址回显地图并mark的操作
Nov 03 #Javascript
ant-design-vue中tree增删改的操作方法
Nov 03 #Javascript
Vue+Vant 图片上传加显示的案例
Nov 03 #Javascript
You might like
第九节 绑定 [9]
2006/10/09 PHP
基于php和mysql的简单的dao类实现crud操作功能
2014/01/27 PHP
php微信公众号开发模式详解
2016/11/28 PHP
PHP判断是手机端还是PC端 PHP判断是否是微信浏览器
2017/03/15 PHP
老生常谈PHP中的数据结构:DS扩展
2017/07/17 PHP
Laravel 模型使用软删除-左连接查询-表起别名示例
2019/10/24 PHP
图片按比例缩放函数
2006/06/26 Javascript
Javascript 获取链接(url)参数的方法[正则与截取字符串]
2010/02/09 Javascript
JavaScript设计模式之单例模式实例
2014/09/24 Javascript
jQuery源码解读之addClass()方法分析
2015/02/20 Javascript
JavaScript将字符串转换成字符编码列表的方法
2015/03/19 Javascript
jquery自定义表格样式
2015/11/23 Javascript
javascript url几种编码方式详解
2016/06/06 Javascript
gulp解决跨域的配置文件问题
2017/06/08 Javascript
node.js中路由,中间件,ge请求和post请求的参数详解
2017/12/26 Javascript
jQuery的ztree仿windows文件新建和拖拽功能的实现代码
2018/12/05 jQuery
vue + element-ui的分页问题实现
2018/12/17 Javascript
Javascript实现一朵从含苞到绽放的玫瑰
2019/03/30 Javascript
node.js的http.createServer过程深入解析
2019/06/06 Javascript
简单了解Vue + ElementUI后台管理模板
2020/04/07 Javascript
jQuery实现增删改查
2020/12/22 jQuery
Python解析树及树的遍历
2016/02/03 Python
OpenCV实现人脸识别
2017/04/07 Python
使用Keras构造简单的CNN网络实例
2020/06/29 Python
使用TensorBoard进行超参数优化的实现
2020/07/06 Python
简单整理HTML5的基本特性和语法
2016/02/18 HTML / CSS
可能这些是你想要的H5软键盘兼容方案(小结)
2019/04/23 HTML / CSS
AmazeUI框架搭建的方法步骤(图文)
2020/08/17 HTML / CSS
AmazeUI底部导航栏与分享按钮的示例代码
2020/08/18 HTML / CSS
德国PC硬件网站:CASEKING
2016/10/20 全球购物
美国在线宠物商店:Chewy
2019/01/12 全球购物
学生出入校管理制度
2014/01/16 职场文书
班主任经验交流会主持词
2014/04/01 职场文书
中小学生学籍证明
2014/10/25 职场文书
2014年终工作总结范本
2014/12/15 职场文书
终止合同协议书范本
2016/03/22 职场文书