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

# iOS

> Mở checkout được host của Dodo Payments từ ứng dụng iOS trong SFSafariViewController và nhận kết quả có kiểu trong một lần gọi.

<Info>
  Đây là iOS checkout SDK chính thức của Dodo Payments dành cho Swift. SDK mở checkout được host của Dodo trong một chế độ xem trình duyệt native và trả về một kết quả có kiểu.
</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 này vào toàn bộ quy trình thanh toán trên mobile.
  </Card>
</CardGroup>

iOS SDK mở checkout được host của Dodo trong `SFSafariViewController`, không lưu 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à bắt return URL.

Yêu cầu iOS 16+, Swift 6.

## Cài đặt

<Steps>
  <Step title="Add the Package">
    Trong Xcode, đi đến **File → Add Package Dependencies** và nhập:

    ```
    https://github.com/dodopayments/dodopayments-mobile-sdk-ios
    ```

    Chọn phiên bản 1.0.0 trở lên.

    Ngoài ra, thêm vào `Package.swift` của bạn:

    ```swift Package.swift theme={null}
    .package(url: "https://github.com/dodopayments/dodopayments-mobile-sdk-ios", from: "1.0.0")
    ```
  </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. Thêm nội dung này vào `Info.plist` của bạn:

    ```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 nội dung này thông qua giao diện **Info → URL Types** của Xcode.
  </Step>
</Steps>

## Cách sử dụng

```swift theme={null}
import DodoCheckout

let result = try await DodoCheckout.start(
    checkoutUrl: checkoutUrl,   // from your backend's checkout session
    returnUrl: URL(string: "myapp://checkout/return")!,
    onEvent: { event in print(event.name) }  // logging only
)

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

## Chuyển tiếp Return URL

`SFSafariViewController` không có cách nào trong tiến trình để tự bắt return URL. Ứng dụng của bạn phải chuyển tiếp các URL đến SDK.

<Tabs>
  <Tab title="SwiftUI">
    ```swift theme={null}
    .onOpenURL { url in
        DodoCheckout.handleOpenURL(url)
    }
    ```
  </Tab>

  <Tab title="SceneDelegate">
    ```swift SceneDelegate.swift theme={null}
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let url = URLContexts.first?.url else { return }
        DodoCheckout.handleOpenURL(url)
    }
    ```
  </Tab>
</Tabs>

<Note>
  Bạn có thể chuyển tiếp mọi URL tại đây một cách an toàn. `handleOpenURL` chỉ xử lý các URL khớp với `returnUrl` đã đăng ký của bạn và trả về `false` cho mọi URL khác.
</Note>

## Ý nghĩa của Result

<Warning>
  `result.status` là gợi ý UI, không phải bằng chứng thanh toán. Xác nhận mọi khoản thanh toán 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 thiết lập 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 Verify the Payment bên dưới.
</ParamField>

<ParamField body="subscriptionId" type="String?">
  Được thiết lập cho các checkout subscription.
</ParamField>

<ParamField body="licenseKeys" type="[String]?">
  Được thiết lập khi checkout bao gồm các sản phẩm có license key.
</ParamField>

<ParamField body="customerEmail" type="String?">
  Được thiết lập khi checkout thu thập email.
</ParamField>

<ParamField body="raw" type="[String: String]">
  Mọi query parameter từ return URL, được giữ nguyê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 một khoản thanh toán thành công hoặc một 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 cơ chế này xác nhận thanh toán, không bao giờ chỉ dựa vào `result.status`.

## Errors

`start` chỉ throw `CheckoutError` khi sử dụng sai hoặc nền tảng gặp lỗi. Khoản thanh toán bị hủy hoặc bị từ chối luôn là một result, không phải exception.

* `invalidCheckoutUrl` (`INVALID_CHECKOUT_URL`): không phải URL session `checkout.dodopayments.com`.
* `invalidReturnUrl` (`INVALID_RETURN_URL`): không phải absolute URL hợp lệ.
* `alreadyInProgress` (`ALREADY_IN_PROGRESS`): một checkout đang chạy.
* `platformError` (`PLATFORM_ERROR`): lỗi nền tảng không mong đợi.

## Session bị bỏ dở

<Info>
  Nếu ứng dụng bị tắt giữa chừng trong quá trình checkout, hãy khôi phục session vào lần khởi chạy tiếp theo và đối soát session đó với backend của bạn.
</Info>

```swift theme={null}
import DodoCheckout

if let abandoned = DodoCheckout.getAbandonedSession() {
    // reconcile abandoned.sessionId with your backend, then:
    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, React Native và Flutter.
  </Card>

  <Card title="React Native SDK" icon="react" href="/developer-resources/sdks/react-native">
    Bọc cùng Swift core này trên iOS.
  </Card>
</CardGroup>
