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

> Mở hosted checkout của Dodo Payments từ ứng dụng React Native trong một tab trình duyệt hệ thống và nhận kết quả có kiểu trong một lần gọi.

<Info>
  Đây là React Native checkout SDK chính thức của Dodo Payments, `@dodopayments/react-native-checkout`. SDK mở hosted checkout của Dodo trong một chế độ xem trình duyệt native và trả về một kết quả có kiểu. Lưu ý: có một package cũ, không liên quan tên là `dodopayments-react-native-sdk` (không có scope) với API hoàn toàn khác. Trang này chỉ mô tả package chính thức hiện tại có scope.
</Info>

<CardGroup cols={2}>
  <Card title="Checkout Sessions API" icon="cart-shopping" href="/developer-resources/checkout-session">
    Tạo checkout\_url mà SDK này sẽ mở từ backend của bạn.
  </Card>

  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Xem cách tích hợp bước này vào toàn bộ quy trình thanh toán trên thiết bị di động.
  </Card>
</CardGroup>

React Native SDK là một lớp bao bọc Turbo Module mỏng trên cùng các core native Swift và Kotlin. SDK mở `SFSafariViewController` trên iOS và Chrome Custom Tab trên Android, không chứa API key và không bao giờ gọi trực tiếp Dodo API. Toàn bộ logic checkout chạy trong trình duyệt; SDK chỉ quản lý vòng đời của view và lấy return URL.

<Warning>
  SDK này chỉ yêu cầu **New Architecture**, React Native 0.76+, iOS 16+ và Android `minSdk` 24.
</Warning>

## Cài đặt

<Steps>
  <Step title="Install the Package">
    <Tabs>
      <Tab title="Android">
        Package được autolink và kéo `com.dodopayments.api:checkout-android` từ Maven.

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

        Không cần thiết lập bổ sung; dependency native được tự động phân giải.
      </Tab>

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

        Swift core được đóng gói trong package và cài đặt thông qua CocoaPods.
      </Tab>

      <Tab title="Expo">
        Chỉ dành cho development builds (không phải Expo Go).

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

        Sau đó cấu hình `app.json` (xem phần Đăng ký Callback URL Scheme bên dưới).
      </Tab>
    </Tabs>
  </Step>

  <Step title="Register a Callback URL Scheme">
    Ứng dụng của bạn phải đăng ký một URL scheme để nhận return URL từ checkout.

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

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

        Thay `"myapp"` bằng scheme của ứng dụng.
      </Tab>

      <Tab title="iOS (Info.plist)">
        Trong `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>
        ```

        Bạn cũng có thể thêm thông tin này thông qua giao diện **Info → URL Types** của Xcode.
      </Tab>

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

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

        <Warning>
          Package cũng đi kèm một plugin cấu hình Expo `@dodopayments/react-native-checkout`,
          nhưng hiện tại plugin không ghi URL scheme và cũng không ghi manifest placeholder.
          Chỉ thêm plugin này sẽ **không** đăng ký callback scheme — hãy sử dụng cấu hình
          `expo-build-properties` và `infoPlist` ở trên.
        </Warning>

        <Note>
          Build lại native project sau khi chỉnh sửa `app.json`:

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

          Tính năng này chỉ hoạt động với development builds, không phải Expo Go.
        </Note>
      </Tab>
    </Tabs>
  </Step>
</Steps>

## Cách sử dụng

```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;
}
```

## Chuyển tiếp Return URL

Listener `Linking` là bắt buộc để xử lý return URL trên iOS. Trên Android, `handleOpenURL` không thực hiện thao tác nào và resolve `false` vì Android core xử lý redirect một cách native. Bạn có thể đăng ký listener này vô điều kiện trên cả hai nền tảng.

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

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

## Ý nghĩa của Result

<Warning>
  `result.status` là một gợi ý UI, không phải bằng chứng thanh toán. Xác nhận mọi payment từ backend của bạn thông qua webhook `payment.succeeded` / `subscription.active`.
</Warning>

<ParamField body="status" type="CheckoutStatus" required>
  Một trong các giá trị `succeeded`, `failed`, `cancelled`, `pending`, `expired`.
</ParamField>

<ParamField body="paymentId" type="string">
  Được đặt khi return URL có chứa giá trị này. Hiển thị giá trị trong UI, không dùng giá trị này để cấp quyền truy cập. Xem phần Xác minh Payment bên dưới.
</ParamField>

<ParamField body="subscriptionId" type="string">
  Được đặt cho subscription checkout.
</ParamField>

<ParamField body="licenseKeys" type="string[]">
  Được đặt khi checkout bao gồm các sản phẩm license key.
</ParamField>

<ParamField body="customerEmail" type="string">
  Được đặt khi checkout thu thập email.
</ParamField>

<ParamField body="raw" type="Record<string, string>">
  Mọi query parameter từ return URL, giữ nguyên văn.
</ParamField>

## Xác minh Payment

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/developer-resources/webhooks">
    Dodo Payments gọi backend của bạn khi payment thành công hoặc subscription được kích hoạt.
  </Card>

  <Card title="Get Payment Detail" icon="magnifying-glass" href="/api-reference/payments/get-payments-1">
    Tra cứu `paymentId` bằng secret key của bạn để kiểm tra trực tiếp trạng thái.
  </Card>
</CardGroup>

Chỉ cấp quyền truy cập sau khi một trong các bước xác nhận payment này hoàn tất, tuyệt đối không chỉ dựa vào `result.status`.

## Lỗi

`start` từ chối với một `CheckoutError` chỉ khi sử dụng sai hoặc nền tảng gặp lỗi. Payment bị hủy hoặc bị từ chối luôn được trả về dưới dạng result, không phải exception.

* `INVALID_CHECKOUT_URL`: không phải session URL của `checkout.dodopayments.com`.
* `INVALID_RETURN_URL`: không phải absolute URL hợp lệ.
* `ALREADY_IN_PROGRESS`: checkout đang chạy.
* `PLATFORM_ERROR`: lỗi nền tảng không mong đợi.

## Session bị bỏ dở

Nếu ứng dụng hoặc JS bundle bị dừng giữa chừng trong quá trình checkout, promise sẽ bị mất nhưng native layer vẫn giữ session. Khôi phục session ở lần mount tiếp theo và đối soát với backend của bạn.

```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();
}
```

## Liên quan

<CardGroup cols={2}>
  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Cùng một contract cho Android, iOS và Flutter.
  </Card>

  <Card title="Expo Boilerplate" icon="layer-group" href="/developer-resources/expo-boilerplate">
    Ví dụ Expo hoàn chỉnh với tích hợp checkout.
  </Card>
</CardGroup>
