在 iOS 中如何使用 react native 检测自动 OTP,它在 android 上工作但在 iOS 上不工作。我使用 npm i react-native-otp-verify

问题描述 投票:0回答:1

我正在尝试在 iOS 中使用自动填充确认码。它在 android 上运行良好,但在 iOS 上运行不正常。我使用与文档相同的技术。在 iOS 上,我在 iOS 中不受支持。是iOS不支持自动填写确认码还是iOS有其他方式?如果有,请分享您的答案或提出其他解决方案。

import React, {useState, useEffect} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
  TouchableOpacity,
  ImageBackground,
  TextInput,
  Platform,
  Keyboard,
} from 'react-native';
import {
  widthPercentageToDP as wp,
  heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import {
  useLinkProps,
  useNavigation,
  CommonActions,
} from '@react-navigation/native';

import {
  CodeField,
  Cursor,
  useBlurOnFulfill,
  isLastFilledCell,
  MaskSymbol,
  useClearByFocusCell,
} from 'react-native-confirmation-code-field';
import OTPInputView from '@twotalltotems/react-native-otp-input';
import LinearGradient from 'react-native-linear-gradient';

import {useDispatch, useSelector} from 'react-redux';
import {
  clearState,
  OTPCodeAction,
} from '../Redux/Features/PhoneNumberSignUp/EnterOTPSignUpKit';
import colors from '../Styles/colors';
import fontFamily from '../Styles/fontFamily';
import Button from '../Components/Button/Button';

import {createPost} from '../Redux/Features/PhoneNumberSignUp/PhoneNumberSignUp';
import Toast from 'react-native-toast-message';
import Loader from '../Components/Loader/Loader';
import EStyleSheet from 'react-native-extended-stylesheet';

import {
  addListener,
  getHash,
  getOtp,
  removeListener,
  startOtpListener,
  useOtpVerify,
} from 'react-native-otp-verify';
const CELL_COUNT = 4;
const OTPEnter = ({route}) => {
  const [firstOTP, setFirstOTP] = useState('');
  const [otpCode, setOtpCode] = useState('');
  // const onChangeFirstOTP = val => {
  //   setFirstOTP(val);
  //   setValuesObj({...valuesObj, pin_code_sms: val});
  // };
  const [value, setValue] = useState('');
  const ref = useBlurOnFulfill({value, cellCount: CELL_COUNT});
  const [props, getCellOnLayoutHandler] = useClearByFocusCell({
    value,
    setValue,
  });

  const dispatch = useDispatch();
  const OTPCodeHere = useSelector(state => state.OTP);

  const navigation = useNavigation();
  const handleNavigate = (routeName, clearStack, params) => {
    navigation.navigate(routeName, params);
    if (clearStack) {
      console.log('Clear');
    }
  };

  const post = useSelector(state => state.post);
  console.log('post', post);

  const [valuesObj, setValuesObj] = useState({
    device_type: route.params.deviceTypeParam,
    sms_number: route.params.contactNumberParam,
    device_identifier: route.params.deviceIdentifierParam,
    device_token: route.params.deviceTokenParam,
    pin_code_sms: '',
  });

  // console.log('gettingToken', route.params.deviceTokenParam);

  const {hash, otp, message, timeoutError, stopListener, startListener} =
    useOtpVerify({numberOfDigits: 4});

  useEffect(() => {
    getHash().then(console.log).catch(console.log);
    getOtp()
      .then(p => addListener(otpHandler))
      .catch(p => console.log(p));
    return () => removeListener();
  }, []);

  // console.log('hashGetting', getHash());

  const otpHandler = message => {
    try {
      const otp = message && (/(\d{4})/g.exec(message)[1] ?? '');
      // console.log('otp<<', otp);
      if (otpHandler !== null && otp) {
        setValue(otp);
        dispatch(OTPCodeAction({...valuesObj, pin_code_sms: otp.toString()}));
        handleNavigate('HomeScreen');
        Keyboard.dismiss();
      }
    } catch (error) {}
  };

  useEffect(() => {
    if (OTPCodeHere.success) {
      handleNavigate('HomeScreen');
      dispatch(clearState());
    }
    if (OTPCodeHere.message) {
      Toast.show({
        type: 'success',
        text2: `${OTPCodeHere.message}`,
        visibilityTime: 6000,
        position: 'top',
      });
    }
  }, [OTPCodeHere, value]);

  // console.log('value111', value);

  const onPressSendCode = () => {
    // validateField();
    dispatch(createPost(route.params.contactNumberParam.toString()));
    dispatch(clearState());
  };

  const onPressSubmitCode = async () => {
    dispatch(OTPCodeAction({...valuesObj, pin_code_sms: value}));
    dispatch(clearState());
    // console.log('valuesObj', valuesObj);
  };

  useEffect(() => {
    if (post.success) {
      dispatch(clearState());
    }
    if (post.message) {
      Toast.show({
        text2: `${post.message}`,
        visibilityTime: 6000,
        position: 'top',
      });
    }
  }, [post]);

  const toastConfig = {
    success: internalState => (
      <View
        style={{
          height: hp('8'),
          width: wp('90'),
          marginHorizontal: wp('5'),
          backgroundColor: '#333333',
          borderRadius: wp('1.5'),
          justifyContent: 'center',
        }}>
        <Text
          style={{
            fontSize: hp('1.5'),
            fontFamily: fontFamily.interLight,
            color: colors.white,
            paddingHorizontal: wp('3'),
            paddingVertical: hp('1.5'),
            lineHeight: hp('2.5'),
          }}>
          {internalState.text2}
        </Text>
      </View>
    ),
  };

  const renderCell = ({index, symbol, isFocused}) => {
    let textChild = null;

    if (symbol) {
      textChild = (
        <MaskSymbol
          maskSymbol="●"
          isLastFilledCell={isLastFilledCell({index, value})}>
          {symbol}
        </MaskSymbol>
      );
    } else if (isFocused) {
      textChild = <Cursor />;
    }

    return (
      <Text
        key={index}
        style={[styles.cell, isFocused && styles.focusCell]}
        onLayout={getCellOnLayoutHandler(index)}>
        {textChild}
      </Text>
    );
  };

  return (
    <ImageBackground
      source={{uri: 'loginbglatest'}}
      style={{flex: 1}}
      resizeMode={'cover'}>
      <Toast config={toastConfig} ref={ref => Toast.setRef(ref)} />

      {post?.isLoading && <Loader></Loader>}
      {OTPCodeHere?.isLoading && <Loader></Loader>}
      <View style={{flex: 3.5}}></View>

      <View style={{marginBottom: hp('1.5'), marginHorizontal: wp('5')}}>
        <Text
          style={{
            color: '#1883b5',
            fontFamily: fontFamily.interLight,
            fontSize: hp('1.5'),
          }}>
          {`Enter the 4-digit OTP sent to ${route.params.contactNumberParam}`}
        </Text>
      </View>

      <View
        style={{
          height: hp('18'),
          flexDirection: 'column',
          backgroundColor: 'white',
          marginHorizontal: wp('5'),
          borderRadius: wp('6'),
          paddingTop: hp('2'),
        }}>
        <View
          style={{
            height: hp('7'),
            justifyContent: 'flex-end',
            paddingTop: hp('2'),
            paddingHorizontal: wp('5'),
          }}>
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'space-evenly',
              justifyContent: 'center',
              marginHorizontal: wp('5'),
            }}>
            <View style={{}}>
              <CodeField
                ref={ref}
                {...props}
                // Use `caretHidden={false}` when users can't paste a text value, because context menu doesn't appear
                value={value}
                onChangeText={setValue}
                cellCount={CELL_COUNT}
                rootStyle={styles.codeFieldRoot}
                keyboardType="number-pad"
                textContentType="oneTimeCode"
                renderCell={renderCell}
              />
            </View>
          </View>
        </View>

        <View
          style={{
            height: hp('8'),
            justifyContent: 'flex-end',
            marginHorizontal: wp('5'),
            marginTop: hp('-1'),
          }}>
          <LinearGradient
            colors={['#2A72B6', '#203B88']}
            start={{x: 0, y: 0}}
            end={{x: 1, y: 0}}
            style={{borderRadius: wp('3')}}>
            <TouchableOpacity
              onPress={onPressSubmitCode}
              style={{
                height: hp('5.5'),
                borderRadius: wp('1.5'),
                justifyContent: 'center',
                alignItems: 'center',
               
              }}>
              <Text style={styles.btnText}>Submit Code</Text>
            </TouchableOpacity>
          </LinearGradient>
          {/* <Button
            onPress={onPressSubmitCode}
            height={hp('5.5')}
            text={'Submit Code'}
            colorsArray={['#2A72B6', '#203B88']}
            textColor={colors.white}
            textSize={hp('1.8')}
          /> */}
        </View>
      </View>

      <View
        style={{
          marginTop: hp('1.25'),
          marginLeft: wp('6'),
          marginRight: wp('3'),
          marginBottom: hp('3.5'),
        }}>
        <Text style={styles.lowerText}>
          Didn't receive the code?
          <Text
            onPress={onPressSendCode}
            style={{
              color: colors.white,
            }}>
            {' '}
            Tap here{' '}
          </Text>
          to resend. Having trouble with the authentication?{' '}
          <Text
            onPress={() => handleNavigate('SupportTicket')}
            style={{
              color: colors.white,
            }}>
            Raise a support request ticket
          </Text>
        </Text>
      </View>
      {/* <View
        style={{
          marginHorizontal: wp('6'),
          marginBottom: hp('1'),
        }}>
        <Text
          onPress={() => handleNavigate('SupportTicket')}
          style={{
            fontSize: hp('1.5'),
            fontFamily: fontFamily.interLight,
            color: colors.white,
          }}>
          Raise a support request ticket
        </Text>
      </View> */}
    </ImageBackground>
  );
};

const styles = EStyleSheet.create({
  root: {flex: 1, padding: 20},
  title: {textAlign: 'center', fontSize: 30},
  codeFieldRoot: {marginTop: 10},
  cell: {
    width: wp('17'),
    height: hp('7'),
    fontSize: hp('3.5'),
    justifyContent: 'center',
    color: colors.black,

    textAlign: 'center',
    marginHorizontal: wp('1.5'),
    borderBottomColor: '#DDD',
    borderBottomWidth: 2,
    paddingTop: hp('1'),
    marginBottom: hp('0.5'),
  },

  focusCell: {
    borderColor: colors.lightGrey,
    shadowColor: colors.lightGrey,
    shadowOffset: {
      width: 0,
      height: 8,
    },
    shadowOpacity: wp('0'),
    elevation: 1,
    shadowRadius: wp('10'),
  },
  lowerText: {
    color: '#1883b5',
    fontFamily: fontFamily.interLight,
    fontSize: '0.55rem',
    lineHeight: hp('2.5'),
    letterSpacing: -0.15,
    paddingRight: wp('2'),
  },
  btnText: {
    color: colors.white,
    fontFamily: fontFamily.interLight,
    fontSize: '0.65rem',
  },
});

export default OTPEnter;
react-native react-hooks react-redux verify one-time-password
1个回答
0
投票

对于 iOS OTP 阅读,您不需要任何外部库。 React-native 默认提供在 textinput 中读取的 OTP。您只需要在 textinput 中添加以下道具。

 textContentType="oneTimeCode"
 autoComplete="sms-otp"

如果您使用的是第三方 otp 输入组件,那么这也可以。

但请记住,在 iOS 中 OTP 自动读取与您在 Android 中获得的不同。在这里你可以看到 texinput 上的 OTP,通过点击键盘上的 OTP,你的文本输入将被 OTP 填充。

如果只是不工作然后在开始时在短信中添加以下内容:

<#>code 

例如,您的消息应如下所示。

<#> code Your Google OTP to verify your phone number is 12345
'your android autoread key'
© www.soinside.com 2019 - 2024. All rights reserved.