You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Native+Stripe API开发数字钱包的技术疑问求助

Hey there! Let's walk through how to get your React Native + Stripe wallet management setup sorted out—since you're already using a server as a middle layer, we can lean into that to keep things secure and compliant, which is critical when handling sensitive card data.

Core Security Rule to Stick To

First and foremost: never, ever send raw card details (number, CVV, expiration) to your own server. Stripe's entire ecosystem is built to handle PCI compliance for you, so we'll use their SDK to tokenize card data directly on the client, then pass only that secure token/identifier to your backend.

1. Adding Cards the Right Way

Use Stripe's React Native SDK to collect card info safely, no raw data touches your servers. Here's a step-by-step implementation:

Client-Side (React Native)

We'll use CardField for secure input and PaymentSheet to handle card verification via a Setup Intent (Stripe's tool for saving payment methods without charging immediately):

import { CardField, useStripe } from '@stripe/stripe-react-native';
import { View, Button, Alert } from 'react-native';

const AddCardScreen = ({ customerId }) => {
  const { initPaymentSheet, presentPaymentSheet } = useStripe();

  const handleAddCard = async () => {
    try {
      // Step 1: Fetch an ephemeral key from your server (short-lived, secure access to Stripe)
      const ephemeralRes = await fetch('/api/stripe/get-ephemeral-key', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ customerId }),
      });
      const ephemeralKey = await ephemeralRes.json();

      // Step 2: Fetch a Setup Intent client secret from your server
      const setupIntentRes = await fetch('/api/stripe/create-setup-intent', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ customerId }),
      });
      const setupIntent = await setupIntentRes.json();

      // Step 3: Initialize the PaymentSheet
      const { error: initError } = await initPaymentSheet({
        customerId,
        customerEphemeralKeySecret: ephemeralKey.secret,
        setupIntentClientSecret: setupIntent.clientSecret,
      });

      if (initError) throw initError;

      // Step 4: Present the PaymentSheet to confirm card addition
      const { error: presentError } = await presentPaymentSheet();
      if (presentError) throw presentError;

      // Success! Card is saved to Stripe—refresh your wallet list
      Alert.alert('Success', 'Card added to your wallet');
      // Trigger a refresh of your wallet UI here
    } catch (err) {
      Alert.alert('Oops', err.message || 'Failed to add card');
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <CardField
        postalCodeEnabled={true}
        placeholder={{ number: '4242 4242 4242 4242' }}
        cardStyle={{ backgroundColor: '#fff', textColor: '#000' }}
        style={{ height: 50, marginVertical: 20 }}
      />
      <Button title="Add Card" onPress={handleAddCard} />
    </View>
  );
};

export default AddCardScreen;

Server-Side (Example with Node.js/Express)

You need two endpoints here: one to generate the ephemeral key, and another to create the Setup Intent:

const stripe = require('stripe')('YOUR_STRIPE_SECRET_KEY');
const express = require('express');
const app = express();
app.use(express.json());

// Endpoint to get ephemeral key
app.post('/api/stripe/get-ephemeral-key', async (req, res) => {
  const { customerId } = req.body;
  const ephemeralKey = await stripe.ephemeralKeys.create(
    { customer: customerId },
    { apiVersion: '2024-06-20' } // Use your Stripe API version
  );
  res.json(ephemeralKey);
});

// Endpoint to create Setup Intent
app.post('/api/stripe/create-setup-intent', async (req, res) => {
  const { customerId } = req.body;
  const setupIntent = await stripe.setupIntents.create({
    customer: customerId,
    payment_method_types: ['card'],
  });
  res.json({ clientSecret: setupIntent.client_secret });
});

2. Managing Wallet: Fetch & Delete Cards

Fetching Saved Cards

Your server will fetch the user's saved payment methods from Stripe, sanitize the data (only return non-sensitive info), and send it to the client:

Server-Side

app.get('/api/user/wallet/cards', async (req, res) => {
  const { customerId } = req.query;
  try {
    const paymentMethods = await stripe.paymentMethods.list({
      customer: customerId,
      type: 'card',
    });
    // Sanitize data—never send full card numbers or CVVs!
    const sanitizedCards = paymentMethods.data.map(method => ({
      id: method.id,
      last4: method.card.last4,
      brand: method.card.brand,
      expMonth: method.card.exp_month,
      expYear: method.card.exp_year,
    }));
    res.json(sanitizedCards);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

Client-Side

Call this endpoint when your wallet screen loads, then render the cards in a list:

// In your WalletScreen component
useEffect(() => {
  const fetchCards = async () => {
    const res = await fetch(`/api/user/wallet/cards?customerId=${customerId}`);
    const cards = await res.json();
    setWalletCards(cards);
  };
  fetchCards();
}, [customerId]);

Deleting a Card

Send the payment method ID to your server, which will detach it from the Stripe customer:

Server-Side

app.delete('/api/user/wallet/card', async (req, res) => {
  const { paymentMethodId } = req.body;
  try {
    await stripe.paymentMethods.detach(paymentMethodId);
    res.json({ success: true });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

Client-Side

Add a delete button to each card in your list, call this endpoint on press, then update the local state:

const handleDeleteCard = async (paymentMethodId) => {
  const res = await fetch('/api/user/wallet/card', {
    method: 'DELETE',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ paymentMethodId }),
  });
  if (res.ok) {
    setWalletCards(prev => prev.filter(card => card.id !== paymentMethodId));
    Alert.alert('Success', 'Card removed');
  }
};

3. Critical Pitfalls to Avoid

  • Don't cache ephemeral keys: They expire quickly (usually 24 hours max), so fetch a new one every time you need to interact with Stripe from the client.
  • PCI Compliance: By using Stripe's SDK, you're automatically reducing your PCI scope—if you ever handle raw card data, you'll have to go through full PCI audits, which is a massive headache.
  • Error Handling: Stripe returns detailed error messages (e.g., "card declined", "invalid CVV")—use these to give users clear, actionable feedback instead of generic errors.
  • Link Users to Stripe Customers: Make sure every user in your app has a corresponding Stripe Customer object. This is how you tie payment methods to specific users.

4. UX Tips for Your Wallet

  • Show brand icons (Visa, Mastercard, etc.) next to each card—Stripe provides the brand in the payment method data, so you can map that to icons in your app.
  • Let users set a default payment method: Update the Stripe Customer's invoice_settings.default_payment_method via your server, then highlight that card in your UI.
  • Add loading states when fetching/deleting cards to keep users informed.

内容的提问来源于stack exchange,提问作者nik2o

火山引擎 最新活动