---
title: "Hiển thị paywall nhắm mục tiêu AA ngay khi khởi chạy lần đầu trong React Native SDK"
description: "Hiển thị paywall ngay lập tức và cập nhật cho người dùng Apple Ads khi attribution được áp dụng trong React Native, sử dụng AdaptyProfile.appliedAttributionSources."
---

Attribution của Apple Ads (AA) được nhận không đồng bộ sau khi `adapty.activate()` được gọi. Ở lần khởi chạy đầu tiên, attribution thường chưa có, nên `getPaywall` sẽ giải quyết theo đối tượng mặc định và người dùng Apple Ads sẽ bỏ lỡ paywall được phân khúc theo AA của bạn. Thay vì chờ attribution đến mới hiển thị paywall, hãy hiển thị paywall ngay lập tức và làm mới khi attribution AA được áp dụng — để người dùng Apple Ads nhận được biến thể nhắm mục tiêu còn những người khác thấy paywall ngay không cần chờ. `AdaptyProfile.appliedAttributionSources` cho bạn biết khi nào attribution AA đã được áp dụng.

## Trước khi bắt đầu \{#before-you-start\}

Bạn cần:
- Adapty React Native SDK phiên bản **3.17.1** trở lên.
- Apple Ads đã được cấu hình cho ứng dụng trong Adapty. Xem [Apple Ads](apple-search-ads).

## Cách hoạt động \{#how-it-works\}

Sau khi `adapty.activate()` được gọi, SDK sẽ yêu cầu attribution Apple Ads từ Apple ở chế độ nền và chuyển kết quả đến backend của Adapty. Khi AA trở thành nguồn attribution đang hoạt động cho hồ sơ người dùng, SDK sẽ gửi một `AdaptyProfile` được cập nhật đến listener `onLatestProfileLoad` của bạn, với `'apple_search_ads'` trong mảng `appliedAttributionSources`.

Điều này cho phép bạn tải paywall theo hai bước:

1. Gọi `getPaywall` ngay lập tức. Khi chưa có attribution nào được áp dụng, Adapty sẽ giải quyết yêu cầu theo đối tượng mặc định, người dùng thấy paywall ngay.
2. Khi `'apple_search_ads'` xuất hiện, gọi lại `getPaywall`. Lúc này Adapty giải quyết yêu cầu theo đối tượng Apple Ads và trả về paywall nhắm mục tiêu, thay thế paywall đầu tiên.

`appliedAttributionSources` có thể rỗng hoặc không có giá trị. Điều đó có nghĩa là:

- Attribution Apple Ads chưa được xử lý cho hồ sơ người dùng này, hoặc
- Chưa có attribution nào đến.

Dù thế nào, bước 1 vẫn an toàn — Adapty giải quyết yêu cầu theo đối tượng phù hợp với trạng thái hồ sơ người dùng hiện tại, thường là đối tượng mặc định. Bước 2 chỉ chạy khi `'apple_search_ads'` xuất hiện.

:::important
Ở mỗi lần khởi chạy tiếp theo, hồ sơ người dùng đã được cache sẵn với `'apple_search_ads'` trong `appliedAttributionSources`, nên lần `getPaywall` đầu tiên đã trả về paywall được phân khúc theo Apple Ads — không có lần tải thứ hai hay thay đổi nào hiển thị. Luồng hai bước chỉ quan trọng ở lần khởi chạy đầu tiên, khi attribution vẫn đang trong quá trình xử lý.
:::

## Triển khai \{#implementation\}

Hiển thị paywall ngay lập tức, sau đó lắng nghe `'apple_search_ads'` và làm mới paywall khi nó xuất hiện.

1. **Kích hoạt SDK.** Xem [Cài đặt & cấu hình React Native SDK](sdk-installation-reactnative).
2. **Tải và hiển thị paywall** bằng `getPaywall` như bình thường — không chặn chờ attribution.
3. **Đăng ký nhận cập nhật hồ sơ người dùng** bằng `adapty.addEventListener('onLatestProfileLoad', …)` và theo dõi `'apple_search_ads'`. Khi nó xuất hiện, tải lại paywall và hiển thị paywall mới. Nếu bạn chưa thiết lập listener, xem [Lắng nghe cập nhật gói đăng ký](react-native-check-subscription-status#listen-to-subscription-updates):

```typescript
const subscription = adapty.addEventListener('onLatestProfileLoad', async profile => {
  if (!profile.appliedAttributionSources?.includes('apple_search_ads')) return;
  const targeted = await adapty.getPaywall(placementId);
  // present the targeted paywall in place of the first one
});

// Call subscription.remove() after the upgrade, or after a timeout (see below).
```

4. **Dừng lắng nghe sau một khoảng thời gian.** Hầu hết người dùng không bao giờ nhận được attribution Apple Ads, vì vậy hãy xóa listener sau một khoảng thời gian thay vì giữ nó mở suốt phiên. Cấu hình [paywall dự phòng](react-native-use-fallback-paywalls) cho placement để người dùng luôn thấy gì đó nếu yêu cầu thất bại.

## Ví dụ hoàn chỉnh \{#complete-example\}

`onAppleAdsAttribution` sẽ resolve khi attribution Apple Ads được áp dụng, hoặc reject sau `timeoutMs`. Đoạn code bên dưới tải paywall ngay lập tức, sau đó tải lại khi attribution đến — người dùng Apple Ads nhận được paywall nhắm mục tiêu, và nếu attribution không bao giờ đến thì paywall đầu tiên vẫn được giữ nguyên:

```typescript

const APPLE_ADS_SOURCE = 'apple_search_ads';
const placementId = 'YOUR_PLACEMENT_ID';

function hasAppleAdsAttribution(profile: AdaptyProfile): boolean {
  return profile.appliedAttributionSources?.includes(APPLE_ADS_SOURCE) ?? false;
}

/**
 * Resolves once Apple Ads attribution is applied to the profile.
 * Rejects with a timeout error if attribution never arrives within `timeoutMs`.
 * Call after `adapty.activate()`.
 */
export function onAppleAdsAttribution(timeoutMs: number): Promise<void> {
  return new Promise((resolve, reject) => {
    let timer: ReturnType<typeof setTimeout> | undefined;
    let subscription: { remove: () => void } | undefined;

    const stop = () => {
      clearTimeout(timer);
      subscription?.remove();
    };

    subscription = adapty.addEventListener('onLatestProfileLoad', profile => {
      if (!hasAppleAdsAttribution(profile)) return;
      stop();
      resolve();
    });

    timer = setTimeout(() => {
      stop();
      reject(new Error(`Apple Ads attribution timed out after ${timeoutMs}ms`));
    }, timeoutMs);
  });
}

let paywall = await adapty.getPaywall(placementId);

onAppleAdsAttribution(30_000)
  .then(() => adapty.getPaywall(placementId))
  .then(updated => {
    paywall = updated;
  })
  .catch(() => {
    console.log('Apple Ads attribution or loading failed');
  });
```

Ở lần khởi chạy đầu tiên, người dùng Apple Ads sẽ thấy paywall mặc định trong một khoảnh khắc trước khi nó được thay thế. Nếu bạn hiển thị paywall bằng Paywall Builder, hãy cân nhắc xem việc hiển thị lại có phù hợp không, hoặc chỉ áp dụng bản cập nhật trước khi paywall được hiển thị. Điều chỉnh `timeoutMs` tùy theo thời gian bạn sẵn sàng lắng nghe — attribution khi đến thường xuất hiện trong vài giây sau khi khởi chạy.

Nếu ứng dụng của bạn đã lắng nghe `onLatestProfileLoad` cho các mục đích khác (ví dụ, [kiểm tra trạng thái gói đăng ký](react-native-check-subscription-status#listen-to-subscription-updates)), bạn không cần thay đổi gì. `adapty.addEventListener` hỗ trợ nhiều listener độc lập, nên listener này sẽ được thêm vào mà không ảnh hưởng đến các listener khác.