> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React Native

> React Native 앱에서 시스템 브라우저 탭으로 Dodo Payments의 호스팅 checkout을 열고 한 번의 호출로 typed result를 받습니다.

<Info>
  공식 Dodo Payments React Native checkout SDK인 `@dodopayments/react-native-checkout`입니다. 이 SDK는 네이티브 브라우저 뷰에서 Dodo의 호스팅 checkout을 열고 typed result를 반환합니다. 참고: 이와 관련이 없는 이전 패키지 `dodopayments-react-native-sdk` (unscoped)가 존재하며, API가 완전히 다릅니다. 이 페이지에서는 현재 공식 scoped package만 설명합니다.
</Info>

<CardGroup cols={2}>
  <Card title="Checkout Sessions API" icon="cart-shopping" href="/developer-resources/checkout-session">
    백엔드에서 이 SDK가 열 checkout\_url을 생성합니다.
  </Card>

  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    전체 모바일 결제 흐름에서 어떻게 연동되는지 확인하세요.
  </Card>
</CardGroup>

React Native SDK는 동일한 네이티브 Swift 및 Kotlin 코어를 감싸는 얇은 Turbo Module wrapper입니다. iOS에서는 `SFSafariViewController`를, Android에서는 Chrome Custom Tab을 열며, API key를 보유하지 않고 Dodo API를 직접 호출하지도 않습니다. 모든 checkout 로직은 브라우저에서 실행되며, SDK는 뷰 lifecycle을 관리하고 return URL을 캡처하기만 합니다.

<Warning>
  이 SDK는 **New Architecture만 지원**하며, React Native 0.76+, iOS 16+, Android `minSdk` 24가 필요합니다.
</Warning>

## 설치

<Steps>
  <Step title="Install the Package">
    <Tabs>
      <Tab title="Android">
        패키지는 autolink되며 Maven에서 `com.dodopayments.api:checkout-android`를 가져옵니다.

        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        ```

        추가 설정은 필요하지 않습니다. 네이티브 dependency가 자동으로 resolve됩니다.
      </Tab>

      <Tab title="iOS">
        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        cd ios && pod install
        ```

        Swift 코어는 패키지에 포함되어 있으며 CocoaPods를 통해 설치됩니다.
      </Tab>

      <Tab title="Expo">
        Development builds에서만 사용할 수 있으며 Expo Go에서는 사용할 수 없습니다.

        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        npx expo install expo-build-properties
        ```

        그런 다음 `app.json`를 설정합니다(아래의 Register a Callback URL Scheme 참조).
      </Tab>
    </Tabs>
  </Step>

  <Step title="Register a Callback URL Scheme">
    앱은 checkout에서 반환되는 return URL을 수신할 수 있도록 URL scheme을 등록해야 합니다.

    <Tabs>
      <Tab title="Android (Gradle)">
        `android/app/build.gradle`에서:

        ```kotlin android/app/build.gradle theme={null}
        android {
            defaultConfig {
                manifestPlaceholders["dodoCallbackScheme"] = "myapp"
            }
        }
        ```

        `"myapp"`를 앱의 scheme으로 바꿉니다.
      </Tab>

      <Tab title="iOS (Info.plist)">
        `ios/YourApp/Info.plist`에서:

        ```xml Info.plist theme={null}
        <key>CFBundleURLTypes</key>
        <array>
          <dict>
            <key>CFBundleURLName</key>
            <string>myapp</string>
            <key>CFBundleURLSchemes</key>
            <array>
              <string>myapp</string>
            </array>
          </dict>
        </array>
        ```

        Xcode의 **Info → URL Types** UI를 통해 추가할 수도 있습니다.
      </Tab>

      <Tab title="Expo (both platforms)">
        `app.json`에서:

        ```json app.json theme={null}
        {
          "expo": {
            "plugins": [
              [
                "expo-build-properties",
                {
                  "android": {
                    "manifestPlaceholders": {
                      "dodoCallbackScheme": "myapp"
                    }
                  }
                }
              ]
            ],
            "ios": {
              "infoPlist": {
                "CFBundleURLTypes": [
                  {
                    "CFBundleURLSchemes": ["myapp"]
                  }
                ]
              }
            }
          }
        }
        ```

        <Warning>
          패키지에는 `@dodopayments/react-native-checkout` Expo config
          plugin도 포함되어 있지만, 현재는 URL scheme과 manifest placeholder를 작성하지 않습니다.
          이것만 추가해도 callback scheme은 **등록되지 않습니다**. 위의
          `expo-build-properties` 및 `infoPlist` 설정을 사용하세요.
        </Warning>

        <Note>
          `app.json`를 수정한 후 네이티브 프로젝트를 다시 빌드합니다:

          ```sh theme={null}
          npx expo prebuild --clean
          ```

          이는 development builds에서만 작동하며 Expo Go에서는 작동하지 않습니다.
        </Note>
      </Tab>
    </Tabs>
  </Step>
</Steps>

## 사용법

```typescript theme={null}
import { Linking } from 'react-native';
import { DodoCheckout } from '@dodopayments/react-native-checkout';

// Required for iOS's return-URL handling.
Linking.addEventListener('url', ({ url }) => DodoCheckout.handleOpenURL(url));

const result = await DodoCheckout.start({
  checkoutUrl,                          // from your backend's checkout session
  returnUrl: 'myapp://checkout/return', // scheme must be registered (see Installation)
  onEvent: (e) => console.log(e.type),  // logging only
});

switch (result.status) {
  case 'succeeded': showSuccess(result.paymentId); break;
  case 'failed':    showFailure(); break;
  case 'cancelled': dismiss(); break;
  case 'pending':   showPending(); break;
  case 'expired':   showExpired(); break;
}
```

## Return URL 전달

`Linking` listener는 iOS의 return-URL 처리를 위해 필요합니다. Android에서는 `handleOpenURL`가 `false`를 resolve하는 no-op입니다. Android 코어가 redirect를 네이티브로 처리하기 때문입니다. 두 플랫폼 모두에서 listener를 조건 없이 등록해도 안전합니다.

```typescript theme={null}
import { Linking } from 'react-native';
import { DodoCheckout } from '@dodopayments/react-native-checkout';

Linking.addEventListener('url', ({ url }) => {
  DodoCheckout.handleOpenURL(url);
});
```

## Result의 의미

<Warning>
  `result.status`는 UI hint일 뿐 결제가 완료되었다는 증거가 아닙니다. `payment.succeeded` / `subscription.active` webhook을 통해 백엔드에서 모든 결제를 확인하세요.
</Warning>

<ParamField body="status" type="CheckoutStatus" required>
  `succeeded`, `failed`, `cancelled`, `pending`, `expired` 중 하나입니다.
</ParamField>

<ParamField body="paymentId" type="string">
  return URL에 해당 값이 포함된 경우 설정됩니다. UI에 표시하되 access 권한을 부여하는 데 사용하지 마세요. 자세한 내용은 아래의 Verify the Payment를 참조하세요.
</ParamField>

<ParamField body="subscriptionId" type="string">
  subscription checkout에 설정됩니다.
</ParamField>

<ParamField body="licenseKeys" type="string[]">
  checkout에 license key product가 포함된 경우 설정됩니다.
</ParamField>

<ParamField body="customerEmail" type="string">
  checkout에서 email을 수집하는 경우 설정됩니다.
</ParamField>

<ParamField body="raw" type="Record<string, string>">
  return URL의 모든 query parameter를 원문 그대로 포함합니다.
</ParamField>

## 결제 확인

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/developer-resources/webhooks">
    결제가 성공하거나 subscription이 활성화되면 Dodo Payments가 백엔드를 호출합니다.
  </Card>

  <Card title="Get Payment Detail" icon="magnifying-glass" href="/api-reference/payments/get-payments-1">
    secret key를 사용해 `paymentId`를 조회하여 상태를 직접 확인합니다.
  </Card>
</CardGroup>

이 중 하나가 결제를 확인한 후에 access 권한을 부여하세요. `result.status`만으로는 절대 부여하지 마세요.

## Errors

`start`는 오용 또는 플랫폼 failure가 발생한 경우에만 `CheckoutError`와 함께 reject됩니다. 취소되거나 거절된 결제는 항상 result로 반환되며 exception이 발생하지 않습니다.

* `INVALID_CHECKOUT_URL`: 유효한 `checkout.dodopayments.com` session URL이 아닙니다.
* `INVALID_RETURN_URL`: 유효한 absolute URL이 아닙니다.
* `ALREADY_IN_PROGRESS`: checkout이 이미 실행 중입니다.
* `PLATFORM_ERROR`: 예상하지 못한 플랫폼 failure입니다.

## Abandoned Sessions

checkout 도중 앱 또는 JS bundle이 종료되면 promise는 유실되지만 네이티브 레이어는 session을 유지합니다. 다음 mount 시 session을 복구하고 백엔드와 reconcile하세요.

```typescript theme={null}
import { DodoCheckout } from '@dodopayments/react-native-checkout';

const abandoned = await DodoCheckout.getAbandonedSession();
if (abandoned) {
  // reconcile abandoned.sessionId with your backend, then:
  await DodoCheckout.clearAbandonedSession();
}
```

## 관련 문서

<CardGroup cols={2}>
  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Android, iOS, Flutter에 동일한 contract를 적용하는 방법입니다.
  </Card>

  <Card title="Expo Boilerplate" icon="layer-group" href="/developer-resources/expo-boilerplate">
    checkout integration이 포함된 완전한 Expo 예제입니다.
  </Card>
</CardGroup>
