몽땅뚝딱 개발자

[React Native] 토스 결제위젯, 브랜드페이 SDK 연동하기 본문

Development/React Native

[React Native] 토스 결제위젯, 브랜드페이 SDK 연동하기

레오나르도 다빈츠 2024. 8. 3. 19:17

 

 

 

 

 

 

담당자에게 Version 2는 React Native를 지원하지 않는다는 답변을 받은 후, Version 1으로 진행하게 되었다. 토스 문서(https://docs.tosspayments.com/sdk/widget-rn)에 링크되어있는 샘플 프로젝트로 간단히 연동할 수 있었다.

 


 

 

1. 설치하기

공식 문서에는 나와있지 않지만 tosspayments-react-native-webview도 함께 설치해야 한다. 자꾸 빌드가 안돼서 샘플 프로젝트랑 비교하면서 찾았다.

npm install @tosspayments/widget-sdk-react-native
npm install tosspayments-react-native-webview

 

 

2. 구현

NavigationContainer 안에서 <PaymentWidgetProvider>로 감싸주고 PaymentWidgetProvider에 clientKey(어드민에서 설정)와 customerKey(규격에 맞게 직접 발급)를 설정한다.

<NavigationContainer>
  <PaymentWidgetProvider clientKey="CLIENT_KEY" customerKey="CUSTOMER_KEY">
    <Stack.Navigator>
    // ....
    </Stack.Navigator>
  </TossPaymentControlProvider>
</NavigationContainer>

 

 

토스 어드민에서 설정한 커스텀 UI의 varientKey를 넣어준다.

import React, { useState } from 'react'
import { usePaymentWidget, AgreementWidget, PaymentMethodWidget } from '@tosspayments/widget-sdk-react-native'
import { Alert, Button } from 'react-native'
import type { AgreementWidgetControl, PaymentMethodWidgetControl } from '@tosspayments/widget-sdk-react-native'

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

  return (
    <>
      <PaymentMethodWidget
        selector="payment-methods"
        onLoadEnd={() => {
          paymentWidgetControl
            .renderPaymentMethods(
              'payment-methods',
              { value: 50000 },
              {
                variantKey: 'DEFAULT', // 토스 어드민 > UI 설정값
              },
            )
            .then((control) => {
              setPaymentMethodWidgetControl(control)
            })
        }}
      />
      <AgreementWidget
        selector="agreement"
        onLoadEnd={() => {
          paymentWidgetControl
            .renderAgreement('agreement', {
              variantKey: 'DEFAULT',
            })
            .then((control) => {
              setAgreementWidgetControl(control)
            })
        }}
      />
      <Button
        title="결제요청"
        onPress={async () => {
          if (paymentWidgetControl == null || agreementWidgetControl == null) {
            Alert.alert('주문 정보가 초기화되지 않았습니다.')
            return
          }

          const agreeement = await agreementWidgetControl.getAgreementStatus()
          if (agreeement.agreedRequiredTerms !== true) {
            Alert.alert('약관에 동의하지 않았습니다.')
            return
          }

          paymentWidgetControl
            .requestPayment?.({
              orderId: 'xucuO-uVCnioK2V3hSBIr',
              orderName: '토스 티셔츠 외 2건',
            })
            .then((result) => {
              if (result?.success) {
                // 결제 성공 비즈니스 로직을 구현하세요.
                // result.success에 있는 값을 서버로 전달해서 결제 승인을 호출하세요.
              } else if (result?.fail) {
                // 결제 실패 비즈니스 로직을 구현하세요.
              }
            })
        }}
      />
      <Button
        title="선택된 결제수단"
        onPress={async () => {
          if (paymentMethodWidgetControl == null) {
            Alert.alert('주문 정보가 초기화되지 않았습니다.')
            return
          }
          Alert.alert(`선택된 결제수단: ${JSON.stringify(await paymentMethodWidgetControl.getSelectedPaymentMethod())}`)
        }}
      />
      <Button
        title="결제 금액 변경"
        onPress={() => {
          if (paymentMethodWidgetControl == null) {
            Alert.alert('주문 정보가 초기화되지 않았습니다.')
            return
          }
          paymentMethodWidgetControl.updateAmount(100_000).then(() => {
            Alert.alert('결제 금액이 100000원으로 변경되었습니다.')
          })
        }}
      />
    </>
  )
}

 

 

 

 

 


 

 

💥 트러블슈팅

1. 'Widget이 이미 존재한다'

widget은 2개 이상을 띄울 수 없다.

 

2. 결제 비밀번호 입력 화면으로 넘어가지 않고 종료되는 현상

- 신용카드: 100원 이상

- 계좌: 200원 이상

을 결제 금액으로 넘겨야 한다.

<PaymentMethodWidget
  selector="payment-methods"
  onLoadEnd={() => {
    paymentWidgetControl
      .renderPaymentMethods(
        'payment-methods',
        { value: 0 }, // 0원으로 넘길 수 없다.
        {
          variantKey: 'CUSTOM_UI_KEY',
        },
      )
      .then((control) => {
        setPaymentMethodWidgetControl(control)
      })
  }}
/>

 

 

Comments