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 相关文章推荐
关于javascript document.createDocumentFragment()
Apr 04 Javascript
引用外部js乱码问题分析及解决方案
Apr 12 Javascript
js实现select跳转功能代码
Oct 22 Javascript
详细分析JavaScript变量类型
Jul 08 Javascript
Jquery插件仿百度搜索关键字自动匹配功能
May 11 Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
Nov 05 Javascript
ES6中Math对象的部分扩展
Feb 20 Javascript
妙用Angularjs实现表格按指定列排序
Jun 23 Javascript
javascript+css3开发打气球小游戏完整代码
Nov 28 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
Sep 21 Javascript
jQuery位置选择器用法实例分析
Jun 28 jQuery
Ajax实现异步加载数据
Nov 17 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
php中通过curl模拟登陆discuz论坛的实现代码
2012/02/16 PHP
Codeigniter通过SimpleXML将xml转换成对象的方法
2015/03/19 PHP
PHP获取音频文件的相关信息
2015/06/22 PHP
codeigniter实现get分页的方法
2015/07/10 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
一个网页标题title的闪动提示效果实现思路
2014/03/22 Javascript
jQuery的文档处理程序详解
2016/05/10 Javascript
BootStrap 附加导航组件
2016/07/22 Javascript
JavaScript排序算法动画演示效果的实现方法
2016/10/18 Javascript
JSON中key动态设置及JSON.parse和JSON.stringify()的区别
2016/12/29 Javascript
Node.js 回调函数实例详解
2017/07/06 Javascript
JS中跳出循环的示例代码
2017/09/14 Javascript
vue.js给动态绑定的radio列表做批量编辑的方法
2018/02/28 Javascript
JS实现匀速与减速缓慢运动的动画效果封装示例
2018/08/27 Javascript
JavaScript学习笔记之DOM操作实例分析
2019/01/08 Javascript
[09:34]2018DOTA2国际邀请赛寻真——永不放弃的iG
2018/08/14 DOTA
Python脚本实现格式化css文件
2015/04/08 Python
Python调用系统底层API播放wav文件的方法
2017/08/11 Python
Django的分页器实例(paginator)
2017/12/01 Python
tensorflow 加载部分变量的实例讲解
2018/07/27 Python
Python从使用线程到使用async/await的深入讲解
2018/09/16 Python
python实现两个字典合并,两个list合并
2019/12/02 Python
用Python 执行cmd命令
2020/12/18 Python
CSS3实现可爱的小黄人动画
2016/07/11 HTML / CSS
canvas简单连线动画的实现代码
2020/02/04 HTML / CSS
美国滑板店:Tactics
2020/11/08 全球购物
计算机工程学院个人求职信
2013/10/05 职场文书
主管职责范文
2013/11/09 职场文书
三年大学自我鉴定
2014/01/16 职场文书
动漫专业高职生职业生涯规划书
2014/02/15 职场文书
2014年科研工作总结
2014/12/03 职场文书
我的法兰西岁月观后感
2015/06/09 职场文书
2015年度环卫处工作总结
2015/07/24 职场文书
2019最新版股权转让及委托持股协议书范本
2019/08/07 职场文书
html form表单基础入门案例讲解
2021/07/15 HTML / CSS
Tomcat安装使用及部署Web项目的3种方法汇总
2022/08/14 Servers