본문 바로가기

React-Native

[RN] React-Native에 Toss PG 연결하기 (version1)

RN 프로젝트에 TossPG를 연결하기 위해 심사 승인 후 토스페이먼츠 개발자 문서를 확인했다.


우선 결제는 위와 같은 flow로 이루어진다. 사용자 입장에서는 카드정보 입력, 인증이 완료되면 결제가 끝난 것 처럼 보이지만, 개발자는 이후 결제를 생성하고 승인 요청을 보낸 뒤 승인이 되어 실제로 결제가 이루어지도록 해주어야한다.


토스PG는 version 1, version 2로 나뉘어져있었다.

Version1에는 React-Native SDK 가이드가 있었고, Version2에는 따로 없었다. 다른분이 문의한 글을 봤는데 Version2도 RN에서 동작은 하지만 Version1을 써도 무방하며 Version1을 사용하고 답변이 되어있어서 Version1을 보며 진행하기로 했다.

    <AssetsProvider>
      <NavigationProvider>
        <NetworkProvider>
          <HardwareBackPressProvider>
            <AuthProvider>
              <PaymentWidgetProvider
                clientKey={`test_gck_docs_Ovk5rk1EwkEbP0W43n07xlzm`}
                customerKey={`oUhSaga2LunDqOF8t7bde`}
              >
                <ChannelProvider>{children}</ChannelProvider>
              </PaymentWidgetProvider>
            </AuthProvider>
            <ModalProvider />
            <BottomSheetProvider />
            <SnackBarProvider />
          </HardwareBackPressProvider>
        </NetworkProvider>
      </NavigationProvider>
    </AssetsProvider>


먼저 <App/>을 감싸는 EntryPoint에서 PaymentWidgetProvider를 감싸준다. 키는 우선 문서에 나와있는 테스트용 키를 사용했다.

import {
  AgreementWidgetControl,
  PaymentMethodWidget,
  PaymentMethodWidgetControl,
  usePaymentWidget,
} from "@tosspayments/widget-sdk-react-native";
import { theme } from "app/styles/theme";
import { useState } from "react";
import styled from "styled-components/native";

export default function TossPGWidget() {
  const paymentWidgetControl = usePaymentWidget();
  const [paymentMethodWidgetControl, setPaymentMethodWidgetControl] =
    useState<PaymentMethodWidgetControl | null>(null);
  const [agreementWidgetControl, setAgreementWidgetControl] =
    useState<AgreementWidgetControl | null>(null);

  return (
    <Container>
      <PaymentMethodWidget
        selector="payment-methods"
        onLoadEnd={() => {
          paymentWidgetControl
            .renderPaymentMethods(
              "payment-methods",
              { value: 50000 },
              {
                variantKey: "DEFAULT",
              }
            )
            .then((control) => {
              setPaymentMethodWidgetControl(control);
            });
        }}
      />
    </Container>
  );
}

const Container = styled.View`
  flex: 1;
  background-color: ${theme.colors.grayscale.white};
`;


이후 문서대로 위젯을 연결해주면,

결제 위젯이 렌더된다.

결제창을 띄우는 함수는 

function requestPayment({ paymentInfo: PaymentInfo }): Promise<Result | undefined>;


이다. 

PaymentInfo에 결제 정보를 담아서 보내며 

interface PaymentInfo {
  orderId: string;
  orderName: string;
  customerEmail?: string;
  customerName?: string;
  appScheme?: string;
  taxFreeAmount?: number;
  taxExemptionAmount?: string;
  cultureExpense?: boolean;
  useEscrow?: boolean;
  useInternationalCardOnly?: boolean;
  escrowProducts?: EscrowProduct[];
  customerMobilePhone?: string;
  showCustomerMobilePhone?: boolean;
  mobileCarrier?: string[];
  products?: Product[];
  shipping?: Shipping;
  paymentMethodOptions?: {
    payPal?: {
      setTransactionContext: any;
    };
  };
}


위와 같은 데이터가 포함된다. 각 데이터에 관한 설명은 토스페이먼츠 개발자센터에서 확인할 수 있다.

paymentWidgetControl
            .requestPayment?.({
              orderId: 'dIedNNboEQjZcwzwS2YJr',
              orderName: "토스 티셔츠 외 2건",
            })
            .then((result) => {
              if (result?.success) {
                // 결제 성공 비즈니스 로직을 구현하세요.
                // result.success에 있는 값을 서버로 전달해서 결제 승인을 호출하세요.
              } else if (result?.fail) {
                // 결제 실패 비즈니스 로직을 구현하세요.
              }
            });


requestPayment함수를 호출해 결제창을 띄우고 사용자가 입력한 카드정보, 카카오페이, 토스결제 등 정상적인 결제가 이루어졌을때 result에 success를 반환하게 된다. 이 때 실제 결제가 이루어져 돈이 빠져나가진 않고 이후 결제 승인 절차가 남아있다.

result.success가 true일때 결제 성공 비즈니스 로직을 구현해준다, 이후 서버 API로 result.success에 있는 값을 전송하고 서버에서는 결제 승인을 호출한다.

결제 승인까지 정상적으로 성공되면 결제가 완료된다.