---
title: "Flow'ları ve paywall'ları görüntüleme - React Native"
description: "Adapty ile React Native uygulamanızda kullanıcılara flow'ları ve paywall'ları sunun."
---

<MethodPromo method="getFlow" label="Flow'ları ve paywall'ları görüntüleme" />

Flow Builder'da bir flow veya paywall oluşturduysanız, onu kullanıcıya göstermek için mobil uygulama kodunuzda render etme derdine girmenize gerek yoktur. Böyle bir flow, hem içinde ne gösterileceğini hem de nasıl gösterileceğini içerir.

Başlamadan önce şunlardan emin olun:

1. Bir [flow veya paywall oluşturdunuz](create-paywall).
2. Onu bir [placement](placements)'a eklediniz.
3. [Flow'u getirdiniz ve view'i hazırladınız](react-native-get-pb-paywalls).

:::warning

Bu rehber yalnızca **flow'lar ve Paywall Builder paywall'ları** içindir; bunlar SDK v4.0 veya sonrasını gerektirir. Flow sunma süreci, remote config paywall'ları için farklıdır.

- **Remote config paywall'larını** sunmak için bkz. [Remote config ile tasarlanan paywall'ı render etme](present-remote-config-paywalls).

:::

Adapty React Native SDK, flow'ları ve paywall'ları sunmak için iki yol sağlar:

- **React bileşeni**: Gömülü bileşen, onu uygulamanızın mimarisine ve navigasyon sistemine entegre etmenize olanak tanır.

- **Modal sunum**

## React bileşeni \{#react-component\}

Bir flow'u mevcut bileşen ağacınıza gömmek için, `AdaptyFlowView` bileşenini doğrudan React Native bileşen hiyerarşinizde kullanın. Gömülü bileşen, onu uygulamanızın mimarisine ve navigasyon sistemine entegre etmenize olanak tanır.

:::tip
`AdaptyFlowView` bileşeni, view'ini render edildiğinde oluşturur; yani yapılandırma ve görseller yüklendiğinde. Bunları önceden yüklemek için, uygulamanızda daha erken bir noktada aynı flow için [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) çağırın. Bileşen daha sonra önbelleğe alınmış verileri yeniden kullanır ve indirmeleri beklemeden render eder.
:::

```typescript showLineNumbers title="React Native (TSX)"

function MyFlow({ flow }) {
  const flowParams = useMemo(() => ({
    loadTimeoutMs: 3000,
  }), []);

  const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []);
  const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []);
  const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []);
  const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []);
  const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []);
  const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []);
  const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []);
  const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []);
  const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []);
  const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []);
  const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []);
  const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => {}, []);
  const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []);
  const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []);

  return (
    <AdaptyFlowView
      flow={flow}
      params={flowParams}
      style={styles.flow}
      onCloseButtonPress={onCloseButtonPress}
      onProductSelected={onProductSelected}
      onPurchaseStarted={onPurchaseStarted}
      onPurchaseCompleted={onPurchaseCompleted}
      onPurchaseFailed={onPurchaseFailed}
      onRestoreStarted={onRestoreStarted}
      onRestoreCompleted={onRestoreCompleted}
      onRestoreFailed={onRestoreFailed}
      onAppeared={onAppeared}
      onError={onError}
      onLoadingProductsFailed={onLoadingProductsFailed}
      onCustomAction={onCustomAction}
      onUrlPress={onUrlPress}
      onWebPaymentNavigationFinished={onWebPaymentNavigationFinished}
    />
  );
}
```

## Modal sunum \{#modal-presentation\}

Bir flow'u bağımsız bir ekran olarak görüntülemek için, [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) metoduyla oluşturulan `view` üzerinde `view.present()` metodunu kullanın. Her `view` yalnızca bir kez kullanılabilir. Flow'u tekrar görüntülemeniz gerekirse, yeni bir `view` örneği oluşturmak için `createFlowView`'u bir kez daha çağırın.

:::warning
Aynı `view`'i yeniden oluşturmadan tekrar kullanmak yasaktır. Bu, bir `AdaptyUIError.viewAlreadyPresented` hatasıyla sonuçlanır.
:::

```typescript showLineNumbers title="React Native (TSX)"

const view = await createFlowView(flow);

// Optional: handle flow events (close, purchase, restore, etc)
// view.setEventHandlers({ ... });

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

:::important
`setEventHandlers`'ı birden çok kez çağırmak, sağladığınız işleyicileri geçersiz kılar; söz konusu belirli olaylar için hem varsayılan hem de önceden ayarlanmış işleyicilerin yerini alır.
:::

### iOS sunum stilini yapılandırın \{#configure-ios-presentation-style\}

Flow'un iOS'ta nasıl sunulacağını, `present()` metoduna `iosPresentationStyle` parametresini ileterek yapılandırın. Parametre `'full_screen'` (varsayılan) veya `'page_sheet'` değerlerini kabul eder.

```typescript showLineNumbers
try {
  await view.present({ iosPresentationStyle: 'page_sheet' });
} catch (error) {
  // handle the error
}
```

## Geliştirici tanımlı zamanlayıcı kullanımı \{#use-developer-defined-timer\}

Mobil uygulamanızda geliştirici tanımlı zamanlayıcılar kullanmak için, bu örnekte `CUSTOM_TIMER_NY` olan `timerId`'yi kullanın; bu, Adapty kontrol panelinde ayarladığınız geliştirici tanımlı zamanlayıcının **Timer ID**'sidir. Bu sayede uygulamanız zamanlayıcıyı doğru değerle dinamik olarak günceller; örneğin `13g 09s 03d 34s` (zamanlayıcının bitiş zamanı olan Yılbaşı'ndan mevcut zamanın çıkarılmasıyla hesaplanır).

<Tabs>
<TabItem value="component" label="React bileşeni">
```typescript showLineNumbers title="React Native (TSX)"
const flowParams = {
  customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
};

<AdaptyFlowView
  flow={flow}
  params={flowParams}
  // ... your event handlers
/>
```
</TabItem>
<TabItem value="modal" label="Modal sunum">
```typescript showLineNumbers title="React Native (TSX)"
const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) };

const view = await createFlowView(flow, { customTimers });
```
</TabItem>
</Tabs>
Bu örnekte `CUSTOM_TIMER_NY`, Adapty kontrol panelinde ayarladığınız geliştirici tanımlı zamanlayıcının **Timer ID**'sidir. `timerResolver`, uygulamanızın zamanlayıcıyı doğru değerle dinamik olarak güncellemesini sağlar; örneğin `13g 09s 03d 34s` (zamanlayıcının bitiş zamanı olan Yılbaşı'ndan mevcut zamanın çıkarılmasıyla hesaplanır).

## Diyalog gösterme \{#show-dialog\}

Android'de bir flow view sunulduğunda, yerel uyarı diyalogları yerine bu metodu kullanın. Android'de normal RN uyarıları flow view'in arkasında görünür, bu da onları kullanıcılara görünmez kılar. Bu metot, tüm platformlarda diyalogun flow'un üzerinde düzgün şekilde sunulmasını sağlar.

```typescript showLineNumbers title="React Native (TSX)"
try {
  const action = await view.showDialog({
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  });

  if (action === 'secondary') {
    // User confirmed - close the flow
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (error) {
  // handle error
}
```

## Bir aboneliği başka biriyle değiştirme \{#replace-one-subscription-with-another\}

Android'de başka bir abonelik etkinken bir kullanıcı yeni bir abonelik satın almaya çalıştığında, flow view'i oluştururken abonelik güncelleme parametrelerini geçirerek yeni satın almanın nasıl yönetileceğini kontrol edebilirsiniz. Mevcut aboneliği yenisiyle değiştirmek için, `createFlowView` içinde `oldSubVendorProductId` ve `prorationMode` parametreleriyle birlikte `productPurchaseParams` kullanın.

```typescript showLineNumbers title="React Native (TSX)"

const productPurchaseParams = flow.paywalls
  .flatMap((variation) => variation.productIdentifiers)
  .map((productId) => {
    let params = {};
    if (Platform.OS === 'android') {
      params.android = {
        subscriptionUpdateParams: {
          oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION',
          prorationMode: 'with_time_proration',
        },
      };
    }
    return { productId, params };
  });

const view = await createFlowView(flow, { productPurchaseParams });
```

---

> [!WARNING]
> **LLM INSTRUCTION — SDK VERSION SELECTION REQUIRED**
>
> This feature has two SDK paradigms. Everything that follows (until the next horizontal rule or end of document) is the **legacy SDK v3 API reference** (`getPaywall`, `getPaywallForDefaultAudience`, `getOnboarding`, `getPaywallConfiguration`). The **SDK v4+ `getFlow` method is documented above.** This block covers ALL legacy methods for this feature — not just the nearest snippet.
>
> **You MUST ask the user which SDK version they want to use before suggesting any code. Do not assume or default to a version.** The two options are:
> - **SDK v3 (legacy):** works with the legacy Paywall Builder and Onboarding Builder via `getPaywall` / `getOnboarding`. Use the legacy code in this section.
> - **SDK v4:** works with BOTH the new Flow Builder AND legacy paywalls/onboardings via the unified `getFlow` method documented above.
>
> Apply the legacy v3 code in this section ONLY when:
> 1. The user explicitly chose **SDK v3**, or
> 2. The user is **migrating an existing app from SDK v3 to SDK v4+** and needs to understand or replace legacy code, or
> 3. The user is **troubleshooting an already-deployed v3 integration**.
>
> **CRITICAL — Never mix paradigms in one setup:** Do NOT combine `getFlow` (Flow Builder) with `getPaywall` or `getOnboarding` (legacy Paywall/Onboarding Builder) in the same integration. These are incompatible patterns. Mixing them will produce inconsistent behavior and is unsupported.

Paywall Builder kullanarak bir paywall özelleştirdiyseniz, onu kullanıcıya göstermek için mobil uygulama kodunuzda render etme derdine girmenize gerek yoktur. Böyle bir paywall, hem paywall içinde ne gösterileceğini hem de nasıl gösterileceğini içerir.

Başlamadan önce şunlardan emin olun:

1. Bir [paywall oluşturdunuz](create-paywall).
2. Paywall'ı bir [placement](placements)'a eklediniz.
3. [Paywall'ı getirdiniz ve view'i hazırladınız](react-native-get-pb-paywalls).

:::warning

Bu rehber yalnızca **yeni Paywall Builder paywall'ları** içindir; bunlar SDK v3.0 veya sonrasını gerektirir. Paywall sunma süreci, Paywall Builder'ın farklı sürümleriyle tasarlanan paywall'lar ve remote config paywall'ları için farklıdır.

- **Remote config paywall'larını** sunmak için bkz. [Remote config ile tasarlanan paywall'ı render etme](present-remote-config-paywalls).

:::

Adapty React Native SDK, paywall'ları sunmak için iki yol sağlar:

- **React bileşeni**: Gömülü bileşen, onu uygulamanızın mimarisine ve navigasyon sistemine entegre etmenize olanak tanır.

- **Modal sunum**

## React bileşeni \{#react-component\}

:::note
**React bileşeni** yaklaşımı SDK 3.14.0 veya üstünü gerektirir.
:::

Bir paywallı mevcut bileşen ağacınıza gömmek için `AdaptyPaywallView` bileşenini doğrudan React Native bileşen hiyerarşinizde kullanın. Gömülü bileşen, uygulamanızın mimarisine ve navigasyon sistemine entegre etmenize olanak tanır.

:::note
Android'de, paywall durum çubuğunun arkasına uzanmıyorsa üst kısmında görsel bir katman belirebiilir. Paywalllarınız için bunu kapatmanızı öneririz. Bkz. [Paywallın üst kısmındaki görsel katman (Android)](#visual-overlay-at-the-top-of-the-paywall-android).
:::

```typescript showLineNumbers title="React Native (TSX)"

function MyPaywall({ paywall }) {
  const paywallParams = useMemo(() => ({
    loadTimeoutMs: 3000,
  }), []);

  const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []);
  const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []);
  const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []);
  const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []);
  const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []);
  const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []);
  const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []);
  const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []);
  const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []);
  const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []);
  const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []);
  const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => {}, []);
  const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []);
  const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []);

  return (
    <AdaptyPaywallView
      paywall={paywall}
      params={paywallParams}
      style={styles.paywall}
      onCloseButtonPress={onCloseButtonPress}
      onProductSelected={onProductSelected}
      onPurchaseStarted={onPurchaseStarted}
      onPurchaseCompleted={onPurchaseCompleted}
      onPurchaseFailed={onPurchaseFailed}
      onRestoreStarted={onRestoreStarted}
      onRestoreCompleted={onRestoreCompleted}
      onRestoreFailed={onRestoreFailed}
      onPaywallShown={onPaywallShown}
      onRenderingFailed={onRenderingFailed}
      onLoadingProductsFailed={onLoadingProductsFailed}
      onCustomAction={onCustomAction}
      onUrlPress={onUrlPress}
      onWebPaymentNavigationFinished={onWebPaymentNavigationFinished}
    />
  );
}
```

## Modal sunum \{#modal-presentation\}

Bir paywallı bağımsız bir ekran olarak göstermek için, [`createPaywallView`](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) metoduyla oluşturulan `view` üzerinde `view.present()` metodunu kullanın. Her `view` yalnızca bir kez kullanılabilir. Paywallı tekrar göstermeniz gerekiyorsa yeni bir `view` örneği oluşturmak için `createPaywallView`'i bir kez daha çağırın.

:::warning
Aynı `view`'ı yeniden oluşturmadan tekrar kullanmak yasaktır. Bu durum `AdaptyUIError.viewAlreadyPresented` hatasına yol açar.
:::

```typescript showLineNumbers title="React Native (TSX)"

const view = await createPaywallView(paywall);

// Optional: handle paywall events (close, purchase, restore, etc)
// view.setEventHandlers({ ... });

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

:::important
`setEventHandlers`'ı birden çok kez çağırmak, sağladığınız işleyicileri geçersiz kılar; söz konusu belirli olaylar için hem varsayılan hem de önceden ayarlanmış işleyicilerin yerini alır.
:::

### iOS sunum stilini yapılandırın \{#configure-ios-presentation-style\}

Paywall'ın iOS'ta nasıl sunulacağını, `present()` metoduna `iosPresentationStyle` parametresini ileterek yapılandırın. Parametre `'full_screen'` (varsayılan) veya `'page_sheet'` değerlerini kabul eder.

```typescript showLineNumbers
try {
  await view.present({ iosPresentationStyle: 'page_sheet' });
} catch (error) {
  // handle the error
}
```

## Geliştirici tanımlı zamanlayıcı kullanma \{#use-developer-defined-timer\}

Mobil uygulamanızda geliştirici tanımlı zamanlayıcılar kullanmak için, `timerId`'yi kullanın; bu örnekte, Adapty kontrol panelinde ayarladığınız geliştirici tanımlı zamanlayıcının **Timer ID**'si olan `CUSTOM_TIMER_NY`. Bu, uygulamanızın zamanlayıcıyı `13d 09h 03m 34s` gibi doğru değerle dinamik olarak güncellemesini sağlar (zamanlayıcının bitiş zamanı, örneğin Yılbaşı Günü, eksi mevcut zaman olarak hesaplanır).

<Tabs>
<TabItem value="component" label="React bileşeni">
```typescript showLineNumbers title="React Native (TSX)"
const paywallParams = {
  customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }
};

<AdaptyPaywallView
  paywall={paywall}
  params={paywallParams}
  // ... your event handlers
/>
```
</TabItem>
<TabItem value="modal" label="Modal sunum">
```typescript showLineNumbers title="React Native (TSX)"
const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) };

const view = await createPaywallView(paywall, { customTimers });
```
</TabItem>
</Tabs>
Bu örnekte, `CUSTOM_TIMER_NY`, Adapty kontrol panelinde ayarladığınız geliştirici tanımlı zamanlayıcının **Timer ID**'sidir. `timerResolver`, uygulamanızın zamanlayıcıyı `13d 09h 03m 34s` gibi doğru değerle dinamik olarak güncellemesini sağlar (zamanlayıcının bitiş zamanı, örneğin Yılbaşı Günü, eksi mevcut zaman olarak hesaplanır).

## Dialog gösterme \{#show-dialog\}

Android'de bir paywall view sunulduğunda, yerel uyarı dialogları yerine bu metodu kullanın. Android'de normal RN uyarıları paywall view'ın arkasında kalır ve kullanıcılar tarafından görülemez. Bu metot, tüm platformlarda paywallın üzerinde dialog'un düzgün şekilde sunulmasını sağlar.

```typescript showLineNumbers title="React Native (TSX)"
try {
  const action = await view.showDialog({
    title: 'Close paywall?',
    content: 'You will lose access to exclusive offers.',
    primaryActionTitle: 'Stay',
    secondaryActionTitle: 'Close',
  });

  if (action === 'secondary') {
    // User confirmed - close the paywall
    await view.dismiss();
  }
  // If primary - do nothing, user stays
} catch (error) {
  // handle error
}
```

## Bir aboneliği diğeriyle değiştirme \{#replace-one-subscription-with-another\}

Bir kullanıcı Android'de başka bir abonelik aktifken yeni bir abonelik satın almaya çalıştığında, paywall view'ı oluştururken abonelik güncelleme parametrelerini ileterek yeni satın almanın nasıl işleneceğini kontrol edebilirsiniz. Mevcut aboneliği yenisiyle değiştirmek için `createPaywallView`'de `oldSubVendorProductId` ve `prorationMode` parametreleriyle birlikte `productPurchaseParams` kullanın.

```typescript showLineNumbers title="React Native (TSX)"

const productPurchaseParams = paywall.productIdentifiers.map((productId) => {
  let params = {};
  if (Platform.OS === 'android') {
    params.android = {
      subscriptionUpdateParams: {
        oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION',
        prorationMode: 'with_time_proration',
      },
    };
  }
  return { productId, params };
});

const view = await createPaywallView(paywall, { productPurchaseParams });
```

## Sorun giderme \{#troubleshooting\}

### Paywallın üst kısmındaki görsel katman (Android) \{#visual-overlay-at-the-top-of-the-paywall-android\}

:::note
Bu ayar React Native SDK 3.15.5'ten itibaren desteklenmektedir ve yalnızca bare React Native projelerinde kullanılabilir.

Expo yönetilen iş akışı kullanıyorsanız bu Android kaynağını doğrudan ekleyemezsiniz. Bu ayarı uygulamak için, ilgili Android kaynağını ekleyen özel bir Expo config plugin oluşturmanız ve bunu app.config.js'e kaydetmeniz gerekir. Bunun nedeni Expo'nun yerel Android projesini sizin adınıza yönetmesidir.
:::

`AdaptyPaywallView` durum çubuğunun arkasına uzanmıyorsa, üst kısmında yine de görsel bir kaplama görünebilir. Onu kaldırmak için uygulamanıza aşağıdaki boolean kaynağını ekleyin:

1. `android/app/src/main/res/values` konumuna gidin. `bools.xml` dosyası yoksa oluşturun.

2. Aşağıdaki kaynağı ekleyin:

```xml
<resources>
    <bool name="adapty_paywall_enable_safe_area_paddings">false</bool>
</resources>
```

Değişikliklerin uygulamanızdaki tüm paywall'lar için genel olarak geçerli olduğunu unutmayın.

---