# REACT-NATIVE - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: vi Generated on: 2026-07-24T13:01:43.502Z Total files: 45 --- # File: sdk-installation-react-native-expo --- --- title: "Install & configure Adapty React Native SDK in an Expo project" description: "Step-by-step guide on installing Adapty React Native SDK in an Expo project for subscription-based apps." --- :::important Hướng dẫn này đề cập đến việc cài đặt và cấu hình Adapty React Native SDK **trong một dự án Expo**. Nếu bạn đang sử dụng **React Native thuần (không có Expo)**, hãy làm theo [hướng dẫn cài đặt React Native](sdk-installation-react-native-pure) thay thế. ::: Adapty SDK bao gồm hai module chính để tích hợp liền mạch vào ứng dụng React Native của bạn: - **Core Adapty**: Module này bắt buộc phải có để Adapty hoạt động đúng trong ứng dụng của bạn. - **AdaptyUI**: Module này cần thiết nếu bạn sử dụng [Adapty Paywall Builder](adapty-paywall-builder), công cụ no-code thân thiện giúp tạo paywall đa nền tảng dễ dàng. AdaptyUI được kích hoạt tự động cùng với module core. Nếu bạn muốn xem hướng dẫn đầy đủ về cách triển khai IAP trong ứng dụng React Native, hãy xem [tại đây](https://adapty.io/blog/react-native-in-app-purchases-tutorial/). :::tip Bạn muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng Expo? Hãy xem các ứng dụng mẫu của chúng tôi: - [Expo dev build sample](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) — đầy đủ chức năng bao gồm mua hàng thực tế và Paywall Builder - [Expo Go & Web sample](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) — kiểm thử với chế độ mock ::: Để xem hướng dẫn triển khai đầy đủ, bạn có thể xem video sau:
## Yêu cầu \{#requirements\} Adapty React Native SDK yêu cầu iOS 15.0+. Để build cho iOS cần có **Swift 6.0** trở lên. [Kids Mode](kids-mode-react-native) yêu cầu **Swift 6.1** trở lên. :::info Từ SDK v3.17, Adapty SDK sử dụng Google Play Billing Library v8.0.0 theo mặc định. ::: :::info Cài đặt SDK là bước 5 trong quá trình thiết lập Adapty. Trước khi các giao dịch mua hàng hoạt động trong ứng dụng, bạn cần kết nối ứng dụng với các cửa hàng, sau đó tạo sản phẩm, paywall và placement trong Adapty Dashboard. [Hướng dẫn quickstart](quickstart) sẽ hướng dẫn bạn qua tất cả các bước cần thiết. ::: ## Cài đặt Adapty SDK \{#install-adapty-sdk\} :::important Kể từ v4, Adapty React Native SDK không còn hỗ trợ cài đặt các thư viện native phụ thuộc qua CocoaPods. Nếu bạn cần v4 trở lên (dành cho [Flow Builder](adapty-flow-builder)), hãy làm theo hướng dẫn [Adapty SDK 4.0: enable Swift Package Manager](#adapty-sdk-40-enable-swift-package-manager) bên dưới. ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) :::important [Expo Dev Client](https://docs.expo.dev/versions/latest/sdk/dev-client/) (một bản build phát triển tùy chỉnh) là bắt buộc để sử dụng Adapty trong dự án Expo. Expo Go không hỗ trợ các native module tùy chỉnh, vì vậy bạn chỉ có thể dùng nó với [**chế độ mock**](#set-up-mock-mode-for-expo-go--expo-web) để phát triển UI/logic (không có giao dịch mua thật và không có AdaptyUI/Paywall Builder). ::: 1. Cài đặt Adapty SDK (thao tác này cũng tự động cài `@adapty/core`): ```sh npx expo install react-native-adapty npx expo prebuild ``` 2. Build ứng dụng cho môi trường phát triển bằng EAS hoặc local build: ```sh # For iOS eas build --profile development --platform ios # For Android eas build --profile development --platform android ``` ```sh # For iOS npx expo run:ios # For Android npx expo run:android ``` 3. Khởi động dev server: ```sh npx expo start --dev-client ``` ### Adapty SDK 4.0: bật Swift Package Manager \{#adapty-sdk-40-enable-swift-package-manager\} React Native SDK 4.0 — bổ sung hỗ trợ [Flow Builder](adapty-flow-builder) — yêu cầu **React Native 0.75 trở lên**. Cài đặt SDK: ```sh npx expo install react-native-adapty@^4.0.0 ``` v4 kéo các iOS SDK gốc (`Adapty`, `AdaptyUI`, `AdaptyPlugin`) thông qua Swift Package Manager thay vì CocoaPods sub-dependencies ([Repo spec của CocoaPods sẽ chuyển sang chế độ chỉ đọc vào tháng 12 năm 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). SPM yêu cầu dynamic frameworks, mà trong Expo bạn bật bằng plugin [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/). Thêm nó vào `app.json` (hoặc `app.config.js`): ```json showLineNumbers title="app.json" { "expo": { "plugins": [ [ "expo-build-properties", { "ios": { "useFrameworks": "dynamic" } } ] ] } } ``` Sau đó cài đặt plugin và tạo lại native project: ```sh npx expo install expo-build-properties npx expo prebuild --clean ``` Xem [Hướng dẫn migration Adapty React Native SDK lên v4](migration-to-react-native-sdk-v4) để biết đầy đủ các bước migration. ## Kích hoạt module Adapty của Adapty SDK \{#activate-adapty-module-of-adapty-sdk\} Để lấy **Public SDK Key**: 1. Truy cập Adapty Dashboard và điều hướng đến [**App settings → General**](https://app.adapty.io/settings/general). 2. Trong phần **Api keys**, sao chép **Public SDK Key** (KHÔNG phải Secret Key). 3. Thay thế `"YOUR_PUBLIC_SDK_KEY"` trong code. Hoặc lấy theo cách lập trình, sử dụng [Adapty CLI](developer-cli): ``` npm install -g adapty adapty auth login adapty apps list ``` Hoặc, trực tiếp: ``` npx adapty auth login adapty apps list ``` - Đảm bảo bạn sử dụng **Public SDK key** để khởi tạo Adapty, **Secret key** chỉ nên dùng cho [server-side API](getting-started-with-server-side-api). - **SDK keys** là duy nhất cho mỗi ứng dụng, vì vậy nếu bạn có nhiều ứng dụng, hãy đảm bảo chọn đúng key. Sao chép đoạn code sau vào `App.tsx` để kích hoạt Adapty: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important Hãy đợi `activate` hoàn tất trước khi gọi bất kỳ phương thức nào khác của Adapty SDK. Xem [Thứ tự gọi trong React Native SDK](react-native-sdk-call-order) để biết toàn bộ trình tự. ::: Bây giờ hãy thiết lập paywall trong ứng dụng của bạn: - Nếu bạn dùng [Adapty Paywall Builder](adapty-paywall-builder), hãy xem [hướng dẫn nhanh về Paywall Builder](react-native-quickstart-paywalls). - Nếu bạn tự xây dựng giao diện paywall, hãy xem [hướng dẫn nhanh cho paywall tùy chỉnh](react-native-quickstart-manual). :::tip Để tránh lỗi kích hoạt trong môi trường phát triển, hãy xem các [mẹo](#development-environment-tips). ::: ## Kích hoạt module AdaptyUI của Adapty SDK \{#activate-adaptyui-module-of-adapty-sdk\} Nếu bạn có kế hoạch sử dụng [Paywall Builder](adapty-paywall-builder), bạn cần module AdaptyUI. Module này sẽ được kích hoạt tự động khi bạn kích hoạt module chính; bạn không cần làm gì thêm. ## Cài đặt tùy chọn \{#optional-setup\} ### Ghi log \{#logging\} #### Thiết lập hệ thống ghi log \{#set-up-the-logging-system\} Adapty ghi lại các lỗi và thông tin quan trọng để giúp bạn hiểu chuyện gì đang xảy ra. Các mức độ log hiện có như sau: | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Chỉ ghi lại các lỗi | | `warn` | Ghi lại các lỗi và thông báo từ SDK không gây ra lỗi nghiêm trọng nhưng đáng chú ý | | `info` | Ghi lại các lỗi, cảnh báo và nhiều thông báo thông tin khác | | `verbose` | Ghi lại mọi thông tin bổ sung có thể hữu ích trong quá trình debug, chẳng hạn như lời gọi hàm, truy vấn API, v.v. | Bạn có thể đặt mức độ log trong ứng dụng trước hoặc trong quá trình cấu hình Adapty: ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### Chính sách dữ liệu \{#data-policies\} Adapty không lưu trữ dữ liệu cá nhân của người dùng trừ khi bạn chủ động gửi lên, nhưng bạn có thể triển khai thêm các chính sách bảo mật dữ liệu để tuân thủ quy định của cửa hàng hoặc từng quốc gia. #### Tắt thu thập và chia sẻ địa chỉ IP \{#disable-ip-address-collection-and-sharing\} Khi kích hoạt module Adapty, đặt `ipAddressCollectionDisabled` thành `true` để tắt tính năng thu thập và chia sẻ địa chỉ IP của người dùng. Giá trị mặc định là `false`. Sử dụng tham số này để tăng cường quyền riêng tư cho người dùng, tuân thủ các quy định bảo vệ dữ liệu khu vực (như GDPR hoặc CCPA), hoặc giảm thu thập dữ liệu không cần thiết khi các tính năng dựa trên IP không được yêu cầu trong ứng dụng của bạn. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### Vô hiệu hóa việc thu thập và chia sẻ advertising ID \{#disable-advertising-id-collection-and-sharing\} Khi kích hoạt module Adapty, đặt `ios.idfaCollectionDisabled` (iOS) hoặc `android.adIdCollectionDisabled` (Android) thành `true` để tắt tính năng thu thập advertising identifier. Giá trị mặc định là `false`. Sử dụng tham số này để tuân thủ chính sách của App Store/Play Store, tránh kích hoạt hộp thoại App Tracking Transparency, hoặc khi ứng dụng của bạn không cần attribution quảng cáo hay analytics dựa trên advertising ID. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### Cấu hình bộ nhớ đệm media cho AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Theo mặc định, AdaptyUI lưu vào bộ nhớ đệm các tệp media (như hình ảnh và video) để cải thiện hiệu suất và giảm mức sử dụng mạng. Bạn có thể tùy chỉnh cài đặt bộ nhớ đệm bằng cách cung cấp cấu hình tùy chỉnh. Sử dụng `mediaCache` để ghi đè các cài đặt bộ nhớ đệm mặc định: ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` | Tham số | Bắt buộc | Mô tả | |-----------|----------|-------------| | memoryStorageTotalCostLimit | tùy chọn | Tổng kích thước cache trong bộ nhớ tính bằng byte. Mặc định theo giá trị riêng của từng nền tảng. | | memoryStorageCountLimit | tùy chọn | Giới hạn số lượng item trong bộ nhớ cache. Mặc định theo giá trị riêng của từng nền tảng. | | diskStorageSizeLimit | tùy chọn | Giới hạn kích thước file trên đĩa tính bằng byte. Mặc định theo giá trị riêng của từng nền tảng. | ### Bật mức độ truy cập cục bộ (Android) \{#enable-local-access-levels-android\} Theo mặc định, [mức độ truy cập cục bộ](local-access-levels) được bật trên iOS và tắt trên Android. Để bật tính năng này trên Android, hãy đặt `localAccessLevelAllowed` thành `true`: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### Xóa dữ liệu khi khôi phục từ backup \{#clear-data-on-backup-restore\} Khi `clearDataOnBackup` được đặt thành `true`, SDK sẽ phát hiện khi ứng dụng được khôi phục từ bản backup iCloud và xóa toàn bộ dữ liệu SDK được lưu cục bộ, bao gồm thông tin hồ sơ người dùng được cache, thông tin sản phẩm và paywall. Sau đó SDK sẽ khởi tạo lại với trạng thái sạch. Giá trị mặc định là `false`. :::note Chỉ có cache cục bộ của SDK bị xóa. Lịch sử giao dịch với Apple và dữ liệu người dùng trên máy chủ Adapty vẫn không thay đổi. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## Mẹo cho môi trường phát triển \{#development-environment-tips\} #### Thiết lập chế độ mock cho Expo Go / Expo Web \{#set-up-mock-mode-for-expo-go--expo-web\} Expo Go và Expo Web không có quyền truy cập vào các native module của Adapty. Để tránh lỗi runtime trong khi vẫn có thể build và kiểm tra UI cũng như logic paywall của ứng dụng, Adapty cung cấp **chế độ mock**. ::::important Chế độ mock **không** phải là công cụ để kiểm tra giao dịch mua thực tế: - Nó **không mở** luồng mua hàng của App Store / Google Play và **không tạo** giao dịch thực. - Nó **không hiển thị** paywall/onboarding được tạo bằng **Adapty Paywall Builder (AdaptyUI)**. - Các native module của Adapty bị **bỏ qua hoàn toàn**—ngay cả khi thiếu file native SDK trong Xcode/Android build hoặc API key không hợp lệ cũng sẽ không gây ra lỗi. Để kiểm tra mua hàng thực và paywall của Paywall Builder, hãy sử dụng Expo Dev Client / production build—ở đó chế độ mock sẽ tự động bị tắt. :::: **Theo mặc định**, SDK tự động phát hiện môi trường Expo Go và web, rồi bật chế độ mock. Bạn không cần cấu hình gì thêm trừ khi muốn tùy chỉnh dữ liệu mock. Khi chế độ mock đang hoạt động: - Tất cả các phương thức Adapty đều trả về dữ liệu mock mà không thực hiện bất kỳ yêu cầu mạng nào đến máy chủ của Adapty. - Theo mặc định, hồ sơ người dùng mock ban đầu không có gói đăng ký nào đang hoạt động. - Theo mặc định, `makePurchase(...)` mô phỏng một giao dịch mua thành công và cấp quyền truy cập premium. Bạn có thể tùy chỉnh dữ liệu mock bằng `mockConfig` trong quá trình kích hoạt. Xem định dạng cấu hình và các tham số được hỗ trợ [tại đây](https://react-native.adapty.io/interfaces/adaptymockconfig). ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` Nếu bạn cần gọi các phương thức SDK trước khi kích hoạt (chẳng hạn như `isActivated()` hoặc `setLogLevel()`), hãy sử dụng `enableMock()` trước `activate()`. Nếu bridge đã được khởi tạo, phương thức này sẽ không làm gì cả. ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // Optional: pass mockConfig to customize mock data // Now you can call methods before activation await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` #### Trì hoãn kích hoạt SDK cho mục đích phát triển \{#delay-sdk-activation-for-development-purposes\} Adapty tải trước tất cả dữ liệu người dùng cần thiết khi khởi động SDK, giúp truy cập dữ liệu mới nhanh hơn. Tuy nhiên, điều này có thể gây ra vấn đề trên iOS Simulator, vì simulator thường xuyên yêu cầu xác thực trong quá trình phát triển. Mặc dù Adapty không thể kiểm soát luồng xác thực StoreKit, nhưng có thể trì hoãn các yêu cầu mà SDK thực hiện để lấy dữ liệu người dùng mới. Bằng cách bật thuộc tính `__debugDeferActivation`, lệnh gọi activate sẽ được giữ lại cho đến khi bạn thực hiện lệnh gọi Adapty SDK tiếp theo. Điều này giúp tránh các lần nhắc xác thực không cần thiết nếu không cần dùng đến. Cần lưu ý rằng **tính năng này chỉ dành cho mục đích phát triển**, vì nó không bao gồm tất cả các tình huống người dùng có thể xảy ra. Trong môi trường production, không nên trì hoãn việc kích hoạt, vì các thiết bị thực thường ghi nhớ dữ liệu xác thực và không liên tục yêu cầu nhập lại thông tin đăng nhập. Dưới đây là cách sử dụng được khuyến nghị: ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' from any 3rd party library }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### Khắc phục lỗi kích hoạt SDK trên Fast Refresh của React Native \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} Khi phát triển với Adapty SDK trong React Native, bạn có thể gặp lỗi: `Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` Điều này xảy ra vì tính năng fast refresh của React Native kích hoạt nhiều lần gọi activation trong quá trình phát triển. Để tránh điều này, hãy sử dụng tùy chọn `__ignoreActivationOnFastRefresh` với giá trị `__DEV__` (cờ chế độ phát triển của React Native). ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` ## Khắc phục sự cố \{#troubleshooting\} #### Lỗi phiên bản iOS tối thiểu \{#minimum-ios-version-error\} Khi build cho iOS, bạn có thể gặp lỗi về **phiên bản iOS tối thiểu** hoặc deployment target. Adapty yêu cầu **iOS 15.0+**. Vì Expo tạo ra dự án iOS (bao gồm cả `Podfile`) trong quá trình `expo prebuild`, **bạn không nên chỉnh sửa `Podfile` trực tiếp**. Thay vào đó, hãy cấu hình deployment target thông qua config plugin `expo-build-properties`. 1. Cài đặt plugin: ```sh npx expo install expo-build-properties ``` 2. Cập nhật cấu hình Expo (`app.json` hoặc `app.config.js`) để đặt iOS deployment target: ``` { "expo": { // ...other Expo config... "plugins": [ [ "expo-build-properties", { "ios": { // Adapty requires iOS 15.0+. "deploymentTarget": "15.0" } } ], ] } } ``` 3. Tạo lại native iOS project và build lại: ``` npx expo prebuild --clean npx expo run:ios # or `eas build -p ios` on your CI ``` #### Xung đột Android Auto Backup manifest \{#android-auto-backup-manifest-conflict\} Khi sử dụng Expo với nhiều SDK cùng cấu hình Android Auto Backup (chẳng hạn như Adapty, AppsFlyer, hoặc expo-secure-store), bạn có thể gặp lỗi xung đột khi merge manifest. Lỗi thường gặp trông như sau: `Manifest merger failed : Attribute application@fullBackupContent value=(@xml/secure_store_backup_rules) from AndroidManifest.xml:24:248-306 is also present at [io.adapty:android-sdk:3.12.0] AndroidManifest.xml:9:18-70 value=(@xml/adapty_backup_rules).` Để giải quyết xung đột này, bạn cần để plugin Adapty quản lý cấu hình Android backup. Nếu dự án của bạn cũng sử dụng `expo-secure-store`, hãy tắt thiết lập backup của nó để tránh bị trùng lặp. Đây là cách cấu hình `app.json` của bạn: ```json title="app.json" { "expo": { "plugins": [ ["react-native-adapty", { "replaceAndroidBackupConfig": true }], ["expo-secure-store", { "configureAndroidBackup": false }] ] } } ``` Tùy chọn `replaceAndroidBackupConfig` mặc định là `false`. Khi được bật, nó cho phép plugin Adapty kiểm soát các quy tắc sao lưu Android. Thêm `"configureAndroidBackup": false` nếu bạn sử dụng `expo-secure-store` để tránh cảnh báo, vì cấu hình sao lưu của SecureStore sẽ được Adapty xử lý. :::important Cài đặt này chỉ áp dụng các yêu cầu sao lưu cho Adapty, AppsFlyer và expo-secure-store. Nếu các thư viện khác trong dự án của bạn có quy tắc sao lưu tùy chỉnh, bạn sẽ cần tự cấu hình thủ công. ::: --- # File: sdk-installation-react-native-pure --- --- title: "Install & configure Adapty SDK in a pure React Native project" description: "Step-by-step guide on installing Adapty SDK on React Native for subscription-based apps." --- :::important Hướng dẫn này chỉ áp dụng cho **dự án React Native thuần (không dùng Expo)**. Nếu bạn đang dùng **Expo**, hãy xem [hướng dẫn cài đặt Expo](sdk-installation-react-native-expo) thay thế. ::: SDK Adapty bao gồm hai module chính để tích hợp liền mạch vào ứng dụng React Native của bạn: - **Core Adapty**: Module này là bắt buộc để Adapty hoạt động đúng trong ứng dụng của bạn. - **AdaptyUI**: Module này cần thiết nếu bạn sử dụng [Adapty Paywall Builder](adapty-paywall-builder), công cụ không cần code, thân thiện với người dùng để dễ dàng tạo paywall đa nền tảng. AdaptyUI sẽ tự động được kích hoạt cùng với module core. :::tip Bạn muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem [ứng dụng mẫu](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples) của chúng tôi, minh họa toàn bộ quá trình thiết lập, bao gồm hiển thị paywall, thực hiện mua hàng và các chức năng cơ bản khác. ::: ## Yêu cầu \{#requirements\} Adapty React Native SDK yêu cầu iOS 15.0 trở lên. Để build cho iOS cần có **Swift 6.0** hoặc cao hơn. [Kids Mode](kids-mode-react-native) yêu cầu **Swift 6.1** hoặc cao hơn. :::info Từ SDK v3.17 trở đi, Adapty SDK sử dụng Google Play Billing Library v8.0.0 theo mặc định. ::: :::info Cài đặt SDK là bước 5 trong quá trình thiết lập Adapty. Trước khi các giao dịch mua hàng hoạt động trong ứng dụng, bạn cần kết nối ứng dụng với các cửa hàng, sau đó tạo sản phẩm, paywall và placement trong Adapty Dashboard. [Hướng dẫn quickstart](quickstart) sẽ hướng dẫn bạn qua tất cả các bước cần thiết. ::: ## Cài đặt Adapty SDK \{#install-adapty-sdk\} :::important Kể từ v4, Adapty React Native SDK không còn hỗ trợ cài đặt các native dependency qua CocoaPods. Nếu bạn cần v4 trở lên (dành cho [Flow Builder](adapty-flow-builder)), hãy làm theo hướng dẫn [Adapty SDK 4.0: enable Swift Package Manager](#adapty-sdk-40-enable-swift-package-manager) bên dưới. ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) 1. Cài đặt Adapty SDK (thao tác này cũng tự động cài đặt `@adapty/core`): ```sh showLineNumbers title="Shell" # using npm npm install react-native-adapty # or using yarn yarn add react-native-adapty ``` 2. Với iOS, cài đặt pods: ```sh showLineNumbers title="Shell" cd ios && pod install ```
Với Android, nếu phiên bản React Native của bạn cũ hơn 0.73.0 (nhấn để mở rộng) Cập nhật file `/android/build.gradle`. Đảm bảo rằng có dependency `kotlin-gradle-plugin:1.8.0` hoặc phiên bản mới hơn: ```groovy showLineNumbers title="/android/build.gradle" ... buildscript { ... dependencies { ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" } } ... ```
### Adapty SDK 4.0: kích hoạt Swift Package Manager React Native SDK 4.0 — hỗ trợ [Flow Builder](adapty-flow-builder) — yêu cầu **React Native 0.75 trở lên**. Cài đặt SDK: ```sh showLineNumbers title="Shell" npm install react-native-adapty@^4.0.0 # or using yarn yarn add react-native-adapty@^4.0.0 ``` v4 tải các native iOS SDK (`Adapty`, `AdaptyUI`, `AdaptyPlugin`) thông qua Swift Package Manager thay vì CocoaPods sub-dependencies ([repo spec của CocoaPods sẽ chuyển sang chế độ chỉ đọc vào tháng 12 năm 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)). SPM yêu cầu dynamic frameworks — thêm đoạn sau vào target trong `ios/Podfile` của bạn, sau đó cài lại pods: ```ruby showLineNumbers title="ios/Podfile" use_frameworks! :linkage => :dynamic ``` ```sh showLineNumbers title="Shell" cd ios && pod install --repo-update ``` Nếu trước đây bạn đã thêm `Adapty`, `AdaptyUI`, hoặc `AdaptyPlugin` dưới dạng sub-dependencies của CocoaPods, hãy xóa các dòng `pod 'Adapty'`, `pod 'AdaptyUI'`, hoặc `pod 'AdaptyPlugin'` khỏi `Podfile` trước. :::warning Chuyển từ liên kết tĩnh (static linkage) mặc định sang dynamic frameworks có thể xung đột với các thư viện chưa hỗ trợ modular headers, và không tương thích với Flipper. Xem [Migrate Adapty React Native SDK to v4](migration-to-react-native-sdk-v4) để biết thêm chi tiết. ::: ## Kích hoạt module Adapty của Adapty SDK \{#activate-adapty-module-of-adapty-sdk\} Để lấy **Public SDK Key**: 1. Truy cập Adapty Dashboard và điều hướng đến [**App settings → General**](https://app.adapty.io/settings/general). 2. Trong phần **Api keys**, sao chép **Public SDK Key** (KHÔNG phải Secret Key). 3. Thay thế `"YOUR_PUBLIC_SDK_KEY"` trong code. Hoặc lấy theo cách lập trình, sử dụng [Adapty CLI](developer-cli): ``` npm install -g adapty adapty auth login adapty apps list ``` Hoặc, trực tiếp: ``` npx adapty auth login adapty apps list ``` - Đảm bảo bạn sử dụng **Public SDK key** để khởi tạo Adapty, **Secret key** chỉ nên dùng cho [server-side API](getting-started-with-server-side-api). - **SDK keys** là duy nhất cho mỗi ứng dụng, vì vậy nếu bạn có nhiều ứng dụng, hãy đảm bảo chọn đúng key. Sao chép đoạn code sau vào `App.tsx` để kích hoạt Adapty: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important Hãy đợi `activate` hoàn thành trước khi gọi bất kỳ phương thức nào khác của Adapty SDK. Xem [Thứ tự gọi trong React Native SDK](react-native-sdk-call-order) để biết toàn bộ trình tự. ::: Bây giờ hãy thiết lập các paywall trong ứng dụng của bạn: - Nếu bạn dùng [Adapty Paywall Builder](adapty-paywall-builder), hãy xem [hướng dẫn nhanh về Paywall Builder](react-native-quickstart-paywalls). - Nếu bạn tự xây dựng giao diện paywall, hãy xem [hướng dẫn nhanh cho custom paywall](react-native-quickstart-manual). :::tip Để tránh lỗi kích hoạt trong môi trường phát triển, hãy tham khảo [các mẹo](#development-environment-tips). ::: ## Kích hoạt module AdaptyUI của Adapty SDK \{#activate-adaptyui-module-of-adapty-sdk\} Nếu bạn có kế hoạch sử dụng [Paywall Builder](adapty-paywall-builder), bạn cần module AdaptyUI. Module này được kích hoạt tự động khi bạn kích hoạt module lõi; bạn không cần làm gì thêm. ## Cài đặt tùy chọn \{#optional-setup\} ### Ghi log \{#logging\} #### Thiết lập hệ thống ghi log \{#set-up-the-logging-system\} Adapty ghi lại các lỗi và thông tin quan trọng khác để giúp bạn hiểu chuyện gì đang xảy ra. Các cấp độ ghi log hiện có như sau: | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | Chỉ ghi lại các lỗi | | `warn` | Ghi lại các lỗi và thông báo từ SDK không gây ra lỗi nghiêm trọng nhưng đáng chú ý | | `info` | Ghi lại các lỗi, cảnh báo và nhiều thông báo thông tin khác | | `verbose` | Ghi lại mọi thông tin bổ sung có thể hữu ích trong quá trình debug, chẳng hạn như các lần gọi hàm, truy vấn API, v.v. | Bạn có thể thiết lập mức độ log trong ứng dụng trước hoặc trong quá trình cấu hình Adapty: ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### Chính sách dữ liệu \{#data-policies\} Adapty không lưu trữ dữ liệu cá nhân của người dùng trừ khi bạn chủ động gửi, nhưng bạn có thể áp dụng thêm các chính sách bảo mật dữ liệu để tuân thủ quy định của cửa hàng hoặc từng quốc gia. #### Tắt thu thập và chia sẻ địa chỉ IP \{#disable-ip-address-collection-and-sharing\} Khi kích hoạt module Adapty, đặt `ipAddressCollectionDisabled` thành `true` để tắt tính năng thu thập và chia sẻ địa chỉ IP của người dùng. Giá trị mặc định là `false`. Sử dụng tham số này để tăng cường quyền riêng tư cho người dùng, tuân thủ các quy định bảo vệ dữ liệu theo khu vực (như GDPR hoặc CCPA), hoặc giảm thiểu việc thu thập dữ liệu không cần thiết khi các tính năng dựa trên IP không được yêu cầu trong ứng dụng của bạn. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### Tắt tính năng thu thập và chia sẻ advertising ID \{#disable-advertising-id-collection-and-sharing\} Khi kích hoạt module Adapty, đặt `ios.idfaCollectionDisabled` (iOS) hoặc `android.adIdCollectionDisabled` (Android) thành `true` để tắt thu thập advertising identifier. Giá trị mặc định là `false`. Sử dụng tham số này để tuân thủ chính sách của App Store/Play Store, tránh kích hoạt lời nhắc App Tracking Transparency, hoặc khi ứng dụng của bạn không cần attribution quảng cáo hay analytics dựa trên advertising ID. ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### Thiết lập cấu hình bộ nhớ đệm media cho AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\} Theo mặc định, AdaptyUI lưu vào bộ nhớ đệm các file media (như hình ảnh và video) để cải thiện hiệu suất và giảm lưu lượng mạng. Bạn có thể tùy chỉnh các cài đặt bộ nhớ đệm bằng cách cung cấp cấu hình tùy chỉnh. Sử dụng `mediaCache` để ghi đè các cài đặt bộ nhớ đệm mặc định: ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` | Tham số | Bắt buộc | Mô tả | |-----------|----------|-------------| | memoryStorageTotalCostLimit | tùy chọn | Tổng kích thước cache trong bộ nhớ tính bằng byte. Mặc định theo giá trị riêng của từng nền tảng. | | memoryStorageCountLimit | tùy chọn | Giới hạn số lượng mục trong bộ nhớ cache. Mặc định theo giá trị riêng của từng nền tảng. | | diskStorageSizeLimit | tùy chọn | Giới hạn kích thước tệp trên đĩa tính bằng byte. Mặc định theo giá trị riêng của từng nền tảng. | ### Bật mức độ truy cập cục bộ (Android) \{#enable-local-access-levels-android\} Theo mặc định, [mức độ truy cập cục bộ](local-access-levels) được bật trên iOS và tắt trên Android. Để bật tính năng này trên Android, hãy đặt `localAccessLevelAllowed` thành `true`: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### Xóa dữ liệu khi khôi phục từ backup \{#clear-data-on-backup-restore\} Khi `clearDataOnBackup` được đặt thành `true`, SDK sẽ phát hiện khi ứng dụng được khôi phục từ bản backup iCloud và xóa toàn bộ dữ liệu SDK được lưu trữ cục bộ, bao gồm thông tin hồ sơ người dùng đã cache, chi tiết sản phẩm và các paywall. Sau đó SDK sẽ khởi tạo lại với trạng thái sạch. Giá trị mặc định là `false`. :::note Chỉ có cache SDK cục bộ bị xóa. Lịch sử giao dịch với Apple và dữ liệu người dùng trên máy chủ Adapty vẫn không thay đổi. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## Mẹo cho môi trường phát triển \{#development-environment-tips\} #### Trì hoãn kích hoạt SDK cho mục đích phát triển \{#delay-sdk-activation-for-development-purposes\} Adapty tải trước tất cả dữ liệu người dùng cần thiết ngay khi SDK được kích hoạt, giúp truy cập dữ liệu mới nhanh hơn. Tuy nhiên, điều này có thể gây ra vấn đề trong iOS simulator, nơi thường xuyên yêu cầu xác thực trong quá trình phát triển. Mặc dù Adapty không thể kiểm soát luồng xác thực StoreKit, nhưng có thể trì hoãn các yêu cầu mà SDK thực hiện để lấy dữ liệu người dùng mới. Bằng cách bật thuộc tính `__debugDeferActivation`, lệnh gọi activate sẽ được giữ lại cho đến khi bạn thực hiện lệnh gọi SDK tiếp theo. Điều này giúp tránh các thông báo yêu cầu dữ liệu xác thực không cần thiết khi không cần thiết. Cần lưu ý rằng **tính năng này chỉ dành cho mục đích phát triển**, vì nó không bao phủ tất cả các tình huống người dùng tiềm năng. Trong môi trường production, không nên trì hoãn việc kích hoạt, vì các thiết bị thực thường ghi nhớ dữ liệu xác thực và không liên tục yêu cầu nhập thông tin đăng nhập. Dưới đây là cách tiếp cận được khuyến nghị khi sử dụng: ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' từ thư viện bên thứ ba bất kỳ }); } catch (error) { console.error('Không thể kích hoạt Adapty SDK:', error); // Xử lý lỗi phù hợp với ứng dụng của bạn } ``` #### Khắc phục lỗi kích hoạt SDK khi sử dụng Fast Refresh của React Native \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} Khi phát triển với Adapty SDK trong React Native, bạn có thể gặp lỗi: `Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` Điều này xảy ra vì tính năng fast refresh của React Native kích hoạt nhiều lần gọi activation trong quá trình phát triển. Để ngăn điều này, hãy sử dụng tùy chọn `__ignoreActivationOnFastRefresh` được đặt thành `__DEV__` (cờ chế độ phát triển của React Native). ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### Thiết lập chế độ mock để kiểm tra cục bộ \{#set-up-mock-mode-for-local-testing\} Để phát triển và kiểm thử cục bộ, bạn có thể bật chế độ mock để không cần tài khoản sandbox App Store/Google Play và tăng tốc độ vòng lặp phát triển. Chế độ mock hoàn toàn bỏ qua các module native của Adapty và trả về dữ liệu giả lập. :::important Chế độ mock **không** phải là công cụ để kiểm thử giao dịch mua thực tế: - Nó **không mở** luồng mua hàng App Store / Google Play và **không tạo** giao dịch thực. - Nó **không render** paywall/onboarding được tạo bằng **Adapty Paywall Builder (AdaptyUI)**. - Các native module của Adapty bị **bỏ qua hoàn toàn**—ngay cả khi thiếu file native SDK trong bản build Xcode/Android hoặc API key không hợp lệ cũng sẽ không phát sinh lỗi. - Không có dữ liệu nào được gửi đến server của Adapty. Để kiểm tra mua hàng thực và paywall từ Paywall Builder, hãy tắt mock mode và sử dụng tài khoản sandbox. ::: Để bật mock mode, đặt `enableMock` thành `true`: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { enableMock: true, }); ``` Khi chế độ mock đang hoạt động: - Tất cả các phương thức của Adapty trả về dữ liệu mock mà không thực hiện bất kỳ yêu cầu mạng nào đến máy chủ của Adapty. - Theo mặc định, hồ sơ người dùng mock ban đầu không có gói đăng ký nào đang hoạt động. - Theo mặc định, `makePurchase(...)` mô phỏng một giao dịch mua thành công và cấp quyền truy cập premium. Bạn có thể tùy chỉnh dữ liệu mock bằng `mockConfig` trong quá trình kích hoạt. Xem định dạng cấu hình và các tham số được hỗ trợ [tại đây](https://react-native.adapty.io/interfaces/adaptymockconfig). ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` Nếu bạn cần gọi các phương thức SDK trước khi kích hoạt (chẳng hạn như `isActivated()` hoặc `setLogLevel()`), hãy sử dụng `enableMock()` trước `activate()`. Nếu bridge đã được khởi tạo, phương thức này sẽ không làm gì cả. ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // Optional: pass mockConfig to customize mock data // Now you can call methods before activation await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` ## Xử lý sự cố \{#troubleshooting\} #### Lỗi phiên bản iOS tối thiểu \{#minimum-ios-version-error\} Nếu bạn gặp lỗi phiên bản iOS tối thiểu, hãy cập nhật Podfile: ```diff -platform :ios, min_ios_version_supported +platform :ios, '15.0' ``` #### Xung đột manifest Android Auto Backup \{#android-auto-backup-manifest-conflict\} Một số SDK (bao gồm Adapty) đi kèm với cấu hình Android Auto Backup riêng. Nếu bạn sử dụng nhiều SDK có định nghĩa backup rules, quá trình merge Android manifest có thể thất bại với lỗi liên quan đến `android:fullBackupContent`, `android:dataExtractionRules`, hoặc `android:allowBackup`. Triệu chứng lỗi thường gặp: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules) is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)` :::note Những thay đổi này cần được thực hiện trong thư mục platform Android của bạn (thường nằm trong thư mục `android/` của dự án). ::: Để khắc phục, bạn cần: - Yêu cầu manifest merger sử dụng các giá trị của ứng dụng cho các thuộc tính liên quan đến backup. - Tạo các file backup rule kết hợp rules của Adapty với rules từ các SDK khác. #### 1. Thêm namespace `tools` vào manifest \{#1-add-the-tools-namespace-to-your-manifest\} Trong file `AndroidManifest.xml`, hãy đảm bảo thẻ gốc `` có chứa tools: ```xml ... ``` #### 2. Ghi đè các thuộc tính backup trong `` \{#2-override-backup-attributes-in-application\} Trong cùng file `AndroidManifest.xml`, cập nhật thẻ `` để ứng dụng của bạn cung cấp các giá trị cuối cùng và yêu cầu manifest merger thay thế các giá trị từ thư viện: ```xml ... ``` Nếu có SDK nào cũng đặt `android:allowBackup`, hãy thêm nó vào `tools:replace`: ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. Tạo các file backup rules đã merge \{#3-create-merged-backup-rules-files\} Tạo các file XML trong thư mục `res/xml/` của dự án Android, kết hợp rules của Adapty với rules từ các SDK khác. Android sử dụng các định dạng backup rule khác nhau tùy theo phiên bản OS, vì vậy việc tạo cả hai file đảm bảo tương thích với tất cả các phiên bản Android mà ứng dụng hỗ trợ. :::note Các ví dụ dưới đây sử dụng AppsFlyer làm SDK bên thứ ba mẫu. Hãy thay thế hoặc bổ sung rules cho các SDK khác mà bạn đang dùng trong ứng dụng. ::: **Dành cho Android 12 trở lên** (sử dụng định dạng data extraction rules mới): ```xml title="sample_data_extraction_rules.xml" ``` **Dành cho Android 11 trở xuống** (sử dụng định dạng full backup content cũ): ```xml title="sample_backup_rules.xml" #### Giao dịch mua thất bại sau khi quay lại từ ứng dụng khác trên Android \{#purchases-fail-after-returning-from-another-app-in-android\} Nếu Activity khởi động flow mua hàng sử dụng `launchMode` không phải mặc định, Android có thể tạo lại hoặc tái sử dụng nó không đúng cách khi người dùng quay lại từ Google Play, ứng dụng ngân hàng hoặc trình duyệt. Điều này có thể khiến kết quả giao dịch bị mất hoặc bị xử lý như đã hủy. Để đảm bảo quá trình mua hàng hoạt động đúng, hãy chỉ sử dụng chế độ khởi chạy `standard` hoặc `singleTop` cho Activity khởi động flow mua hàng, và tránh các chế độ khác. Trong file `AndroidManifest.xml`, đảm bảo Activity khởi động flow mua hàng được đặt thành `standard` hoặc `singleTop`: ```xml ``` #### Lỗi build Swift 6 do Podfile ghi đè SWIFT_VERSION \{#swift-6-build-errors-caused-by-podfile-swift_version-override\} Khi build ứng dụng React Native cho iOS, bạn có thể gặp lỗi biên dịch Swift 6 trên các pod target của Adapty. Các triệu chứng thường gặp bao gồm: lỗi `@Sendable` không khớp trong `AdaptyUIBuilderLogic`, thiếu conformance `Sendable` trên các kiểu Adapty, hoặc lỗi actor isolation. Các pod Adapty khai báo `s.swift_version = '6.0'` và yêu cầu Swift 6 để build. Code của bạn vẫn có thể dùng Swift 5 — chỉ các pod target của Adapty (`Adapty`, `AdaptyUI`, `AdaptyUIBuilder`, `AdaptyLogger`, `AdaptyPlugin`) mới cần build bằng Swift 6. Nguyên nhân phổ biến nhất là hook `post_install` trong `ios/Podfile` ghi đè `SWIFT_VERSION` cho mọi pod target: ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` **Cách sửa**: Loại trừ các pod target của Adapty khỏi phần ghi đè: ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name) target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` Sau đó chạy `pod install` từ thư mục `ios/` và build lại. Để xác nhận, mở `ios/Pods/Pods.xcodeproj`, chọn target pod `Adapty` → **Build Settings** → **Swift Language Version**. Giá trị phải là **Swift 6**. --- # File: react-native-quickstart-paywalls --- --- 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ó. Để 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( (result, product) => result.type !== 'user_cancelled', [], ); return ( ); } ``` Để 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 } ``` :::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. For the React component, handle actions directly in the `AdaptyFlowView` component: ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onCloseButtonPress = useCallback( () => true, // allow the flow to close [], ); const onCustomAction = useCallback( (actionId) => false, [], ); return ( ); } ``` Đố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 }, }); ``` :::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. ```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( () => true, [], ); const onPurchaseCompleted = useCallback( (result, product) => result.type !== 'user_cancelled', [], ); useEffect(() => { loadFlow(); }, []); return ( {flow ? ( ) : (