繁体   English   中英

Expo react-native app with firebase phone authentication works on web, error on ios simulator and crashes with no warning on Android

[英]Expo react-native app with firebase phone authentication works on web, error on ios simulator and crashes with no warning on Android

我正在使用 expo 构建一个 react-native 应用程序,我只有 2 个组件,WelcomeScreen 和 PhoneLoginScreen。 I am trying to implement firebase phone authentication which works fine on the Web but on iOS Simulator I get an error Verifier._reset is not a function. (In 'verifier._reset()', 'verifiier._reset' is undefined Verifier._reset is not a function. (In 'verifier._reset()', 'verifiier._reset' is undefined ,在 Android 上,当我单击导航到 PhoneLoginScreen 组件的继续按钮时,它会崩溃。代码如下:

应用程序.js

import React from "react"

import { NavigationContainer } from "@react-navigation/native"
import { createNativeStackNavigator } from "@react-navigation/native-stack"

import WelcomeScreen from "./components/WelcomeScreen"
import PhoneLoginScreen from "./components/auth/PhoneLoginScreen"

const Stack = createNativeStackNavigator()

export default function App() {
    return (
        <NavigationContainer>
            <Stack.Navigator initialRouteName="Welcome">
                <Stack.Screen
                    name="Welcome"
                    component={WelcomeScreen}
                    options={{ headerShown: false }}
                />

                <Stack.Screen
                    name="PhoneLogin"
                    component={PhoneLoginScreen}
                    options={{ headerShown: false }}
                />
            </Stack.Navigator>
        </NavigationContainer>
    )
}

WelcomeScreen.js

import React from "react"
import { Text, View, Button } from "react-native"

export default function WelcomeScreen({ navigation }) {
    return (
        <View
            style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
            <Text>Welcome</Text>
            <Button
                title="Continue"
                onPress={() => navigation.navigate("PhoneLogin")}
            />
        </View>
    )
}

PhoneLoginScreen.js

import React, { useRef, useState } from "react"
import { firebaseApp, auth } from "../../firebase"
import {
    Text,
    View,
    TextInput,
    Button,
    StyleSheet,
    TouchableOpacity,
} from "react-native"

import {
    FirebaseRecaptchaVerifierModal,
    FirebaseRecaptchaBanner,
} from "expo-firebase-recaptcha"

import { PhoneAuthProvider, signInWithCredential } from "firebase/auth"

export default function PhoneLoginScreen() {
    const recaptchaVerifier = useRef(null)
    const [message, showMessage] = useState()
    const [phoneNumber, setPhoneNumber] = useState()
    const [verificationId, setVerificationId] = useState()
    const [verificationCode, setVerificationCode] = useState()

    const firebaseConfig = firebaseApp ? firebaseApp.options : undefined
    const attemptInvisibleVerification = true

    return (
        <View style={styles.center}>
            <FirebaseRecaptchaVerifierModal
                ref={recaptchaVerifier}
                firebaseConfig={firebaseConfig}
                attemptInvisibleVerification={attemptInvisibleVerification}
            />

            <Text style={{ marginTop: 20 }}>Enter phone number</Text>

            <TextInput
                style={{ marginVertical: 10, fontSize: 17 }}
                placeholder="+1 999 999 9999"
                autoFocus
                autoCompleteType="tel"
                keyboardType="phone-pad"
                textContentType="telephoneNumber"
                onChangeText={phoneNumber => setPhoneNumber(phoneNumber)}
            />

            <Button
                title="Send Verification Code"
                disabled={!phoneNumber}
                onPress={async () => {
                    try {
                        const phoneProvider = new PhoneAuthProvider(auth)
                        const verificationId =
                            await phoneProvider.verifyPhoneNumber(
                                phoneNumber,
                                recaptchaVerifier.current
                            )
                        setVerificationId(verificationId)
                        showMessage({
                            text: "Verification code has been sent to your phone.",
                        })
                    } catch (err) {
                        showMessage({
                            text: `Error 111: ${err.message}`,
                            color: "red",
                        })
                    }
                }}
            />
            <Text style={{ marginTop: 20 }}>Enter Verification code</Text>
            <TextInput
                style={{ marginVertical: 10, fontSize: 17 }}
                editable={!!verificationId}
                placeholder="123456"
                onChangeText={setVerificationCode}
            />
            <Button
                title="Confirm Verification Code"
                disabled={!verificationId}
                onPress={async () => {
                    try {
                        const credential = PhoneAuthProvider.credential(
                            verificationId,
                            verificationCode
                        )

                        await signInWithCredential(auth, credential)
                        showMessage({
                            text: "Phone authentication successful 👍",
                        })
                    } catch (err) {
                        showMessage({
                            text: `Error: ${err.message}`,
                            color: "red",
                        })
                    }
                }}
            />
            {message ? (
                <TouchableOpacity
                    style={[
                        StyleSheet.absoluteFill,
                        {
                            backgroundColor: 0xffffffee,
                            justifyContent: "center",
                        },
                    ]}
                    onPress={() => showMessage(undefined)}>
                    <Text
                        style={{
                            color: message.color || "blue",
                            fontSize: 17,
                            textAlign: "center",
                            margin: 20,
                        }}>
                        {message.text}
                    </Text>
                </TouchableOpacity>
            ) : undefined}
            {attemptInvisibleVerification && <FirebaseRecaptchaBanner />}
        </View>
    )
}

const styles = StyleSheet.create({
    center: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
    },
})

firebase.js

import firebase from "firebase/compat/app"
import "firebase/compat/auth"
import "firebase/compat/firestore"

// Initialize Firebase
const firebaseConfig = {
    // Config info...
}

let firebaseApp

if (firebase.apps.length === 0) {
    firebaseApp = firebase.initializeApp(firebaseConfig)
} else {
    firebaseApp = firebase.app()
}

const auth = firebase.auth()

export { auth, firebaseApp }

package.json 依赖项

"dependencies": {
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/native-stack": "^6.2.5",
    "expo": "~43.0.2",
    "expo-firebase-recaptcha": "~2.0.2",
    "expo-status-bar": "~1.1.0",
    "firebase": "^9.5.0",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-native": "0.64.3",
    "react-native-safe-area-context": "3.3.2",
    "react-native-screens": "~3.8.0",
    "react-native-web": "0.17.1",
    "react-native-webview": "11.13.0"
  }

我一直在谷歌上搜索,没有任何效果。 请指教

这是一个错误。 “expo-firebase-recaptcha”的维护者还没有发布修复,所以在那一天到来之前,这就是你自己修复它的方法:

Go 到 node_modules/expo-firebase-recaptcha,打开build文件夹,找到FirebaseRecaptchaVerifierModal.js

在 FirebaseRecaptchaVerifierModal 内部,将以下 function 添加到组件定义中:

_reset = () => {}

在添加空的 function 定义后,我包含了文件的片段:

FirebaseRecaptchaVerifierModal.js

[...]
            else {
                this.setState({
                    visible: true,
                    visibleLoaded: false,
                    resolve,
                    reject,
                });
            }
        });
    }
    
    /**
     * Add the following line anywhere inside of the FirebaseRecaptchaVerifierModal component.
     */
    _reset = () => {}

    onVisibleLoad = () => {
        this.setState({
            visibleLoaded: true,
        });
    };
[...]

注意:您必须在每次安装 yarn/npm 或更改 node_modules 后执行此操作,直到发布者推送更新。

错误:verifier._reset 不是 function。 当尝试使用 firebase 使用手机登录时,反应原生和 Expo

FirebaseRecaptchaVerifierModal attemptInvisibleVerification Crashs on Android Emulator看看这个。这对我很有帮助

我加

`<FirebaseRecaptchaVerifierModal

ref={recaptchaVerifierRef}

firebaseConfig={firebaseConfig}

androidHardwareAccelerationDisabled

tryInvisibleVerification />` 我的 FirebaseRecaptchaVerifierModal 上的这一行,这将有助于解决我的问题。

** 修复 EXPO 45、46 **

在网上冲浪寻求答案后,我失败了,找不到任何东西可以让它在 Expo 45 和 Expo 46 上工作,最后把它交给我了,因为我们无法使用手动 recaptcha 发布应用程序,因为它非常糟糕 UX . 因此,在尝试了 FirebaseRecaptchaVerifierModal 中所有可能的道具后,我终于找到了工作修复

通过结合所有修复并添加我自己发现的一个,我终于可以安心地 rest 了,因为这正在工作

// Declare the Timeout for Initial Page Load Fix
  const [isInit, setisInit] = useState(false)
  useEffect(() => {
    setTimeout(function () {
      setisInit(true)
    }, 1000)
    return () => {
      setisInit(false)
    }
  }, [])

return(
<View>
...
        {isInit && (
          <FirebaseRecaptchaVerifierModal
            ref={recaptchaVerifier}
            firebaseConfig={app.options}
            androidHardwareAccelerationDisabled={true}
            androidLayerType="software"
            attemptInvisibleVerification
          />
        )}
...

      <FirebaseRecaptchaBanner />
</View>

这是神奇的线

 androidLayerType="software"

我希望 Expo 在那里更新文档并避免我们所有开发人员的这种痛苦经历,我的意思是在我发送垃圾邮件之前,我真的从未见过带有手动 Recaptcha 的应用程序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM