【发布时间】: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"
这些是我采取的步骤:
- 安装 stripe-react-native,并将其作为插件添加到我的 app.json 中:
"plugins": [
[
"@stripe/stripe-react-native",
{
"merchantIdentifier": "",
"enableGooglePay": false
}
]
],
- 在全局级别上,我导入 StripeProvider 组件并传递给定的可发布密钥:
pk_live_51[.....]
在全球范围内,它看起来像这样:
<StripeProvider
publishableKey="pk_live_51[...]"
>
<AuthProvider>
<ApolloProvider client={client}>
<InnerApp />
</ApolloProvider>
</AuthProvider>
</StripeProvider>
- 然后根据条带文档,在我将设置未来付款的组件中,我应该从后端获取 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_[...]",
},
},
- 根据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}
/>
- 无论如何,现在按钮终于启用了,用户可以点击它,它会调用以下函数:
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