> ## 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.

# Flutter

> Flutter에서 시스템 브라우저 탭으로 Dodo Payments의 호스팅 체크아웃을 열고 한 번의 호출로 타입이 지정된 결과를 받습니다.

<Info>
  이는 pub.dev의 공식 Dodo Payments Flutter 패키지입니다 (`dodopayments_checkout`
  ). 별도로 커뮤니티에서 제작한 패키지도 제공됩니다. 자세한 내용은
  [Community Projects](/community/projects)를 참조하세요.
</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>

`dodopayments_checkout`는 iOS에서 Dodo의 호스팅 체크아웃을
`SFSafariViewController`로, Android에서는 Chrome Custom Tab으로 엽니다 — 독립 실행형 [iOS](/developer-resources/sdks/ios) 및
[Android](/developer-resources/sdks/android) SDK에서 사용하는 것과 동일한 네이티브 코어입니다. 모든 체크아웃 로직은
이러한 네이티브 코어에 있으며, Dart 레이어는 타입이 지정된
[Pigeon](https://pub.dev/packages/pigeon) 채널을 통해 호출을 전달합니다. API key를 보유하지 않으며
Dodo Payments API를 직접 호출하지도 않습니다.

Flutter 3.44+ / Dart 3.12+, iOS 16+, Android `minSdk` 23이 필요합니다.

## 설치

<Steps>
  <Step title="Add the Dependency">
    ```yaml pubspec.yaml theme={null}
    dependencies:
      dodopayments_checkout: ^1.0.0
    ```
  </Step>

  <Step title="Register a Callback URL Scheme">
    <Tabs>
      <Tab title="iOS">
        `ios/Runner/Info.plist`에 스킴의 URL type을 추가합니다:

        ```xml ios/Runner/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>
        ```

        그런 다음 수신 URL을 (예: [`app_links`](https://pub.dev/packages/app_links)을 통해)
        SDK로 전달하세요. `SFSafariViewController`는 자체 return URL을 가로챌 수 없기 때문입니다:

        ```dart theme={null}
        import 'package:dodopayments_checkout/dodopayments_checkout.dart';

        DodoCheckout.instance.handleOpenURL(url);
        ```

        <Note>
          여기서는 모든 URL을 전달해도 안전합니다. `handleOpenURL`는 등록된 `returnUrl`와 일치하는 URL에만
          작동하며, 그 외의 모든 경우에는 `false`를 반환합니다.
        </Note>
      </Tab>

      <Tab title="Android">
        콜백 스킴을 Gradle manifest placeholder로 설정합니다:

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

        <Warning>
          `MainActivity`가 `android:taskAffinity=""`(기본 `flutter
                    create` 설정)으로 설정되어 있다면 제거하거나 SDK의 activity에 동일한 affinity를 지정하세요. 그렇지 않으면 일부 OEM Android 빌드에서 진행 중인 체크아웃이 손실되고 `PLATFORM_ERROR`가 반환될 수 있습니다.
        </Warning>
      </Tab>
    </Tabs>
  </Step>
</Steps>

## 사용법

```dart theme={null}
import 'package:dodopayments_checkout/dodopayments_checkout.dart';

final result = await DodoCheckout.instance.start(
  CheckoutParams(
    checkoutUrl: Uri.parse(checkoutUrl), // from your backend's checkout session
    returnUrl: Uri.parse('myapp://checkout/return'), // scheme must be registered (see Setup)
    onEvent: (event) => print(event.type), // logging only
  ),
);

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

## 결과의 의미

<Warning>
  `result.status`는 UI 힌트일 뿐 결제 완료의 증거가 아닙니다. 모든 결제를
  백엔드에서 `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에 표시하되 액세스 권한을 부여하는 데 사용하지 마세요. 아래의 Verify the Payment를 참조하세요.
</ParamField>

<ParamField body="subscriptionId" type="String?">
  subscription 체크아웃에 대해 설정됩니다.
</ParamField>

<ParamField body="licenseKeys" type="List<String>?">
  체크아웃에 license key 제품이 포함될 때 설정됩니다.
</ParamField>

<ParamField body="customerEmail" type="String?">
  체크아웃에서 이메일을 수집할 때 설정됩니다.
</ParamField>

<ParamField body="raw" type="Map<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>

이 중 하나가 결제를 확인한 후에만 액세스 권한을 부여하세요. `result.status`만으로 권한을 부여해서는 안 됩니다.

## 오류

`start`는 잘못된 사용이나 플랫폼 장애가 발생한 경우에만 `CheckoutException`를 발생시킵니다.
취소되거나 거부된 결제는 항상 예외가 아닌 결과로 반환됩니다.

* `invalidCheckoutUrl` (`INVALID_CHECKOUT_URL`): 유효한 `checkout.dodopayments.com` session URL이 아닙니다.
* `invalidReturnUrl` (`INVALID_RETURN_URL`): 유효한 absolute URL이 아닙니다.
* `alreadyInProgress` (`ALREADY_IN_PROGRESS`): 이미 checkout이 실행 중입니다.
* `platformError` (`PLATFORM_ERROR`): 예기치 않은 플랫폼 오류입니다.

## 중단된 세션

<Info>
  앱이 체크아웃 도중 종료되면 다음 실행 시 세션을 복구하고
  백엔드와 대조하여 상태를 조정하세요.
</Info>

```dart theme={null}
import 'package:dodopayments_checkout/dodopayments_checkout.dart';

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

## 관련 항목

<CardGroup cols={2}>
  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Android, iOS 및 React Native에 동일한 계약을 적용합니다.
  </Card>

  <Card title="Community Projects" icon="users" href="/community/projects">
    별도로 커뮤니티에서 제작한 Flutter 패키지도 제공됩니다.
  </Card>
</CardGroup>
