---
title: "Bật tính năng mua hàng với Flow Builder trong React Native SDK"
description: "Hướng dẫn nhanh để bật in-app purchase với Adapty Flow Builder."
---

Để bật tính năng in-app purchase, bạn cần nắm ba khái niệm quan trọng:
- [**Sản phẩm**](product) – những thứ người dùng có thể mua (gói đăng ký, consumable, quyền truy cập trọn đời)
- [**Flow**](adapty-flow-builder) – chuỗi màn hình hiển thị sản phẩm cho người dùng, được xây dựng trong Flow Builder không cần code. SDK lấy chúng qua `getFlow`. Nếu bạn muốn tự xây dựng giao diện trong code của mình, hãy dùng paywall thay thế — xem [Triển khai paywall thủ công](react-native-quickstart-manual).
- [**Placement**](placements) – nơi và thời điểm bạn hiển thị flow trong ứng dụng (ví dụ: `main`, `onboarding`, `settings`). Bạn gắn flow vào placement trong dashboard, sau đó yêu cầu chúng theo placement ID trong code. Cách này giúp dễ dàng chạy A/B test và hiển thị các flow khác nhau cho từng nhóm người dùng.
Adapty cung cấp cho bạn ba cách để tích hợp tính năng mua hàng trong ứng dụng. Hãy chọn một trong số đó tùy theo yêu cầu của ứng dụng:
| Triển khai | Độ phức tạp | Khi nào dùng |
|---|---|---|
| Adapty Flow Builder | ✅ Dễ | Bạn [tạo một flow hoàn chỉnh, sẵn sàng mua hàng trong trình tạo không cần code](quickstart-paywalls). Adapty tự động render và xử lý toàn bộ flow mua hàng, xác thực receipt và quản lý gói đăng ký. |
| Paywall tự tạo | 🟡 Trung bình | Bạn tự triển khai giao diện paywall trong code ứng dụng, nhưng vẫn lấy đối tượng flow từ Adapty để duy trì tính linh hoạt trong việc cung cấp sản phẩm. Xem [hướng dẫn](react-native-quickstart-manual). |
| Observer mode | 🔴 Khó | Bạn đã có hạ tầng xử lý mua hàng riêng và muốn tiếp tục sử dụng nó. Lưu ý rằng observer mode có một số hạn chế trong Adapty. Xem [bài viết](observer-vs-full-mode). |
:::important
**Các bước bên dưới hướng dẫn cách triển khai một flow được tạo trong Adapty Flow Builder.**

Nếu bạn muốn tự xây dựng giao diện paywall, hãy xem [Triển khai paywall thủ công](react-native-quickstart-manual).
:::

Để hiển thị một flow được tạo trong Adapty Flow Builder, trong code của ứng dụng, bạn chỉ cần:

1. **Lấy flow**: Lấy nó từ Adapty.
2. **Hiển thị và Adapty sẽ xử lý việc mua hàng cho bạn**: Hiển thị view trong ứng dụng.
3. **Xử lý các hành động nút**: Liên kết tương tác của người dùng với phản hồi tương ứng trong ứng dụng. Ví dụ: mở liên kết hoặc đóng flow khi người dùng nhấn các nút.
## Trước khi bắt đầu \{#before-you-start\}

Trước khi bắt đầu, hãy hoàn thành các bước sau:

1. Kết nối ứng dụng với [App Store](initial_ios) và/hoặc [Google Play](initial-android) trong Adapty Dashboard.
2. [Tạo sản phẩm](create-product) trong Adapty.
3. [Tạo paywall và thêm sản phẩm vào đó](create-paywall).
4. [Tạo placement và thêm paywall vào đó](create-placement).
5. [Cài đặt và kích hoạt Adapty SDK](sdk-installation-reactnative) trong code ứng dụng.

:::tip
Cách nhanh nhất để hoàn thành các bước này là làm theo [hướng dẫn quickstart](quickstart) hoặc tạo paywall và placement bằng [Developer CLI](developer-cli-quickstart).
:::

## 1. Lấy flow \{#1-get-the-flow\}

Các flow của bạn được liên kết với các placement được cấu hình trên dashboard. Placement cho phép bạn chạy các flow khác nhau cho các đối tượng khác nhau hoặc chạy [A/B test](ab-tests).

Để lấy một flow đã tạo trong Adapty Flow Builder, hãy lấy đối tượng `flow` theo ID [placement](placements) bằng phương thức `getFlow`. Flow chứa các phần tử UI và style cần thiết để hiển thị nó.
```typescript showLineNumbers title="React Native"

try {
  const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');
  // the requested flow
} catch (error) {
  // handle the error
}
```

## 2. Hiển thị flow \{#2-display-the-flow\}

Bây giờ, khi bạn đã có flow, chỉ cần thêm vài dòng code là có thể hiển thị nó.

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>

Để nhúng flow vào cây component hiện có của bạn, hãy sử dụng component `AdaptyFlowView` trực tiếp trong cấu trúc component React Native của bạn:
```typescript showLineNumbers title="React Native (TSX)"

function MyFlow({ flow }) {
  const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>(
    (result, product) => result.type !== 'user_cancelled',
    [],
  );

  return (
    <AdaptyFlowView
      flow={flow}
      style={{ flex: 1 }}
      onPurchaseCompleted={onPurchaseCompleted}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

Để hiển thị flow dưới dạng màn hình độc lập, hãy tạo một `view` bằng phương thức `createFlowView`, thiết lập các trình xử lý sự kiện, rồi gọi `view.present()`. Mỗi `view` chỉ có thể dùng một lần. Nếu bạn cần hiển thị flow lại, hãy gọi `createFlowView` thêm một lần nữa để tạo instance `view` mới.
```typescript showLineNumbers title="React Native"

try {
  const view = await createFlowView(flow);

  view.setEventHandlers({
    onPurchaseCompleted(result, product) {
      return result.type !== 'user_cancelled';
    },
  });

  await view.present();
} catch (error) {
  // handle the error
}
```

</TabItem>
</Tabs>

:::tip
Để biết thêm chi tiết về cách hiển thị một flow, xem [hướng dẫn](react-native-present-paywalls) của chúng tôi.
:::
## 3. Xử lý hành động của nút \{#handle-button-actions\}

Khi người dùng nhấn các nút trong flow, React Native SDK tự động xử lý việc mua hàng, khôi phục, đóng flow và mở URL.

Tuy nhiên, một số nút có ID tùy chỉnh hoặc được định nghĩa sẵn và yêu cầu bạn xử lý hành động trong code. Hoặc bạn có thể muốn ghi đè hành vi mặc định của chúng.

Ví dụ, đây là hành vi mặc định của nút đóng. Bạn không cần thêm đoạn code này, nhưng ở đây bạn có thể thấy cách thực hiện nếu cần.

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>
For the React component, handle actions directly in the `AdaptyFlowView` component:
```typescript showLineNumbers title="React Native (TSX)"

function MyFlow({ flow }) {
  const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(
    () => true, // allow the flow to close
    [],
  );
  const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>(
    (actionId) => false,
    [],
  );

  return (
    <AdaptyFlowView
      flow={flow}
      style={{ flex: 1 }}
      onCloseButtonPress={onCloseButtonPress}
      onCustomAction={onCustomAction}
    />
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">

Đối với modal presentation, hãy triển khai các trình xử lý sự kiện bằng `setEventHandlers`:

```typescript showLineNumbers title="React Native"
const unsubscribe = view.setEventHandlers({
  onCloseButtonPress() {
    return true; // allow the flow to close
  },
});
```

</TabItem>
</Tabs>

:::tip
Đọc hướng dẫn của chúng tôi về cách xử lý [actions](react-native-handle-paywall-actions) và [events](react-native-handling-events-1) của nút.
:::
## Các bước tiếp theo \{#next-steps\}

:::tip
Bạn có câu hỏi hoặc gặp sự cố? Hãy xem [diễn đàn hỗ trợ](https://adapty.featurebase.app/) của chúng tôi — nơi bạn có thể tìm câu trả lời cho các câu hỏi thường gặp hoặc đặt câu hỏi của riêng mình. Đội ngũ và cộng đồng của chúng tôi luôn sẵn sàng giúp đỡ!
:::

Paywall của bạn đã sẵn sàng để hiển thị trong ứng dụng. Hãy kiểm tra mua hàng trong [App Store sandbox](test-purchases-in-sandbox) hoặc trong [Google Play Store](testing-on-android) để đảm bảo bạn có thể hoàn tất một giao dịch mua thử từ paywall.

Tiếp theo, bạn cần [kiểm tra mức độ truy cập của người dùng](react-native-check-subscription-status) để đảm bảo bạn hiển thị paywall hoặc cấp quyền truy cập vào các tính năng trả phí cho đúng người dùng.

## Ví dụ đầy đủ \{#full-example\}

Dưới đây là cách tích hợp tất cả các bước trong hướng dẫn này vào ứng dụng của bạn.

<Tabs groupId="presentation-method" queryString>
<TabItem value="platform" label="React component" default>
```javascript showLineNumbers title="React Native (TSX)"

export default function FlowScreen() {
  const [flow, setFlow] = useState(null);

  const loadFlow = async () => {
    try {
      const flowData = await adapty.getFlow('YOUR_PLACEMENT_ID');
      setFlow(flowData);
    } catch (error) {
      console.warn('Error loading flow:', error);
    }
  };

  const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(
    () => true,
    [],
  );

  const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>(
    (result, product) => result.type !== 'user_cancelled',
    [],
  );

  useEffect(() => {
    loadFlow();
  }, []);

  return (
    <View style={{ flex: 1 }}>
      {flow ? (
        <AdaptyFlowView
          flow={flow}
          style={{ flex: 1 }}
          onCloseButtonPress={onCloseButtonPress}
          onPurchaseCompleted={onPurchaseCompleted}
        />
      ) : (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Button title="Load Flow" onPress={loadFlow} />
        </View>
      )}
    </View>
  );
}
```

</TabItem>
<TabItem value="standalone" label="Modal presentation">
```javascript showLineNumbers title="React Native"

export default function FlowScreen() {
  const showFlow = async () => {
    try {
      const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');

      const view = await createFlowView(flow);

      view.setEventHandlers({
        onCloseButtonPress() {
          return true;
        },
        onPurchaseCompleted(result, product) {
          return result.type !== 'user_cancelled';
        },
      });

      await view.present();
    } catch (error) {
      // handle any error that may occur during the process
      console.warn('Error showing flow:', error);
    }
  };

  // you can add a button to manually trigger the flow for testing purposes
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="Show Flow" onPress={showFlow} />
    </View>
  );
}
```

</TabItem>
</Tabs>