【问题标题】:Expo, React Native, Stripe: Setting up future payment methods not workingExpo、React Native、Stripe:设置未来的付款方式不起作用
【发布时间】:2022-01-19 01:59:08
【问题描述】:

我急需帮助。

所以我有一个使用 Expo / React Native 的 iOS 应用程序的副项目。我在使用 Stripe & Expo 的 Stripe 库设置未来的付款方式时遇到了问题。

我们的后端设置了一个 graphql 后端,并为我提供了我需要的所有变量。我正在尝试设置未来的付款以稍后向客户收费,但是在创建意图并从我们的后端获取 clientSecret、ephemeralKey 和 customerId 后,我遇到了 paymentIntentSheet 未显示的问题。现在我不知道问题出在哪里..是因为我使用了错误的版本吗?可能安装不正确?我使用的变量是否正确..?

我使用以下文档页面作为指南: https://stripe.com/docs/payments/save-and-reuse?platform=react-native https://github.com/stripe/stripe-react-native#expo

这些是我正在使用的库的版本号,与此主题/问题相关:

"expo": "~41.0.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"@stripe/stripe-react-native": "0.1.1"

这些是我采取的步骤:

  1. 安装 stripe-react-native,并将其作为插件添加到我的 app.json 中:
"plugins": [
            [
                "@stripe/stripe-react-native",
                {
                    "merchantIdentifier": "",
                    "enableGooglePay": false
                }
            ]
        ],
  1. 在全局级别上,我导入 StripeProvider 组件并传递给定的可发布密钥: pk_live_51[.....]

在全球范围内,它看起来像这样:

<StripeProvider
publishableKey="pk_live_51[...]"
        >
            <AuthProvider>
                <ApolloProvider client={client}>
                    <InnerApp />
                </ApolloProvider>
            </AuthProvider>
        </StripeProvider>
  1. 然后根据条带文档,在我将设置未来付款的组件中,我应该从后端获取 setupIntent、ephemeralKey 和客户。在这种情况下,它是在我的组件的 useEffect 中完成的。我获得了一个 graphql 突变来获得这些值:
mutation (
        $createUserPaymentMethodSetupIntentInput: CreateUserPaymentMethodSetupIntentInput!
    ) {
        createUserPaymentMethodSetupIntent(
            input: $createUserPaymentMethodSetupIntentInput
        ) {
            setupIntentId
            clientSecret
            customerId
            ephemeralKeySecret
        }
    }

然后我调用最终会为我提供所有必要变量的函数:


createIntent({
            variables: {
                createUserPaymentMethodSetupIntentInput: {
                    userUid: userUid,
                },
            },
        })
            .then((res) => {
                const clientSecret =
                    res.data.createUserPaymentMethodSetupIntent.clientSecret
                const setupIntentId =
                    res.data.createUserPaymentMethodSetupIntent.setupIntentId
                const ephemeralKeySecret =
                res.data.createUserPaymentMethodSetupIntent.ephemeralKeySecret
                const customerId =
                    res.data.createUserPaymentMethodSetupIntent.customerId
                
                // IGNORE THIS FOR NOW
                initializePaymentSheet(
                    clientSecret,
                    setupIntentId,
                    ephemeralKeySecret,
                    customerId
                )
            })
            .catch((err) => console.log({ graphqlError: err }))

该函数给了我以下响应:

Object {
  "data": Object {
    "createUserPaymentMethodSetupIntent": Object {
      "__typename": "CreatedUserPaymentMethodSetupIntent",
      "clientSecret": "seti_1K[....]",
      "customerId": "cus_[...]",
      "ephemeralKeySecret": "ek_live_[...]",
      "setupIntentId": "seti_[...]",
    },
  },
  1. 根据docs,我应该使用 setupIntent、ephemeralKey 和 customer 值作为其给定函数/钩子之一中的变量,称为“initPaymentSheet”,该函数/钩子应该初始化支付表。

这些函数是这样导入的:

const { initPaymentSheet, presentPaymentSheet } = useStripe();

在第 3 步中,您会看到我调用了一个函数,该函数在成功从服务器获取值后调用 initPaymentSheet。

initializePaymentSheet(
                    clientSecret,
                    setupIntentId,
                    ephemeralKeySecret,
                    customerId
                )

initializePaymentSheet 函数如下所示:

const initializePaymentSheet = (
        clientSecret,
        setupIntentId,
        ephemeralKeySecret,
        customerId
    ) => {
        initPaymentSheet({
            customerId: customerId,
            customerEphemeralKeySecret: ephemeralKeySecret,
            setupIntentClientSecret: setupIntentId,
        })
            .then((res) => {
                console.log(res)
                setDisabledButton(false)
            })
            .catch((err) => console.log("error.."))
    }

如您所见,我在那里调用 initPaymentSheet 钩子,与文档中显示的完全一样,并传入我从后端收到的值。但是,这样做之后,我在控制台中收到以下错误:

Object {
  "error": Object {
    "code": "Failed",
    "message": "You must provide the paymentIntentClientSecret",
  },
}

这似乎不是一个大错误,所以我继续并通过添加 paymentIntentClientSecret 字段来更改 initPaymentSheet 参数,并传入以前未使用的 clientSecret 值:

initPaymentSheet({
            customerId: customerId,
            customerEphemeralKeySecret: ephemeralKeySecret,
            setupIntentClientSecret: setupIntentId,
            paymentIntentClientSecret: clientSecret
        })
            .then((res) => {
                console.log(res)
                setDisabledButton(false)
            })
            .catch((err) => console.log("little error.."))

调用该函数后,看到错误消失,上面显示的console.log在控制台中记录了以下内容:

Object {
  "paymentOption": null,
}

我并没有想太多,并认为它显示为 null 只是因为我之前没有设置 paymentOptions。我很高兴没有更多的错误。 在 .then 链中,您会看到我启用了一个按钮,该按钮基本上允许用户调用一个函数,该函数将显示一个支付表,用户可以在其中提交他们的 paymentMethod。此按钮已禁用,因为我认为您应该先初始化 paymentSheet 再启用它?

<WideButton
                disabled={disabledButton}
                text="Add New Payment Method"
                clicked={openPaymentSheet}
            />
  1. 无论如何,现在按钮终于启用了,用户可以点击它,它会调用以下函数:
const openPaymentSheet = async () => {
        setDisabledButton(true)
        const { error, paymentOption } = await presentPaymentSheet()

        if (error) {
            console.log(error)
            setDisabledButton(false)
            Alert.alert(`Error code: ${error.code}`, error.message)
        }

        if (paymentOption) {
            setDisabledButton(false)
            Alert.alert(
                "Success",
                "Your payment method is successfully set up for future payments!"
            )
            console.log(paymentOption)
        }

    
    }

现在引用条纹docs: 当您的客户点击设置按钮时,调用 presentPaymentSheet() 打开工作表。在客户完成设置他们的付款方式以供将来使用后,工作表将被关闭,并且承诺会通过可选的 StripeError 解决。

所以,这正是我所做的:调用 presentPaymentSheet,但随后出现以下错误:

Object {
  "code": "Failed",
  "message": "There was an unexpected error -- try again in a few seconds",
}

现在这就是我卡住的地方,因为它没有为我提供比上面提供的更多信息。我试过到处寻找,一些资源告诉我应该更新我的条带,有人说我应该在 app.json 中将条带添加到我的插件中。我已经完成了所有这些,但我仍然无法弄清楚。

这是一个视频,向您展示实际行为: https://user-images.githubusercontent.com/29804130/146274443-82c581ba-8913-4c87-ad2e-5b8719680fed.mov

下面是整个组件的代码:


// steps
// 1. call graphql query to set up intent, retrieve the clientsecret and setupintentid
// 2. call stripes initPaymentSheet's function and pass in useruid, clientsecret and setupintentid
// 3. when  initpaymentsheet is ready, enable button for user to add payment information
// 4. Retrieve the payment information and call the createpaymentmethod mutation
// 5. disable button again, and refresh page

export default function PaymentMethods({ userUid }) {
    const { initPaymentSheet, presentPaymentSheet } = useStripe()

    const [disabledButton, setDisabledButton] = useState(false)

    const [createIntent, { data, loading, error }] = useMutation(
        ADD_PAYMENT_METHOD_INTENT
    )

    useEffect(() => {
        createUserPaymentMethodIntent()
    }, [])

    const createUserPaymentMethodIntent = () => {
        setDisabledButton(true)

        createIntent({
            variables: {
                createUserPaymentMethodSetupIntentInput: {
                    userUid: userUid,
                },
            },
        })
            .then((res) => {
                console.log(res)

                const clientSecret =
                    res.data.createUserPaymentMethodSetupIntent.clientSecret
                const setupIntentId =
                    res.data.createUserPaymentMethodSetupIntent.setupIntentId
                const ephemeralKeySecret =
                    res.data.createUserPaymentMethodSetupIntent.ephemeralKeySecret
                const customerId =
                    res.data.createUserPaymentMethodSetupIntent.customerId

                initializePaymentSheet(
                    clientSecret,
                    setupIntentId,
                    ephemeralKeySecret,
                    customerId
                )
            })
            .catch((err) => console.log({ graphqlError: err }))
    }

    const initializePaymentSheet = (
        clientSecret,
        setupIntentId,
        ephemeralKeySecret,
        customerId
    ) => {
        initPaymentSheet({
            customerId: customerId,
            customerEphemeralKeySecret: ephemeralKeySecret,
            setupIntentClientSecret: setupIntentId,
            paymentIntentClientSecret: clientSecret,
        })
            .then((res) => {
                console.log(res)
                setDisabledButton(false)
            })
            .catch((err) => console.log("little error.."))
    }

    const openPaymentSheet = async () => {
        setDisabledButton(true)

        const { error } = await presentPaymentSheet()

        if (error) {
            Alert.alert(`Error code: ${error.code}`, error.message)
        } else {
            Alert.alert(
                "Success",
                "Your payment method is successfully set up for future payments!"
            )
        }
    }

    return (
        <ScrollView>
            <PaymentMethodList userUid={userUid} />
            <WideButton
                disabled={disabledButton}
                text="Add New Payment Method"
                clicked={openPaymentSheet}
            />
        </ScrollView>
    )
}

请大家帮忙:(

【问题讨论】:

    标签: ios reactjs react-native expo stripe-payments


    【解决方案1】:

    您可能想要检查 Stripe 仪表板中的日志(仪表板 -> 开发人员 -> 日志)。从那里您将能够看到有关此错误的更多信息,

    【讨论】:

      猜你喜欢
      • 2021-10-21
      • 2021-09-09
      • 2022-01-19
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多